spicyapiDocumentation
SDK
Contenu principal

SDK Python

Le SDK Python officiel de SpicyAPI (spicyapi) — l’installer, obtenir un devis, lancer votre première génération, téléverser un fichier local, vérifier les webhooks et lire chaque code d’erreur.

spicyapi est le SDK Python officiel de SpicyAPI. Il place la génération d’images, de vidéos et de sons derrière un seul objet client : il joint votre clé API, transforme l’enveloppe de réponse en dictionnaires ordinaires, attend la fin d’une tâche avec une temporisation raisonnable, téléverse les fichiers locaux en un seul appel et vérifie les signatures de webhook en temps constant.

Il demande Python 3.11 ou plus récent et n’a aucune dépendance d’exécution. C’est délibéré : ce paquet entre dans un arbre de dépendances qui est déjà le vôtre, et chaque contrainte qu’il y ajoute est une occasion de conflit de plus.

Est-ce le bon outil ?

Vous voulez…Utilisez
Appeler SpicyAPI depuis votre propre code PythonCe SDK
L’appeler depuis Node.js ou TypeScriptLe SDK TypeScript
L’appeler depuis Go, PHP ou JavaLe SDK Go, PHP ou Java
Générer des contenus depuis un terminal sans écrire de codeLa CLI
Laisser un assistant IA appeler SpicyAPI pour vousLe serveur MCP et l’Agent Skill
Utiliser un modèle de chat ou de texteLa bibliothèque officielle openai, anthropic ou google-genai pointée vers SpicyAPI ; voir Texte et streaming

L’installer

pip install spicyapi

Placez ensuite votre clé dans l’environnement, pour qu’elle n’apparaisse jamais dans votre code ni dans le fichier d’historique de votre shell :

export SPICY_API_KEY="sk-spicy-..."

Votre premier résultat

Demandez le prix, décidez, créez la tâche, attendez, lisez les fichiers. Le devis est gratuit et ne réserve rien.

import os, uuid
from spicyapi import SpicyClient, output_assets

client = SpicyClient()  # lit SPICY_API_KEY dans l’environnement

model = client.get_model("MODEL_ID_FROM_CATALOG")
quote = client.quote_task(model=model["model"], input_data={"prompt": "a lantern in fog"})
print(quote["estimatedCost"], quote["maxCharge"])   # décidez avant de dépenser

task = client.create_task(
    model=model["model"],
    input_data={"prompt": "a lantern in fog"},
    idempotency_key=str(uuid.uuid4()),
    quote_id=quote["quoteId"],
    expected_cost=quote["estimatedCost"],
)
final = client.wait_for_terminal(task["taskId"])
for asset in output_assets(final):                  # fonction du module, pas une méthode
    print(asset["url"])

MODEL_ID_FROM_CATALOG est un emplacement réservé. Prenez un vrai identifiant dans le catalogue authentifié — client.list_models(), c’est-à-dire GET /api/v1/models — et jamais de mémoire ni d’une page ancienne : des modèles sont ajoutés, suspendus et retirés. Construisez input_data à partir de l’inputSchema propre à ce modèle, que renvoie list_models(include_schema=True) ; chaque modèle accepte des champs différents.

Les montants reviennent sous forme de chaînes décimales en dollars américains, jamais de flottants, parce qu’un flottant binaire ne peut pas contenir exactement la plupart des montants décimaux. Comparez-les et additionnez-les avec decimal.Decimal. Il n’y a ni crédits ni points nulle part dans cette API.

wait_for_terminal rend la main dès qu’un état final est atteint. Un état final n’est pas pour autant un succès : vérifiez final["state"] avant de lire la sortie.

Certains points de terminaison répondent par du texte plutôt que par des fichiers. Lisez d’abord output_text(final) quand le modèle produit une transcription ou une légende : un client qui ne parcourt que la liste des fichiers déclare qu’une tâche parfaitement réussie n’a rien produit.

Partir d’un fichier local

L’image vers vidéo, le remplacement de personne et la retouche d’image demandent tous que votre matière première soit d’abord chez nous. upload_file réalise le téléversement en trois temps — ticket, PUT vers le stockage, validation — en un seul appel et renvoie une URI spicy://. C’est cette URI qui part dans l’entrée.

