spicyapiDocumentation
Développer avec l’API
Contenu principal

Catalogue des modèles et schémas

Choisissez les modèles appelables dans le catalogue authentifié, lisez leurs tarifs et construisez les requêtes selon leur JSON Schema actuel.

createTask.model prend la valeur exacte de model renvoyée par la réponse authentifiée de GET /api/v1/models. Son input est défini par l’inputSchema actuel de cette même entrée. Cette réponse obtenue à l’exécution est la seule source de vérité pour un ID appelable.

Ne copiez pas un ID depuis une page statique

Les instantanés de lancement, pages de familles et catalogues des créateurs de modèles servent à découvrir les produits. Ils peuvent inclure des entrées prévues, désactivées ou renommées et ne doivent jamais servir de repli lorsque le catalogue actuel est vide. Avant toute tâche payante, récupérez le catalogue authentifié et exigez à la fois enabled: true et available: true.

Dans les exemples de cette page, MODEL_ID_FROM_CATALOG est une valeur à remplacer, pas un véritable modèle : utilisez une valeur de model issue de votre catalogue actuel. La lecture du catalogue est gratuite.

Sélectionner un modèle et son entrée validée

Les schémas de requête diffèrent entre modèles. Pour un exemple exécutable sûr, sélectionnez ensemble un modèle actuel et l’un de ses exemples validés côté serveur :

const response = await fetch(
  'https://api.spicyapi.ai/api/v1/models?includeSchema=1&includeExamples=1',
  { headers: { Authorization: `Bearer ${process.env.SPICY_API_KEY}` } },
);
const envelope = await response.json();
if (!response.ok || envelope.code !== 200) throw new Error(envelope.msg);

const selected = envelope.data.items.find(
  (item) => item.enabled && item.available && item.examples?.length,
);
if (!selected) throw new Error('No callable model with a validated example');

const createTaskBody = {
  model: selected.model,
  input: selected.examples[0].input,
};

Chaque exemple est un input complet déjà validé par le serveur contre le schéma actuel : vous pouvez l’envoyer tel quel.

Lire le catalogue par programmation

GET /api/v1/models
GET /api/v1/models/{model}
curl "https://api.spicyapi.ai/api/v1/models?modality=video" \
  -H "Authorization: Bearer $SPICY_API_KEY"

La liste n’est pas paginée : une réponse contient tous les modèles visibles par votre clé qui correspondent aux filtres. Tous les paramètres sont facultatifs.

ParamètreSignification
modalityimage, video, audio ou text
providerCréateur du modèle, avec correspondance exacte et sensible à la casse, par exemple ByteDance. Copiez-le depuis le provider d’une entrée
taskUne tâche, par exemple text-to-image, edit (retouche d’image), image-to-video, text-to-video, reference-to-video, speech-to-text, video-analyze, video-edit, video-extend, character-animation ou chat. Lisez tasks dans le catalogue pour la liste actuelle. La retouche d’image accepte deux formes : les modèles sont publiés en .../edit, mais tasks les classe comme image-to-image, et le filtre accepte les deux
searchTexte recherché sans distinction de casse dans l’ID ou le nom affiché du modèle, jusqu’à 128 caractères
includeSchematrue ou 1 ajoute l’inputSchema de chaque entrée
includeExamplestrue ou 1 ajoute les examples de chaque entrée, validés contre le schéma actuel

Le point de terminaison d’un modèle, GET /api/v1/models/{model}, inclut toujours inputSchema et examples ; includeSchema et includeExamples ne concernent que la liste. Les barres obliques de l’ID peuvent rester telles quelles ; encodez-les en pourcentage uniquement si votre client HTTP considère un paramètre de chemin comme un seul segment. Un modèle inexistant ou non proposé actuellement renvoie 404.

Une réponse de liste abrégée :

{
  "code": 200,
  "msg": "success",
  "data": {
    "total": 1,
    "items": [
      {
        "model": "MODEL_ID_FROM_CATALOG",
        "family": "…",
        "displayName": "…",
        "provider": "…",
        "modality": "video",
        "tasks": ["image-to-video"],
        "async": true,
        "enabled": true,
        "available": true,
        "availability": "available",
        "taskTimeoutSeconds": 1200,
        "maxOutputDurationSeconds": 10,
        "quantityField": "duration_seconds",
        "pricing": [
          { "variant": "generate_audio=false;resolution=720p", "unit": "per_second", "price": "0.05", "currency": "USD" },
          { "variant": "generate_audio=true;resolution=720p", "unit": "per_second", "price": "0.08", "currency": "USD" }
        ],
        "startingPrice": { "variant": "generate_audio=false;resolution=720p", "unit": "per_second", "price": "0.05", "currency": "USD" },
        "badges": ["audio_output"],
        "relatedModels": [],
        "version": "v1",
        "updatedAt": "2026-09-16T16:47:57Z"
      }
    ]
  },
  "request_id": "req_01k3m8x9q2z4v7n5p6r8s0t1w2"
}

