integrating-jupiter

Par elophanto · elophanto

Guide complet pour l'intégration des APIs Jupiter (Ultra Swap, Lend, Perps, Trigger, Recurring, Tokens, Price, Portfolio, Prediction Markets, Send, Studio, Lock, Routing). À utiliser pour la sélection des endpoints, les flux d'intégration, la gestion des erreurs et le renforcement en production.

npx skills add https://github.com/elophanto/elophanto --skill integrating-jupiter

Intégration API Jupiter

Compétence unique pour toutes les APIs Jupiter, optimisée pour un routage rapide et une exécution déterministe.

URL de base : https://api.jup.ag Authentification : x-api-key depuis portal.jup.ag (obligatoire pour les endpoints REST Jupiter)

Utiliser / Ne pas utiliser

À utiliser quand :

  • La tâche demande de choisir ou d'appeler des endpoints Jupiter.
  • La tâche implique swap, lending, perps, orders, pricing, portfolio, send, studio, lock, ou routing.
  • L'utilisateur a besoin d'aide pour déboguer des appels à l'API Jupiter.

À ne pas utiliser quand :

  • La tâche est une configuration Solana générique sans utilisation de l'API Jupiter.
  • La tâche est UI-only sans décisions comportementales d'API.

Déclencheurs : swap, quote, gasless, best route, lend, borrow, earn, liquidation, perps, leverage, long, short, position, limit order, trigger, price condition, dca, recurring, scheduled swaps, token metadata, token search, verification, shield, price, valuation, price feed, portfolio, positions, holdings, prediction markets, market odds, event market, invite transfer, send, clawback, create token, studio, claim fee, vesting, distribution lock, unlock schedule, dex integration, rfq integration, routing engine

Démarrage rapide développeur

import { Connection, Keypair, VersionedTransaction } from '@solana/web3.js';

const API_KEY = process.env.JUPITER_API_KEY!;  // depuis portal.jup.ag
if (!API_KEY) throw new Error('Missing JUPITER_API_KEY');
const BASE = 'https://api.jup.ag';
const headers = { 'x-api-key': API_KEY };

async function jupiterFetch<T>(path: string, init?: RequestInit): Promise<T> {
  const res = await fetch(`${BASE}${path}`, {
    ...init,
    headers: { ...headers, ...init?.headers },
  });
  if (res.status === 429) throw { code: 'RATE_LIMITED', retryAfter: 10 };
  if (!res.ok) {
    const raw = await res.text();
    let body: any = { message: raw || `HTTP_${res.status}` };
    try {
      body = raw ? JSON.parse(raw) : body;
    } catch {
      // conserver fallback texte body
    }
    throw { status: res.status, ...body };
  }
  return res.json();
}

// Signer et envoyer toute transaction Jupiter
async function signAndSend(
  txBase64: string,
  wallet: Keypair,
  connection: Connection,
  additionalSigners: Keypair[] = []
): Promise<string> {
  const tx = VersionedTransaction.deserialize(Buffer.from(txBase64, 'base64'));
  tx.sign([wallet, ...additionalSigners]);
  const sig = await connection.sendRawTransaction(tx.serialize(), {
    maxRetries: 0,
    skipPreflight: true,
  });
  return sig;
}

Intent Router (première étape)