uploaded = client.upload_file("/path/to/reference.png")
task = client.create_task(
    model="MODEL_ID_FROM_CATALOG",
    input_data={"image": uploaded["uri"], "prompt": "slow dolly in"},
    idempotency_key=str(uuid.uuid4()),
)

Une URL HTTPS publiquement joignable peut aller directement dans l’entrée, sans aucun téléversement. Les images sont acceptées jusqu’à 10 Mio, l’audio et la vidéo jusqu’à 90 Mio ; voir Médias pour le reste.

Webhooks

verify_webhook est une fonction de module : un gestionnaire de requête peut donc s’en servir sans construire de client. Elle compare en temps constant et ne vérifie l’horodatage qu’une fois la signature validée.

from spicyapi import verify_webhook

delivery = verify_webhook(
    raw_body=request.body,                      # les octets exacts, avant toute analyse
    signature=request.headers["X-Webhook-Signature"],
    timestamp=request.headers["X-Webhook-Timestamp"],
    payload_version=request.headers["X-Webhook-Payload-Version"],
    secret=os.environ["SPICY_WEBHOOK_SECRET"],
)

Vérifiez les octets bruts. Un json.loads suivi d’un json.dumps les modifie, et la signature ne correspondra plus jamais. Les livraisons sont réessayées : dédoublonnez sur l’identifiant de livraison. Le format complet des livraisons et le calendrier des nouvelles tentatives figurent dans Webhooks.

Erreurs

Chaque échec lève une SpicyApiError qui porte status, code, request_id et retry_after_seconds. Branchez sur code, jamais sur le texte du message : les messages sont traduits, les codes non.

Le statut HTTP 503 est partagé par trois codes métier différents : le lire seul ne suffit donc pas à décider quoi faire.

codeSignificationQue faire
40003Les octets téléversés ne correspondent pas à leur ticketRecommencez avec un ticket neuf
40004Aucun déploiement ne sert cette combinaison de paramètresChangez le paramètre nommé dans le message
40201Solde insuffisantRechargez
40901Le prix a bougé avant la création de la tâcheRedemandez un devis, en gardant la même clé d’idempotence
503Une dépendance est brièvement indisponiblePatientez selon Retry-After
50301Le modèle n’a pour l’instant aucun déploiement ni prix utilisableActualisez le catalogue, sans marteler
50302Une génération synchrone a échoué en amont et a été rembourséeRéessayez avec une nouvelle clé d’idempotence

err.recovery renvoie les mêmes consignes à l’exécution. Citez request_id quand vous contactez le support. Tous les codes sont listés dans Erreurs.

Deux choses qui vous feront économiser

Gardez une clé d’idempotence par soumission. Réutilisez-la pour chaque renvoi de cette soumission, y compris après un dépassement de délai ou une connexion coupée. Une réponse perdue ne prouve pas que la tâche n’a pas été créée : une clé neuve transforme un résultat inconnu en une seconde tâche payante. Voir Idempotence.

Une tâche qui réussit est facturée, même si le résultat déçoit. Demandez un devis d’abord quand le prix compte ; quote_task ne réserve rien et ne crée rien.

Ce que ce paquet ne fait pas

  • Les modèles de texte. Ils parlent les formats réseau d’OpenAI, d’Anthropic et de Gemini : les bibliothèques officielles openai, anthropic et google-genai fonctionnent donc déjà ; pointez-les vers https://api.spicyapi.ai/v1 avec la même clé. Voir Texte et streaming.
  • Les applications navigateur, mobiles et de bureau. N’embarquez jamais cette clé dans une application : une clé compilée dans un client est une clé publique. Appelez depuis votre serveur.
  • Choisir un modèle ou remplir ses champs. Il vous fournit le catalogue et le schéma de chaque modèle ; c’est vous qui décidez quoi envoyer.
  • Annuler une tâche. Une fois acceptée, une tâche va jusqu’au bout. Arrêter votre programme n’arrête que votre attente.

Le code source

Le paquet est sous licence MIT et développé au grand jour sur github.com/spicyapi-ai/spicy-python. Son README est la visite guidée la plus courte et la plus complète du client ; cette page y ajoute les notions qui l’entourent.

Étapes suivantes

Sur cette page