Les tarifs ci-dessus sont illustratifs. inputSchema et examples n’apparaissent dans les entrées de liste que sur demande.

Les champs à exploiter côté client

ChampFonction
modelValeur exacte à envoyer dans createTask.model, sous la forme publisher/model/task
familyIdentifiant stable de famille de produits pour regrouper les points de terminaison associés
displayNameNom lisible du point de terminaison
providerCréateur du modèle, par exemple le laboratoire qui l’a développé
modality / tasksMédia de classement du point de terminaison dans le catalogue et tâche effectuée. modality pilote la navigation et le filtre modality ; ce n’est pas une promesse sur le type de résultat : un point de terminaison speech-to-text est classé dans audio et répond en texte. Voir Forme des sorties
toolkitFamille d’outils du point de terminaison, actuellement uniquement subject-swap. Absent lorsque le modèle n’est dans aucun ensemble : testez donc la valeur, pas la présence de la clé. Comme badges, ce classement ne modifie jamais l’admission, le tarif ni la validation. Voir Remplacement de sujet
asynctrue : créer une tâche et récupérer le résultat par polling ou webhook. false : la réponse est renvoyée directement
inputSchemaJSON Schema 2020-12 utilisé pour créer les formulaires et valider les requêtes
examplesEntrées validées contre le schéma actuel ; dans la liste, renvoyées uniquement sur demande
enabledIndique si l’entrée peut être appelée maintenant. Le catalogue liste aussi les entrées publiées mais pas encore ouvertes ou suspendues par la plateforme, renvoyées à false. Vérifiez ce champ avec available avant d’envoyer une tâche
availableIndique si le modèle peut être appelé maintenant. false signifie qu’un appel échouerait, par exemple faute de tarif actuel
availabilityPhase annoncée : planned, available, preview (champs et sorties susceptibles d’évoluer) ou maintenance (échec temporaire, retour prévu)
pricing / startingPriceVos tarifs ; voir Lire les tarifs
quantityFieldChamp d’entrée dont la valeur est la quantité facturée, souvent duration_seconds pour la vidéo. Une valeur vide signifie une unité par appel. Lisez-le toujours dans le catalogue
taskTimeoutSecondsÉchéance d’exécution d’une tâche sur la plateforme. Ce n’est pas une durée de média
maxOutputDurationSecondsDurée de sortie maximale du modèle, tirée du maximum de sa propriété duration_seconds ; absent si aucun maximum n’est déclaré
badgesIndications de capacités et de licence, par exemple commercial_use ou no_watermark. Ignorez les valeurs inconnues
relatedModelsAlternatives ou étapes suivantes sélectionnées, sous forme d’IDs appelables
version / updatedAtSuivi des changements : comparez-les pour savoir si une lecture ultérieure a modifié quelque chose

mature et policyTier sont des indications informatives. Elles n’interviennent pas dans l’acceptation d’une requête.

Lire les tarifs

Chaque entrée de pricing correspond à un palier tarifaire :

ChampSignification
unitper_image, per_second (de média de sortie), per_request ou per_1k_tokens
priceVotre tarif unitaire en dollars américains, sous forme de chaîne décimale. Il tient déjà compte des tarifs de votre compte, qui peuvent différer entre comptes
variantRéglages sélectionnant ce palier. Vide si le modèle a un tarif unique ; valeur seule, par exemple 720p, lorsqu’un seul champ sélectionne le palier ; paires field=value séparées par ; et triées par nom de champ, par exemple generate_audio=false;resolution=480p, lorsque plusieurs champs le sélectionnent
currencyToujours USD
regularPrice, offerLabel, offerPercent, offerEndsAtPrésents uniquement pendant une offre client : tarif avant l’offre, nom de l’offre, pourcentage et date de fin

