jupiter-token-verification
Jupiter Token Verification
Submit and pay for token verification on Jupiter via a simple REST API.
- Base URL:
https://token-verification-dev-api.jup.ag - Auth: API key required for submission endpoints (
x-api-keyheader). Eligibility checks are unauthenticated. - Payment currency: JUP (1 JUP per express verification)
- Naming: "Express" and "premium" refer to the same paid tier. The user-facing name is express, but the API uses
"premium"as theverificationTiervalue. - Agent behavior: Guide users step by step — collect parameters one at a time, validate each input, and confirm before submitting. See Agent Conversation Flow.
Use / Do Not Use
Use when:
- Submitting a token for verification (basic or express)
- Paying for express verification with JUP tokens
- Checking the verification status of a token
- Updating token metadata (name, symbol, social links, etc.) alongside verification
Do not use when:
- Performing admin operations (verify, reject, unverify) — these require admin auth
- Swapping, lending, or trading — use
integrating-jupiterskill instead
Triggers
verify token, token verification, submit verification, verification status, check verification, verification payment, pay for verification, express verification, basic verification, update token metadata, token metadata, update token info
Intent Router
| User intent | Endpoint | Method | Auth |
|---|---|---|---|
| Check express eligibility | /combined/express/check-eligibility?tokenId=… |
GET |
None |
| Check basic eligibility | /combined/basic/check-eligibility?tokenId=… |
GET |
None |
| Submit basic verification | /basic/submit |
POST |
API key |
| Craft express payment transaction | /payments/express/craft-txn?senderAddress=… |
GET |
API key |
| Sign and execute express payment | /payments/express/execute |
POST |
API key |
References
Load these on demand when you need implementation details:
- API Reference — Endpoint details, request/response schemas, data types, eligibility rules, API key generation and management, tokenMetadata schema. Load when making API calls or validating parameters.
- Payment Execution — Express payment flow (steps 7a–7e), template script, config.json, error handling. Load when the user confirms an express verification.
Agent Conversation Flow
When a user triggers this skill, guide them through parameter collection step by step. Do NOT ask for all parameters at once — collect them incrementally, validate each input, and confirm before making API calls.
Step-by-Step Parameter Collection
1. Determine Intent
Ask the user what they want to do:
What would you like to do?
- Check if a token is eligible for verification
- Submit a token for verification
- Update metadata for a token (e.g., name, symbol, social links)
If the user's message already makes their intent clear, skip this question.
For "update metadata" intent: proceed to Step 2 (tier selection) → Step 3 (collect mint) → Step 4 (check eligibility). The eligibility endpoint must match the tier selected in Step 2.
2. Choose Verification Tier
Before collecting the mint address, determine which tier the user wants. This ensures only one eligibility endpoint is called later.
Auto-select from user intent: If the user's original message already indicates which tier they want, use their choice directly:
- Phrases like
express verification,paid verification,express flow→ auto-select express - Phrases like
basic verification,free verification→ auto-select basic
Otherwise, ask:
Would you like basic (free) or express (1 JUP) verification?
- Basic — free, standard review process
- Express — costs 1 JUP, paid from your wallet
Default to express if the user is unsure, approvals are faster.
3. Collect Token Mint Address (always required)
Ask:
What is the Solana token mint address you'd like to verify?
Validate before proceeding:
- Must be a valid base58 string
- Typically 32–44 characters
- If invalid, say: "That doesn't look like a valid Solana mint address. It should be a base58 string like
So11111111111111111111111111111111111111112. Please try again."
4. Check Token Eligibility (single tier)
After collecting the mint, check eligibility for only the tier selected in Step 2 — do NOT call both endpoints:
- Basic:
GET /combined/basic/check-eligibility?tokenId={tokenId} - Express:
GET /combined/express/check-eligibility?tokenId={tokenId}
Use the result to determine which flow to follow:
A) Token is already verified — endpoint returns canVerify: false and the verificationError message indicates an existing (non-rejected) verification:
This token is already verified on Jupiter.
canMetadata |
Action |
|---|---|
true |
Offer metadata update: "Would you like to update the token metadata (name, symbol, social links, etc.)?" If yes → proceed to Step 5 (API key) → Step 6a (metadata collection) → Step 7 (confirm) → Step 8 with submitVerification: false. If no → done. |
false |
Report: "Metadata updates are also not available at this time ({metadataError})." Done. |
B) Token can be verified — endpoint returned canVerify: true:
Proceed to Step 4a (Check Metadata Availability), then continue to Step 5.
C) Token cannot be verified — canVerify: false with an error other than existing verification (e.g., token not found, not eligible for this tier):
Report the verificationError. If canMetadata: true, offer a metadata-only update. Otherwise stop.
For "check-only" intent (user just wants to know status): report whether the token is eligible for the selected tier, whether metadata updates are available, and any errors. Done — do not proceed to submission.
4a. Check Metadata Availability
After confirming the token can be verified, check the canMetadata result from the eligibility response retrieved in Step 4:
canMetadata |
Action |
|---|---|
true |
Ask: "Would you also like to update token metadata (name, symbol, social links, etc.)?" If yes → metadata fields will be collected in Step 6a. If no → skip Step 6a. |
false |
Inform: "Metadata updates are not available for this token ({metadataError})." Skip Step 6a. |
5. Resolve API Key
Before any authenticated call (POST /basic/submit, GET /payments/express/craft-txn, POST /payments/express/execute), resolve the API key:
- Check
.env/.env.localforJUPITER_API_KEYorJUP_API_KEY - If not found, guide the user through generating a new API key:
- Direct them to open
https://vrfd-auth-api-dev.jup.ag/api/keys/newin their browser — this handles login and key generation in one flow - Important: The key is shown once and cannot be retrieved again (only the prefix
vrfd_ak_xxxx...is stored for display). Tell the user to copy it immediately. - Creating a new key automatically revokes any existing active key for their account
- Direct them to open
- Once the user has their key, ask them to store it in
.envasJUPITER_API_KEY=<key>and ensure.envis in.gitignore
The key is passed via the x-api-key header. Rate limit: 2 requests/day per key.
For full API key management details (listing keys, revoking keys), see API Reference — Managing Keys.
6. Collect Remaining Parameters (one at a time)
Collect these in order. For each, show what it is and why it matters:
a) Token's Twitter/X URL (optional but recommended)
What is the token project's Twitter/X URL? Example:
https://x.com/jupiterexchange> (Type "skip" to leave blank)
Validate: must be a full URL starting with https://x.com/ or https://twitter.com/ followed by a valid username (1–15 chars, alphanumeric + underscore). If the user provides a bare handle like @handle, auto-convert it to https://x.com/handle and confirm with the user.
b) Requester's Twitter/X URL (optional)
What is your Twitter/X URL? This identifies who submitted the request. Example:
https://x.com/your_handle> (Type "skip" to leave blank)
Same validation as above.
c) Description (optional but recommended)
Please provide a short description of the token. Example: "Community governance token for XYZ protocol" > (Type "skip" to leave blank)
d) Wallet Address (basic tier — required)
If basic was selected:
What is your Solana wallet address?
Validate: same base58 format as token mint.
If express was selected: skip this step. The wallet address will be derived automatically from the user's private key during the payment execution flow.
6a. Collect Metadata Fields (when metadata is included)
Runs when the user opted in at Step 4a or in a metadata-only flow (canVerify: false, canMetadata: true).
Present the available fields:
Here are the metadata fields you can update:
Identity: name, symbol, icon, tokenDescription Links: website, twitter, twitterCommunity, telegram, discord, instagram, tiktok, otherUrl Supply & Market Data: circulatingSupply, circulatingSupplyUrl, coingeckoCoinId
Which fields would you like to update?
Ask which fields they want to update, then collect values one at a time.
Field collection rules:
tokenIdis auto-filled from the token mint collected in Step 2 — do not ask for it- When the user provides a value for
circulatingSupply, auto-setuseCirculatingSupply: true - When the user provides a value for
coingeckoCoinId, auto-setuseCoingeckoCoinId: true - When the user provides a value for
circulatingSupplyUrl, auto-setuseCirculatingSupplyUrl: true - URL fields (website, twitter, discord, etc.) should be validated as proper URLs
- See API Reference — tokenMetadata Object for the full schema
For metadata-only flow (when canVerify: false, canMetadata: true): this step is the primary collection step — verification params from Step 6 are skipped.
7. Confirm Before Submitting
Present a summary of all collected parameters and ask for confirmation:
Here's a summary of your verification request:
Field Value Token Mint {tokenId}Tier {basic/express} Token Twitter {url or not provided} Your Twitter {url or not provided} Description {text or not provided} Wallet {address or not provided}
If metadata fields were collected in Step 6a, add them to the summary:
| Metadata | | | — Name | {value or not provided} | | — Symbol | {value or not provided} | | (etc. for each collected field) | |
For metadata-only flow, adjust the heading: "Here's a summary of your metadata update request:" and omit verification-only fields (tier, token twitter, your twitter, description).
Does this look correct? (yes/no)
If the user says no, ask which field to change.
8. Submit and Report
- For basic: call
POST /basic/submitwithsubmitVerification: trueand all collected parameters. IncludetokenMetadatain the request body when metadata fields were collected in Step 6a. Report the result — response includesverificationCreatedandmetadataCreatedbooleans. Done. (See API Reference for request/response details.) - For express: load Payment Execution and follow steps 7a–7e. The agent will resolve the user's private key, write a payment script, execute it locally, and report the result. When metadata fields were collected, they are included in the execute request body as
tokenMetadata. - For metadata-only (when
canVerify: false, canMetadata: true): callPOST /basic/submitwithsubmitVerification: falseand includetokenMetadatawith the collected fields. Do not include verification parameters. ReportmetadataCreatedresult.
Input Auto-Correction
When collecting user input, handle these common mistakes gracefully instead of rejecting outright:
| User provides | Auto-correct to | Confirm with user? |
|---|---|---|
@jupiterexchange |
https://x.com/jupiterexchange |
Yes — "I'll format that as https://x.com/jupiterexchange — is that correct?" |
jupiterexchange (bare handle) |
https://x.com/jupiterexchange |
Yes |
twitter.com/handle (no https) |
https://twitter.com/handle |
Yes |
x.com/handle (no https) |
https://x.com/handle |
Yes |
| Token mint with leading/trailing spaces | Trimmed string | No |
Gotchas
- Twitter handles must be full URLs —
https://x.com/handleorhttps://twitter.com/handle. Bare handles like@handleare rejected by the API. craft-txnreturns an unsigned transaction — the user MUST sign it with their wallet before callingexecute. Do not submit unsigned transactions.- The execute endpoint co-signs server-side — do NOT broadcast the transaction to the Solana RPC yourself. The server adds its own signature and submits it.
- Payment is 1 JUP token (1,000,000 base units with 6 decimals) — confirm the user has enough JUP balance before starting the payment flow.
- Check eligibility before submitting — call
GET /combined/express/check-eligibility?tokenId=…orGET /combined/basic/check-eligibility?tokenId=…first. Submitting a duplicate returns an error. - Already-verified tokens cannot be resubmitted — if the token is already verified, the eligibility endpoint returns
canVerify: falsewithverificationError. - Token must exist — the token must be indexed by Jupiter's data API. Unknown tokens return an error.
- Admin endpoints are off-limits —
POST /verifications/verify,POST /verifications/unverify, andPOST /verifications/mass-unverifyall require admin authentication. Do not attempt to call them. - Basic verification = done at Step 8 — only express verification requires the payment flow (steps 7a–7e).
- Express upgrades via execute — when you pay via the
executeendpoint, the server automatically creates (or upgrades) the verification to express tier. Response includesverificationCreatedandmetadataCreatedbooleans. You do not need to callPOST /basic/submitseparately for express. - Private keys MUST stay local — The payment script signs transactions client-side. The private key is NEVER sent to any API, server, or external service. Only the signed transaction is transmitted. Agents must communicate this clearly to users and include security comments in generated scripts. Recommend
.envfiles (with.gitignore) and dedicated payment wallets. Never accept a raw private key directly in chat — only support.envfiles and keypair file paths. - Use
VersionedTransaction, not legacyTransaction— The API returns a versioned transaction. Deserialize withVersionedTransaction.deserialize(buffer), sign withtransaction.sign([keypair]), and serialize withBuffer.from(transaction.serialize()).toString('base64'). Do not use legacyTransaction.from()orpartialSign(). - Script execution requires Node.js v18+ — The payment script uses
fetch(built-in from Node 18) and@solana/web3.js. If Node.js is too old, fall back to providing the script for manual execution or suggest the user upgrade Node.js. - Always verify transaction contents before signing — Never blindly sign a server-provided transaction. Decode the instructions, verify the program is SPL Token, verify the amount matches expectations and does not exceed 1 JUP (1,000,000 base units), and verify the destination matches the expected receiver ATA. Reject if any unexpected instructions are present (compute budget instructions are allowed).
- Never interpolate user input into source code — User-provided values (description, Twitter handles, etc.) must be written to a separate
config.jsonfile and read at runtime. Embedding user input directly in TypeScript string literals enables code injection attacks. - API key required for submission endpoints —
POST /basic/submit,GET /payments/express/craft-txn, andPOST /payments/express/executeall require anx-api-keyheader. Eligibility check endpoints are unauthenticated. - Rate limit: 2 requests/day per API key — The submission endpoints are rate-limited to 2 requests per day per API key. Warn users before submitting.
- Metadata can be submitted with or without verification — The combined endpoints support optional
tokenMetadatafor setting token metadata alongside verification. WhencanVerify: falsebutcanMetadata: true, submit withsubmitVerification: falseand onlytokenMetadatato perform a metadata-only update. At least one ofsubmitVerification: trueortokenMetadatamust be provided.
Resources
- JUP Token Mint:
JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN - Jupiter Docs: dev.jup.ag
- Jupiter Verified: verified.jup.ag
More from nghanyi/agent-skills
jupiter-vrfd
Use when submitting a Jupiter token verification request (1 JUP) or checking verification eligibility.
9jupiter-lend
Interact with Jupiter Lend Protocol. Read-only SDK (@jup-ag/lend-read) for querying liquidity pools, lending markets (jlTokens), and vaults. Write SDK (@jup-ag/lend) for lending (deposit/withdraw) and vault operations (deposit collateral, borrow, repay, manage positions). No API keys needed for on-chain interactions.
1integrating-jupiter
Comprehensive guidance for integrating Jupiter APIs (Ultra Swap, Lend, Perps, Trigger, Recurring, Tokens, Price, Portfolio, Prediction Markets, Send, Studio, Lock, Routing). Use for endpoint selection, integration flows, error handling, and production hardening.
1