Intention utilisateur Famille API Première action
Swap/quote Ultra Swap GET /ultra/v1/order -> signer -> POST /ultra/v1/execute
Lend/borrow/yield Lend POST /lend/v1/earn/deposit ou /withdraw
Leverage/perps Perps On-chain via Anchor IDL (pas d'API REST encore)
Limit orders Trigger POST /trigger/v1/createOrder -> signer -> POST /trigger/v1/execute
DCA/recurring buys Recurring POST /recurring/v1/createOrder -> signer -> POST /recurring/v1/execute
Token search/verification Tokens GET /tokens/v2/search?query={mint}
Price lookup Price GET /price/v3?ids={mints}
Portfolio/positions Portfolio GET /portfolio/v1/positions/{address}
Prediction market integration Prediction Markets GET /prediction/v1/events -> POST /prediction/v1/orders
Invite send/clawback Send POST /send/v1/craft-send -> signer -> envoyer à RPC
Token creation/fees Studio POST /studio/v1/dbc-pool/create-tx -> upload -> submit
Vesting/distribution Lock Program on-chain LocpQgucEQHbqNABEYvBvwoxCPsSbG91A1QaQhQQqjn
DEX/RFQ integration Routing Choisir chemin DEX (trait AMM) vs RFQ (webhook)

Playbooks API

Utilisez chaque bloc comme un contrat d'exécution minimal. Récupérez les références liées pour les formes complètes de requête/réponse, interfaces TypeScript, et détails des paramètres.

Ultra Swap

  • URL de base : https://api.jup.ag/ultra/v1
  • Déclencheurs : swap, quote, gasless, best route
  • Frais : 5-10 bps (standard) ou 20% des frais d'intégrateur avec frais personnalisés configurés
  • Rate Limit : 50 req/10s base, évolue avec le volume d'exécution 24h (voir Rate Limits)
  • Endpoints : /order (GET), /execute (POST), /holdings/{account} (GET), /shield (GET), /search (GET), /routers (GET)
  • Pièges : Les payloads signés ont une TTL de ~2 min. Les transactions sont immuables après réception. Séparer order/execute dans le code et logging. Re-quoter avant exécution si les conditions peuvent avoir changé.
  • Refs : Overview | Order | Execute | Responses | OpenAPI

Lend

  • URL de base : https://api.jup.ag/lend/v1
  • Déclencheurs : lend, borrow, earn, liquidation
  • Programs : Earn jup3YeL8QhtSx1e253b2FDvsMNC87fDrgQZivbrndc9, Borrow jupr81YtYssSyPt8jbnGuiWon5f6x9TcDEFxYe3Bdzi
  • SDK : @jup-ag/lend (TypeScript)
  • Endpoints : /earn/deposit (POST), /earn/withdraw (POST), /earn/mint (POST), /earn/redeem (POST), /earn/deposit-instructions (POST), /earn/withdraw-instructions (POST), /earn/tokens (GET), /earn/positions (GET), /earn/earnings (GET)
  • Pièges : Recalculer l'état du compte avant chaque action qui change l'état. Encoder les vérifications de risques (health factors, limites de liquidation) comme préconditions. Tous deposit/withdraw/mint/redeem retournent une VersionedTransaction base64 non signée.
  • Refs : Overview | Earn | SDK | OpenAPI

Perps


Trigger (Limit Orders)

  • URL de base : https://api.jup.ag/trigger/v1
  • Déclencheurs : limit order, trigger, price condition
  • Frais : 0,1% (non-stablecoin), 0,03% (paires stables)
  • Pagination : 10 orders par page
  • Endpoints : /createOrder (POST), /cancelOrder (POST), /cancelOrders (POST, max 5 par tx), /execute (POST), /getTriggerOrders (GET)
  • Pièges : Frontend applique un min de 5 USD ; on-chain n'a pas de minimum. Program ne valide PAS si les taux sont favorables — valider le prix cible avant create. Token-2022 désactivé. Slippage zéro par défaut ("Exact" mode) ; définir slippageBps pour "Ultra" mode avec taux de remplissage plus élevé.
  • Refs : Overview | Create | Get orders | Best Practices | OpenAPI

Recurring (DCA)

  • URL de base : https://api.jup.ag/recurring/v1
  • Déclencheurs : dca, recurring, scheduled swaps
  • Frais : 0,1% sur tous les orders récurrents
  • Contraintes : Min 100 USD total, min 2 orders, min 50 USD par order
  • Pagination : 10 orders par page
  • Endpoints : /createOrder (POST), /cancelOrder (POST), /execute (POST), /getRecurringOrders (GET)
  • Pièges : Token-2022 non supporté. Les orders récurrents basés sur le prix sont dépréciés — utiliser params.time uniquement.
  • Refs : Overview | Create | Get orders | Best Practices | OpenAPI

Tokens

  • URL de base : https://api.jup.ag/tokens/v2
  • Déclencheurs : token metadata, token search, verification, shield
  • Endpoints : /search?query={q} (GET, séparer les mints par virgule, max 100), /tag?query={tag} (GET, verified ou lst), /{category}/{interval} (GET, catégories : toporganicscore, toptraded, toptrending ; intervalles : 5m, 1h, 6h, 24h), /recent (GET)
  • Pièges : Utiliser l'adresse mint comme identité primaire ; traiter symbol/name comme commodité. Afficher audit.isSus et organicScore dans l'UX.
  • Refs : Overview | Token info v2 | OpenAPI

Price

  • URL de base : https://api.jup.ag/price/v3
  • Déclencheurs : price, valuation, price feed
  • Limite : Max 50 mint IDs par requête
  • Endpoints : /price/v3?ids={mints} (GET, séparés par virgule)
  • Pièges : Les tokens avec tarification peu fiable retournent null ou sont omis (pas une erreur). Échouer fermé sur données manquantes/faible confiance pour actions sensibles à la sécurité. Utiliser le champ confidenceLevel.
  • Refs : Overview | Price v3 | OpenAPI

Portfolio

  • URL de base : https://api.jup.ag/portfolio/v1
  • Statut : Beta — plateformes Jupiter uniquement
  • Déclencheurs : portfolio, positions, holdings
  • Endpoints : /positions/{address} (GET), /positions/{address}?platforms={ids} (GET), /platforms (GET), /staked-jup/{address} (GET)
  • Pièges : Traiter les positions vides comme état valide. La réponse est beta — normaliser dans un schéma interne stable. Types d'éléments : multiple, liquidity, trade, leverage, borrowlend.
  • Refs : Overview | Jupiter positions | OpenAPI

Prediction Markets

  • URL de base : https://api.jup.ag/prediction/v1
  • Statut : Beta (breaking changes possibles)
  • Géo-restreint : IPs USA et Corée du Sud bloquées
  • Convention de prix : 1 000 000 unités natives = $1,00 USD
  • Déclencheurs : prediction markets, market odds, event market
  • Dépôt mints : JupUSD (JuprjznTrTSp2UFa3ZBUFgwdAmtZCq4MQCwysN55USD), USDC
  • Endpoints : /events (GET), /events/search (GET), /markets/{marketId} (GET), /orderbook/{marketId} (GET), /orders (POST), /orders/status/{pubkey} (GET), /positions (GET), /positions/{pubkey} (DELETE), /positions/{pubkey}/claim (POST), /history (GET), /leaderboards (GET)
  • Pièges : Vérifier position.claimable avant de réclamer. Les gagnants reçoivent $1/contrat.
  • Refs : Overview | Events | Positions | OpenAPI

Send

  • URL de base : https://api.jup.ag/send/v1
  • Statut : Beta
  • Déclencheurs : invite transfer, send, clawback
  • Tokens supportés : SOL, USDC, memecoins
  • Endpoints : /craft-send (POST), /craft-clawback (POST), /pending-invites (GET), /invite-history (GET)
  • Pièges : Exigence double signature — keypair du sender + recipient (dérivé du code invite). Les réclamations uniquement via Jupiter Mobile (pas de réclamation API). Ne jamais exposer les codes invite.
  • Refs : Overview | Invite code | Craft send | OpenAPI

Studio

  • URL de base : https://api.jup.ag/studio/v1
  • Statut : Beta
  • Déclencheurs : create token, studio, claim fee
  • Endpoints : /dbc-pool/create-tx (POST), /dbc-pool/submit (POST, multipart/form-data), /dbc-pool/addresses/{mint} (GET), /dbc/fee (POST), /dbc/fee/create-tx (POST)
  • Flux : create-tx -> upload image vers URL présignée -> upload metadata vers URL présignée -> signer -> submit via /dbc-pool/submit
  • Pièges : Doit être soumis via /dbc-pool/submit (pas externalement) pour que le token reçoive une page Studio sur jup.ag. Codes d'erreur : 403 = non autorisé pour pool, 404 = proxy account non trouvé.
  • Refs : Overview | Create token | Claim fee | OpenAPI

Lock

  • Program ID : LocpQgucEQHbqNABEYvBvwoxCPsSbG91A1QaQhQQqjn
  • Déclencheurs : vesting, distribution lock, unlock schedule
  • Intégration : Program on-chain uniquement (pas d'API REST)
  • Source : github.com/jup-ag/jup-lock
  • UI : lock.jup.ag
  • Sécurité : Audité par OtterSec et Sec3
  • Pièges : Pas d'API REST. Utiliser les scripts d'instruction du répertoire cli/src/bin/instructions.
  • Refs : Lock overview

Routing

  • Déclencheurs : dex integration, rfq integration, routing engine
  • Engines : Juno (meta-aggregator), Iris (multi-hop DEX routing, alimente Ultra), JupiterZ (RFQ market maker quotes)
  • DEX Integration (vers Iris) : Gratuit, pas de frais. Prérequis : health du code, audit de sécurité, traction commerciale. Implémenter le crate jupiter-amm-interface. Critique : Pas d'appels réseau dans l'implémentation (les accounts sont pré-batched et en cache). Ref impl : github.com/jup-ag/rust-amm-implementation
  • RFQ Integration (JupiterZ) : Les market makers hébergent webhook à /jupiter/rfq/quote (POST, 250ms), /jupiter/rfq/swap (POST), /jupiter/rfq/tokens (GET). Requis : taux de remplissage 95%, réponse 250ms, expiration 55s. SDK : github.com/jup-ag/rfq-webhook-toolkit
  • Market Listing : Routage instantané pour tokens < 30 jours. Routage normal (vérifié tous les 30 min) demande < 30% de perte sur round-trip $500 OU < 20% d'impact de prix comparant $1k vs $500.
  • Refs : Overview | DEX integration | RFQ integration | Market listing

Rate Limits

Ultra Swap (dynamique, basé sur le volume) :

Volume d'exécution 24h Requêtes par fenêtre 10s
$0 50
$10 000 51
$100 000 61
$1 000 000 165

Les quotas se recalculent tous les 10 minutes. Le plan Pro n'augmente PAS les limites Ultra.

Autres APIs : Gérées au niveau du portal. Voir rate limits du portal.

Sur HTTP 429 : Backoff exponentiel avec jitter : delay = min(baseDelay * 2^attempt + random(0, jitter), maxDelay). Attendre la rafraîchissement de la fenêtre glissante 10s. Ne PAS burst agressivement.

Durcissement production

  1. Auth : Échouer rapidement si x-api-key est manquant ou invalide.
  2. Timeouts : 5s pour les quotes, 30s pour les exécutions, plus timeout d'opération total.
  3. Retries : Uniquement les défaillances transientes/réseau/rate-limit avec backoff exponentiel + jitter.
  4. Idempotence : Ultra /execute accepte la même signedTransaction + requestId pendant 2 min sans exécution dupliquée.
  5. Validation : Valider les adresses mint, la précision des montants, et la propriété du wallet avant les appels.
  6. Safety : Appliquer des guardrails slippage et max-amount depuis la config app.
  7. Observabilité : Logger requestId, API family, endpoint, latency, status, et error code.
  8. UX résilience : Retourner des états exploitables (retry, adjust params, insufficient balance, rate limited).
  9. Cohérence : Réconcilier les états asynchrones (submitted vs confirmed vs failed) avant succès utilisateur final.
  10. Fraîcheur : Re-récupérer les docs référencées quand le comportement diffère du flux attendu.

Bonnes pratiques d'intégration

  1. Commencer par l'overview spécifique à l'API avant coder les appels endpoint.
  2. Appliquer l'auth comme précondition stricte pour toute requête. Ref : Portal setup
  3. Concevoir la logique de retry autour du comportement de rate-limit documenté, pas d'hypothèses fixes. Ref : Rate limits
  4. Mapper toutes les réponses non-succès vers des erreurs app typées en utilisant la sémantique de réponse documentée. Ref : API responses
  5. Pour les produits basés sur les orders (Ultra/Trigger/Recurring), séparer les phases create/execute/retrieve dans le code et les logs.
  6. Traiter la santé réseau/service comme part du comportement runtime (dégrader gracieusement). Ref : Status page

Pattern d'erreur transversal

interface JupiterResult<T> {
  ok: boolean;
  result?: T;
  error?: { code: string | number; message: string; retryable: boolean };
}

async function jupiterAction<T>(action: () => Promise<T>): Promise<JupiterResult<T>> {
  try {
    const result = await action();
    return { ok: true, result };
  } catch (error: any) {
    const code = error?.code ?? error?.status ?? 'UNKNOWN';

    // Rate limit — retry avec backoff
    if (code === 429 || code === 'RATE_LIMITED') {
      return { ok: false, error: { code: 'RATE_LIMITED', message: 'Rate limited', retryable: true } };
    }

    // Erreurs Ultra execute (codes négatifs)
    if (typeof code === 'number' && code < 0) {
      const retryable = [-1, -1000, -1001, -1005, -1006, -2000, -2003, -2005].includes(code);
      return { ok: false, error: { code, message: error?.error ?? 'Execute failed', retryable } };
    }

    // Erreurs program (codes positifs comme 6001 = slippage)
    if (typeof code === 'number' && code > 0) {
      return { ok: false, error: { code, message: error?.error ?? 'Program error', retryable: false } };
    }

    return { ok: false, error: { code, message: error?.message ?? 'UNKNOWN_ERROR', retryable: false } };
  }
}

Politique de contexte frais

Toujours récupérer le contexte le plus frais depuis les docs/specs référencés avant d'exécuter un playbook.

  1. Résoudre l'intention avec Intent Router.
  2. Avant de coder, récupérer les refs liées du playbook (overview + docs spécifiques à l'API).
  3. Si nécessaire pour validation ou ambiguïté, récupérer la spec OpenAPI.
  4. Traiter les docs récupérés comme source de vérité sur mémoire cachée.
  5. Si les docs récupérés entrent en conflit avec ce fichier, suivre les docs récupérés et noter le désaccord.
  6. Si les docs ne peuvent pas être récupérés, déclarer que le contexte est obsolète/non vérifié et continuer avec la meilleure guidance connue.
  7. Conserver l'invariant auth : x-api-key est requis pour les endpoints REST Jupiter (pas pour les flux on-chain-only comme Perps/Lock).

Vérifier

  • Un vrai appel RPC/SDK a été émis (mainnet, devnet, ou validateur local) et le payload de réponse est capturé dans la transcription, pas seulement paraphrasé
  • Chaque transaction a été simulée (simulateTransaction ou équivalent) avant toute étape de signature/envoi ; les logs de simulation sont attachés
  • Pour toute transaction signée/envoyée, la signature résultante est enregistrée et confirmée on-chain (statut retourné par getSignatureStatuses ou une URL explorer)
  • Slippage, priority-fee, et compute-unit limits ont été définis explicitement avec valeurs numériques concrètes, pas laissés aux defaults de la librairie
  • Les adresses de compte, mints, et program IDs utilisés dans la run correspondent aux adresses jupyter-defi documentées pour le cluster cible (pas de mix mainnet/devnet)
  • Le chemin d'erreur a été exercé au moins une fois (solde insuffisant, oracle obsolète, blockhash expiré, etc.) et la gestion d'erreur de l'agent a produit un message lisible

Références opérationnelles

Skills similaires