startingPrice est l’entrée la moins chère, pas le prix de vos réglages. Les champs sélectionnant un palier figurent dans inputSchema["x-pricing"].variantFields lorsqu’il est présent. Sinon, ce sont les champs marqués x-ui.affects_price: true, sauf quantityField. Un champ omis prend son default de schéma.

  • Modèles média : le coût est price × quantity, avec la valeur de quantityField de votre entrée comme quantité, ou une unité lorsque quantityField est vide. Certains points de terminaison ajoutent une facturation distincte pour chaque entrée supplémentaire, le plus souvent par image de référence. C’est une vraie composante de la facture, pas un détail d’arrondi : pour une retouche acceptant un tableau de références, le remplir peut multiplier le montant alors que unit, quantity, variant et le price du palier restent identiques à ceux d’une seule image. Le calcul précédent sous-estime alors la facture sans indice visible. Le signe lisible par machine est un champ marqué x-ui.affects_price: true, qui n’est ni quantityField ni listé dans x-pricing.variantFields : il change le montant sans sélectionner de palier. Pour un tel point de terminaison, considérez pricing comme un minimum et prenez le montant d’un devis.
  • Modèles de texte (per_1k_tokens) : un seul nombre ne peut décrire la facture. price est uniquement le tarif des tokens de sortie pour 1 000 tokens. Les tokens d’entrée et d’entrée en cache ont leurs propres tarifs, généralement plus bas, facturés selon l’utilisation mesurée de chaque appel. Ne multipliez pas price par le nombre total de tokens. Les tarifs par million de tokens d’entrée, d’entrée en cache et de sortie figurent sur la page de chaque modèle et dans le price.perMillionTokens du catalogue public.

Pour connaître avant paiement le montant d’une requête exacte sur l’API native, utilisez POST /api/v1/jobs/quote. Les montants définitifs figurent dans la trace de tâche (cost avec settled: true) et dans Facturation.

Mettre le catalogue en cache

  • La réponse du catalogue peut être mise en cache jusqu’à 60 secondes (Cache-Control: private, max-age=60). Utilisez uniquement un cache privé par compte : les tarifs dépendent du compte, donc jamais un cache CDN partagé ou public.
  • Au-delà, ne le relisez pas avant chaque tâche. Les lectures du catalogue utilisent le quota de lecture du compte, indépendamment de l’envoi des tâches. Le récupérer avant chaque appel gaspille toujours la capacité de lecture ; voir Limites de débit.
  • Actualisez-le périodiquement, par exemple toutes les quelques minutes, après une erreur de validation 400 et lorsqu’une soumission pour ce modèle est refusée.
  • Gardez la version et l’updatedAt de l’entrée utilisée pour savoir si une lecture ultérieure a changé quelque chose.
  • Ne distribuez jamais un schéma figé codé en dur et ne vous rabattez jamais sur une page statique si le catalogue actuel ne contient aucun élément appelable.

Règles partagées du schéma et du Playground

inputSchema utilise JSON Schema 2020-12. Les mots-clés standard pilotent la validation serveur ; l’objet x-ui de chaque propriété décrit uniquement l’ordre, la présentation du Playground et les indications d’actualisation des devis. Les clients doivent ignorer les extensions de présentation inconnues, qui ne remplacent jamais required, les énumérations, les bornes ou les branches conditionnelles. Voir le Contrat Spicy Schema complet.

Construire votre propre table de paramètres par modèle

Ce site ne fournit aucune table de paramètres par modèle. Ce n’est pas par manque d’effort : les modèles et champs évoluent chaque semaine, toute copie statique diverge, et lire un paramètre périmé mène à un 400 ou à un tarif erroné. Les paramètres ont une seule source, l’inputSchema du catalogue. Le Playground affiche ce même document et le SDK le valide.

Traduire chaque partie du schéma en table

Dans le schémaDans votre table de paramètres
Une clé de propertiesNom du paramètre. Les champs sont unifiés entre modèles : un sens, un nom partout
Présence dans requiredObligatoire ou facultatif
anyOf / allOfObligatoire sous condition. anyOf = fournir au moins un de ces champs ; allOf avec if → then = fournir A oblige à fournir B
typeType
descriptionTexte d’aide anglais affichable tel quel ; vous n’avez pas à le rédiger
enumValeurs acceptées. Si x-ui.enum_labels existe, utilisez-le pour convertir les valeurs en libellés lisibles
minimum / maximumPlage acceptée ; x-ui.step donne le pas et x-ui.unit le suffixe (s, px)
minItems / maxItemsNombre d’entrées accepté dans un tableau. Sans cela, la ligne ne renseigne pas sur la limite rencontrée
itemsForme d’une entrée de tableau. Lorsque items.type vaut object, ce sous-schéma est un schéma d’objet complet : lisez ses required, additionalProperties et, pour chaque sous-champ, type, description, plage et default. Affichez-les en table imbriquée plutôt que dans une zone de texte libre
defaultValeur par défaut lorsque le champ est omis
x-ui.orderClé de tri, valeurs décroissantes d’abord. Ne triez pas selon l’ordre des clés de properties : l’ordre des clés d’un objet JSON ne fait pas partie du contrat
x-ui.primaryÉpingler en haut comme entrée principale
x-ui.advancedPeut être replié dans une section avancée
x-ui.affects_priceMarquer comme affectant le tarif ; une modification nécessite un nouveau devis
x-ui.widgetContrôle à afficher dans un formulaire modifiable, parmi treize valeurs ; voir Spicy Schema

