eve-esi
Query and manage EVE Online characters via the ESI (EVE Swagger Interface) REST API. Performs OAuth2/PKCE browser login and stores plus auto-refreshes long-lived OAuth tokens local…
cnc_x_ai
@burnshall-ui
Install
$ openclaw skills install @burnshall-ui/eve-esiData Handling
This skill communicates with the following external services. Every outbound call is either a public/unauthenticated CCP endpoint, an OAuth2 flow against the official EVE SSO, or an optional, user-configured notification sink.
- EVE Online ESI API (
esi.evetech.net) — official EVE Online REST API (operated by CCP Games) for all character and universe data queries. Includes bulk lookup endpoints such asPOST /characters/affiliation/andPOST /universe/names/, which resolve public numeric IDs (character/corp/alliance/type IDs) to public data. These POST bodies never contain tokens, credentials, or private account data — only IDs that are already public in-game. Authenticated endpoints (wallet, assets, skills, etc.) send the OAuth2 bearer token only to this same host, per ESI's own API contract. - EVE SSO (
login.eveonline.com) — official OAuth2/PKCE authorization server for EVE Online. Used only for the login/token-refresh flow described inreferences/authentication.md. - EVE Developer Portal (
developers.eveonline.com/applications) — official CCP portal where the user registers their own EVE application and obtains a Client ID. This skill never calls this URL programmatically; it is referenced in documentation only, as the one-time manual step a user performs before runningscripts/auth_flow.py --client-id <...>. - zKillboard API (
zkillboard.com/api/) — optional, public, unauthenticated. Only used for PVP threat-assessment features; disabled unless threat/route scripts are invoked. - Telegram Bot API — optional, only contacted if the user sets
TELEGRAM_BOT_TOKENand configures alerts. - Discord Webhooks — optional, only contacted if the user sets
DISCORD_WEBHOOK_URLand configures alerts.
No character data, tokens, or credentials are sent to any third-party server beyond the above. Telegram/Discord only receive the specific alert text the user has configured — never raw account data or tokens.
What this skill can access, and what it will not do
Read-only by default. GET requests and the documented bulk-lookup POST
endpoints run normally. Any other POST, plus PUT and DELETE, is refused unless
you pass --allow-write explicitly. Without that flag this skill cannot send
mail, change contacts, alter contracts, open in-game windows, or modify your
account in any way.
Sensitive data. The scopes you grant during auth_flow.py decide what the
skill can read. Several are genuinely private: wallet balance and full ISK
transaction history, complete asset lists, mail contents, contracts, clone and
implant locations, and current in-space location. Grant only the scopes your
use case needs — the skill works fine with a narrow scope set, and public
endpoints need no scopes at all.
Agent instruction: ask before you authenticate
Do not choose a scope profile on the user's behalf. Scopes are granted once and stay granted until revoked, so this is the user's decision, not yours.
Before running auth_flow.py, show the user the profiles and ask which one
they want:
| Profile | Scopes | Grants access to |
|---|---|---|
basic | 7 | Skills, skill queue, clones, implants, location, ship, online status |
pi (default) | 8 | basic plus Planetary Interaction |
industry | 11 | basic plus assets, industry jobs, market orders, contracts |
full | 17 | Everything, including wallet balance, ISK history and mail |
python3 scripts/auth_flow.py --list-scope-profiles prints the exact scope
list for each. --scopes "<space separated>" takes an explicit set.
If the user has not expressed a preference, use the default and say so — do not
silently pick full because it is convenient. If a later query fails for lack
of a scope, report which scope is missing and let the user decide whether to
re-authenticate with a wider profile.
The final gate is outside this skill: EVE SSO shows the user a consent screen listing every requested scope, and nothing is granted until they approve it in their browser.
Token handling. Access tokens are bearer credentials: anyone holding one can read your account until it expires (~20 min). Refresh tokens are long-lived and rotate on each use.
- Prefer
esi_query.py --char <name>, which refreshes the token in-process. The token never enters argv. - Avoid
--token "$TOKEN"andcurl -H "Authorization: Bearer $TOKEN": command lines are visible to any local user viaps, and land in your shell history. Use--token-stdinwhen a token must come from outside. - Never paste a token into a config file, a bug report, a log, or a chat message.
Alert transmission. If you configure Telegram or Discord, the alert text you define is sent to those services in plaintext over their APIs. Do not template raw wallet figures or asset inventories into alerts you would not want stored on a third-party server.
EVE Online ESI
The ESI (EVE Swagger Interface) is the official REST API for EVE Online third-party development.
- Base URL:
https://esi.evetech.net— no version segment. - Versioning: send
X-Compatibility-Date: 2026-08-04on every request. CCP has replaced the old/latest,/legacyand/v5URL prefixes with this header (dev blog). A request that omits it does not get the newest behaviour — it gets the oldest one ESI still serves.esi_query.pysets the header itself; override it with--compatibility-dateorEVE_ESI_COMPATIBILITY_DATE. - Spec:
https://esi.evetech.net/meta/openapi.json(OpenAPI 3.1) orhttps://esi.evetech.net/meta/openapi-3.0.json(OpenAPI 3.0). The oldswagger.jsonis deprecated and no longer receives new routes (dev blog). - Valid compatibility dates: https://esi.evetech.net/meta/compatibility-dates
- Changelog: https://esi.evetech.net/meta/changelog — check this before
bumping the compatibility date, and adjust for any
is_breakingentry on an endpoint this skill uses. - API Explorer: https://developers.eveonline.com/api-explorer
- User-Agent: every request identifies the skill and links its source repo,
because CCP treats anonymous traffic as grounds for throttling. Set
EVE_ESI_CONTACTto an email,discord:nameoreve:charnameto add the contact CCP would rather have.
Skill Location
All scripts live at: ~/.openclaw/workspace/skills/eve-esi/scripts/
Always use full paths when calling scripts:
SKILL=~/.openclaw/workspace/skills/eve-esi
Authentication
Tokens are stored in ~/.openclaw/eve-tokens.json (created by auth_flow.py, chmod 600).
All scripts (get_token.py, esi_query.py) read from this file directly — no env vars are required for normal operation.
First-time setup (once per character). The Client ID comes from the user's own application at https://developers.eveonline.com/applications — it is not stored anywhere by this skill, so ask the user for it rather than hunting for it. Ask which scope profile they want before running this; do not choose for them.
# 0. In the EVE application, the Callback URL must be exactly
# http://localhost:8080/callback — the developer portal allows the http
# scheme only for the host `localhost` and rejects 127.0.0.1 on save.
# 1. Set up SSH tunnel on your local PC:
# ssh -L 8080:127.0.0.1:8080 user@your-server -N
# 2. Run auth flow on server (pass Client ID directly):
python3 ~/.openclaw/workspace/skills/eve-esi/scripts/auth_flow.py \
--client-id <YOUR_CLIENT_ID> --char-name main --scope-profile <basic|pi|industry|full>
# 3. Open the shown URL in browser, log in with EVE account
Preferred: let the query script handle the token. --char <name> resolves and
refreshes the token in-process, so it never appears on a command line, in shell
history, or in your logs:
python3 ~/.openclaw/workspace/skills/eve-esi/scripts/esi_query.py --char main \
--endpoint "/characters/<CHAR_ID>/wallet/" --pretty
Only if you genuinely need the raw token elsewhere (it expires after ~20 min, refresh is automatic):
python3 ~/.openclaw/workspace/skills/eve-esi/scripts/get_token.py --char main
Do not capture it into a shell variable and pass it as --token "$TOKEN" —
that exposes it via ps and shell history. Use --token-stdin if a token must
be handed over.
List authenticated characters:
python3 ~/.openclaw/workspace/skills/eve-esi/scripts/get_token.py --list
For full OAuth2/PKCE details: see references/authentication.md.
Calling ESI directly
The curl examples below are reference material for the raw API. Every one of
them goes through this helper, which sets the two headers ESI expects: a
compatibility date, so the response contract stays pinned, and a User-Agent, so
CCP can see who is calling. esi_query.py sets both by itself — that is one
reason it is the preferred path.
ESI="https://esi.evetech.net"
COMPAT="2026-08-04"
UA="OpenClaw-ESI-Skill/1.3.3 (+https://github.com/burnshall-ui/openclaw-eve-skill)"
esi() { curl -s -H "X-Compatibility-Date: $COMPAT" -H "User-Agent: $UA" "$@"; }
Public endpoints (no auth)
# Character public info
esi "$ESI/characters/2114794365/" | python -m json.tool
# Portrait URLs
esi "$ESI/characters/2114794365/portrait/"
# Corporation history
esi "$ESI/characters/2114794365/corporationhistory/"
# Bulk affiliation lookup
esi -X POST "$ESI/characters/affiliation/" \
-H "Content-Type: application/json" \
-d '[2114794365, 95538921]'
Character info (authenticated)
These put the token on a command line, where
psand shell history expose it. For day-to-day use preferesi_query.py --char <name>(see Using the query script).
TOKEN="<your_access_token>"
CHAR_ID="<your_character_id>"
# Online status (scope: esi-location.read_online.v1)
esi -H "Authorization: Bearer $TOKEN" "$ESI/characters/$CHAR_ID/online/"
Wallet
# Balance (scope: esi-wallet.read_character_wallet.v1)
esi -H "Authorization: Bearer $TOKEN" "$ESI/characters/$CHAR_ID/wallet/"
# Journal (paginated)
esi -H "Authorization: Bearer $TOKEN" "$ESI/characters/$CHAR_ID/wallet/journal/?page=1"
# Transactions
esi -H "Authorization: Bearer $TOKEN" "$ESI/characters/$CHAR_ID/wallet/transactions/"
Assets
# All assets (paginated; scope: esi-assets.read_assets.v1)
esi -H "Authorization: Bearer $TOKEN" "$ESI/characters/$CHAR_ID/assets/?page=1"
# Resolve item locations
esi -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '[1234567890, 9876543210]' \
"$ESI/characters/$CHAR_ID/assets/locations/"
# Resolve item names
esi -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '[1234567890]' \
"$ESI/characters/$CHAR_ID/assets/names/"
Skills
# All trained skills + total SP (scope: esi-skills.read_skills.v1)
esi -H "Authorization: Bearer $TOKEN" "$ESI/characters/$CHAR_ID/skills/"
# Skill queue (scope: esi-skills.read_skillqueue.v1)
esi -H "Authorization: Bearer $TOKEN" "$ESI/characters/$CHAR_ID/skillqueue/"
# Attributes (intelligence, memory, etc.)
esi -H "Authorization: Bearer $TOKEN" "$ESI/characters/$CHAR_ID/attributes/"
Location and ship
# Current location (scope: esi-location.read_location.v1)
esi -H "Authorization: Bearer $TOKEN" "$ESI/characters/$CHAR_ID/location/"
# Current ship (scope: esi-location.read_ship_type.v1)
esi -H "Authorization: Bearer $TOKEN" "$ESI/characters/$CHAR_ID/ship/"
Clones and implants
# Jump clones + home station (scope: esi-clones.read_clones.v1)
esi -H "Authorization: Bearer $TOKEN" "$ESI/characters/$CHAR_ID/clones/"
# Active implants (scope: esi-clones.read_implants.v1)
esi -H "Authorization: Bearer $TOKEN" "$ESI/characters/$CHAR_ID/implants/"
More endpoints
For contracts, fittings, mail, industry, killmails, market orders, mining, planetary interaction, loyalty points, notifications, blueprints, standings, and all other character endpoints, see references/endpoints.md.
Dashboard Config
The skill defines and validates a config format for alerts, reports and market
tracking. It does not execute any of it: there is no poller, no scheduler
and no notification sender in this skill. Do not tell the user their alerts are
running because a config exists — the config is a description that some other
automation has to act on. validate_config.py checks that a config is well
formed and that the stored token actually carries the scopes it references.
- Schema: config/schema.json — full JSON Schema with all fields, types, and defaults
- Example: config/example-config.json — ready-to-use template
Features
| Module | Description |
|---|---|
| Alerts | Real-time polling for war decs, structure attacks, skill completions, wallet changes, industry jobs, PI extractors, killmails, contracts, clone jumps, mail |
| Reports | Cron-scheduled summaries: net worth, skill queue, industry, market orders, wallet, assets |
| Market | Price tracking with absolute thresholds and trend detection |
Security
Do not write tokens into the dashboard config file. There are two supported places for credentials, and they do not conflict:
| Location | What lives there | Who writes it |
|---|---|---|
~/.openclaw/eve-tokens.json | The canonical token store: refresh tokens + client IDs, one entry per character. Created chmod 600, rewritten atomically, lock-protected. | auth_flow.py / get_token.py |
| Dashboard config JSON | No secrets. Reference env vars if a value is unavoidable. | You |
The scripts read the token store directly, so a normal setup needs no
credentials in the config file and no env vars at all. Only use $ENV:
references if you drive the dashboard from a system that cannot reach the
token store:
{
"token": "$ENV:EVE_TOKEN_MAIN",
"refresh_token": "$ENV:EVE_REFRESH_MAIN"
}
The config file should live outside the workspace (e.g. ~/.openclaw/eve-dashboard-config.json).
Validate a config
python scripts/validate_config.py path/to/config.json
# Show example config
python scripts/validate_config.py --example
# Show JSON schema
python scripts/validate_config.py --schema
Using the query script
Pass --char <name> and the script refreshes the stored token itself. The token
never appears on a command line, so ps and shell history cannot leak it.
SKILL=~/.openclaw/workspace/skills/eve-esi
# Replace 'main' with your --char-name if you authenticated under a different name.
CHAR_ID=$(python3 $SKILL/scripts/get_token.py --char main --char-id)
# Simple query
python3 $SKILL/scripts/esi_query.py --char main --endpoint "/characters/$CHAR_ID/wallet/" --pretty
# Fetch all pages of assets
python3 $SKILL/scripts/esi_query.py --char main --endpoint "/characters/$CHAR_ID/assets/" --pages --pretty
# Bulk lookup POST (asset names) — a read-only lookup, no --allow-write needed
python3 $SKILL/scripts/esi_query.py --char main --endpoint "/characters/$CHAR_ID/assets/names/" \
--method POST --body '[1234567890]' --pretty
If you must supply a token from elsewhere, pipe it in rather than passing --token:
printf '%s\n' "$TOKEN" | python3 $SKILL/scripts/esi_query.py --token-stdin --endpoint /characters/$CHAR_ID/wallet/
Best practices
- Caching: respect the
Expiresheader; do not poll before it expires. Polling around the cache is treated as circumventing it and can get you banned. - Error limits: monitor
X-ESI-Error-Limit-Remain; back off when low. A 4xx costs five times what a 2xx costs, so validate input before sending it. - Rate limits: routes under bucket limiting report
X-Ratelimit-Remainingand answer with429plusRetry-Afteronce the bucket is empty.esi_query.pyhonours both, and warns once a bucket drops below 20%. - User-Agent: always set a descriptive User-Agent with contact info.
- Pagination: check the
X-Pagesresponse header; iterate with?page=N. - Versioning: do not use URL prefixes.
/latest/,/legacy/,/dev/and/v5/are deprecated — send theX-Compatibility-Dateheader instead, and pin it to a date you have actually reviewed.esi_query.pystrips a version prefix if one reaches it anyway. - Scheduling: stagger periodic jobs rather than firing them all on
*/5.
Threat Assessment & Route Planning
The skill provides threat intelligence for PI systems in low/null-sec space. Data sources: ESI (kills, jumps, FW, incursions) and zKillboard (PVP activity).
ESI Threat Endpoints
SKILL=~/.openclaw/workspace/skills/eve-esi
# System kills (last hour) — all or filtered
python3 $SKILL/scripts/esi_query.py --action system_kills --pretty
python3 $SKILL/scripts/esi_query.py --action system_kills --system-ids 30002537,30045337 --pretty
# System jump traffic (last hour)
python3 $SKILL/scripts/esi_query.py --action system_jumps --system-ids 30045337 --pretty
# System info (name, security status)
python3 $SKILL/scripts/esi_query.py --action system_info --system-id 30002537 --pretty
# Route planning (flags: secure, shortest, insecure)
python3 $SKILL/scripts/esi_query.py --action route_plan --origin 30000142 --destination 30002537 --route-flag secure --pretty
# Character location (requires auth)
python3 $SKILL/scripts/esi_query.py --action character_location --char main --character-id $CHAR_ID --pretty
# Faction warfare systems
python3 $SKILL/scripts/esi_query.py --action fw_systems --pretty
# Active incursions
python3 $SKILL/scripts/esi_query.py --action incursions --pretty
Threat Assessment Scripts (Workspace)
Hinweis: Die Workspace-Skripte (
threat_query.py,cache_threat_data.py,cache_market_prices.py) sind Referenz-Beschreibungen und müssen erst im Agent-Workspace erstellt werden, bevor sie genutzt werden können.
These scripts live in ~/.openclaw/workspace/scripts/ (not in the skill repo):
# Threat level for specific systems
python3 ~/.openclaw/workspace/scripts/threat_query.py --action threat_assessment --system-ids 30002537,30045337
# Threat for all PI systems across all characters
python3 ~/.openclaw/workspace/scripts/threat_query.py --action threat_assessment_pi
# Route with per-system threat annotation
python3 ~/.openclaw/workspace/scripts/threat_query.py --action route_annotated --origin 30000142 --destination 30002537
# Route from character's current location
python3 ~/.openclaw/workspace/scripts/threat_query.py --action route_annotated --character main --destination 30045337
# Full PI + Threat morning briefing
python3 ~/.openclaw/workspace/scripts/threat_query.py --action pi_briefing
Threat Levels
| Level | Score | Meaning |
|---|---|---|
low | 0-15 | Normaler PI-Betrieb |
medium | 15-40 | Schnell rein, schnell raus |
high | 40-80 | Nur mit Scout/Cloak |
critical | 80+ | NICHT reinfliegen |
Threat Cache
Threat data is cached in Redis (30min TTL for ESI, 1h for zKillboard). The cache is updated every 30 minutes via cron:
# Update cache manually
python3 ~/.openclaw/workspace/scripts/cache_threat_data.py
# Show cached threat data
python3 ~/.openclaw/workspace/scripts/cache_threat_data.py --check
Resolving type IDs
ESI returns numeric type IDs (e.g. for ships, items, skills). Resolve names via:
SKILL=~/.openclaw/workspace/skills/eve-esi
# Single type
python3 $SKILL/scripts/esi_query.py --endpoint "/universe/types/587/" --pretty
# Bulk names (up to 1000 IDs)
python3 $SKILL/scripts/esi_query.py --endpoint "/universe/names/" \
--method POST --body '[587, 638, 11393]' --pretty
Top skills in this category
API Gateway
@byungkyuCall third-party APIs through the Maton gateway, which injects the credential for an app the user has already connected. Use this skill when the user names a connected app and a concrete action in it - read a mailbox, query a CRM, file an issue, update a spreadsheet, run a query through a connected
1password
@steipeteSet up and use 1Password CLI (op). Use when installing the CLI, enabling desktop app integration, signing in (single or multi-account), or reading/injecting/running secrets via op.
google-slides
@byungkyuGoogle Slides API integration with managed OAuth. Create presentations, add slides, insert content, and manage slide formatting. Use this skill when users want to interact with Google Slides. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway). Calls run through the `maton` CLI with OAuth login; default to read and list calls, and confirm every write or new connection with the user.
LinkedIn API integration with managed OAuth. Share posts, manage profile, and access LinkedIn features. Use this skill when users want to share content on LinkedIn, get profile/organization information, or interact with LinkedIn's platform. Advertising features (campaigns, ad accounts) require additional OAuth scopes — verify granted scopes before use. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway). Requires network access and valid Maton API key. Calls run through the `maton` CLI with OAuth login; default to read and list calls, and confirm every write or new connection with the user.
google-workspace-admin
@byungkyuGoogle Workspace Admin SDK integration with managed OAuth. This is a write-capable administrative integration for users, groups, organizational units, roles, and domain settings. Only connect with a least-privileged Google admin account, restrict OAuth scopes to the specific resources needed, and revoke the connection after use. All write operations require explicit user approval showing the exact HTTP method, endpoint path, and target resource identifier before execution. Use this skill only when users need Google Workspace administration. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway). Calls run through the `maton` CLI with OAuth login; default to read and list calls, and confirm every write or new connection with the user.