Les branches conditionnelles n’apparaissent qu’à la racine d’inputSchema, sous deux formes : anyOf, dont chaque branche liste uniquement les champs required (« fournissez au moins un de ces champs »), et allOf, dont chaque branche est if → then (« fournir A oblige à fournir B »). Ne les déduisez pas de la famille et n’attendez pas oneOf, not ni dependentSchemas. Les nouveaux points de terminaison suivent les champs canoniques de Spicy Schema ; les anciens suivent leur schéma actuel.

Récupérer le schéma

const modelId = 'MODEL_ID_FROM_CATALOG'; // the exact `model` value from GET /api/v1/models
const res = await fetch(`https://api.spicyapi.ai/api/v1/models/${modelId}`, {
  headers: { Authorization: `Bearer ${process.env.SPICY_API_KEY}` },
});
const { data } = await res.json();
const schema = data.inputSchema;

const rows = Object.entries(schema.properties)
  .sort(([, a], [, b]) => (b['x-ui']?.order ?? 0) - (a['x-ui']?.order ?? 0))
  .map(([name, prop]) => ({
    name,
    required: (schema.required ?? []).includes(name),
    type: prop.type,
    description: prop.description,
    values: prop.enum
      ? prop.enum.map((v) => prop['x-ui']?.enum_labels?.[v] ?? v)
      : prop.minimum !== undefined || prop.maximum !== undefined
        ? [`${prop.minimum ?? ''}–${prop.maximum ?? ''}${prop['x-ui']?.unit ?? ''}`]
        : [],
    default: prop.default,
    affectsPrice: prop['x-ui']?.affects_price === true,
    advanced: prop['x-ui']?.advanced === true,
  }));

Cet exemple s’arrête volontairement aux valeurs scalaires : il laisse values vide pour un tableau, puisque celui-ci définit ses entrées par items, minItems et maxItems, pas par enum ou une plage. Complétez-le avant de le distribuer : une ligne montrant un tableau comme un simple array sans forme d’entrée ni limite de longueur n’est pas exploitable par le lecteur.

La réponse d’un modèle renvoie aussi examples : chacun est une entrée complète déjà validée côté serveur contre le schéma actuel. Il sert donc d’exemple minimal exécutable dans vos documents et de corps de requête à envoyer tel quel. C’est plus sûr qu’un exemple composé à la main, qui devient périmé quand le schéma change, contrairement à examples.

Ce même code couvre tout modèle en changeant modelId et ne devient pas périmé lorsque nous ajoutons des modèles. Pour créer une table du catalogue entier, parcourez les items de GET /api/v1/models?includeSchema=1 et mettez-la en cache selon Mise en cache du catalogue.

Une aide plus longue que description

description est une phrase dimensionnée pour un libellé de formulaire. Si un paramètre demande davantage d’explications, le catalogue public porte une seconde note par paramètre :

curl "https://api.spicyapi.ai/console/v1/catalog/models/MODEL_ID_FROM_CATALOG?locale=en"

La réponse d’un modèle renvoie paramNotes, un objet indexé par nom de paramètre, dans l’une des dix langues documentaires via locale. Il contient ce qui ne tient pas dans un libellé : par rapport à quoi une valeur est mesurée, quel réglage ralentit sensiblement l’appel et quelles entrées acceptées par le schéma peuvent néanmoins donner un résultat décevant. Pour un paramètre pointant vers un fichier que vous hébergez, c’est généralement le seul endroit indiquant si nous le récupérons, quand et ce qui se passe s’il est inutilisable.

Deux limites : paramNotes est disponible dans le catalogue public, sans clé, pas dans le GET /api/v1/models authentifié ; lisez-le donc séparément et mettez-le en cache à côté du schéma. Il s’agit d’un texte explicatif, jamais d’une règle : inputSchema reste seul à décider de l’acceptation d’une requête.

Sur cette page