API, CLI et MCP
Tout ce que vous pouvez faire dans l’application est aussi accessible avec votre code et vos agents : soumettre des liens, des fichiers ou des comptes entiers, attendre le marquage et consulter les résultats. Un même contrat, trois façons d’y accéder. Les traitements sont asynchrones, les écritures sont idempotentes et vous voyez le coût avant et après.
Vous découvrez Garfunkel ? Découvrez comment un post est analysé.
Démarrage rapide
Créez une clé API dans l’application, sous Paramètres → Développeurs, définissez-la comme GARFUNKEL_API_KEY, puis choisissez votre mode d’accès. Les clients MCP peuvent aussi se connecter avec OAuth plutôt qu’avec une clé.
export GARFUNKEL_API_KEY=gma_live_…
garfunkel submit urls.txt --category sports --dry-run
garfunkel submit urls.txt --category sports --wait
garfunkel results export job_… --format jsonlAuthentification
Envoyez Authorization: Bearer gma_live_…, une clé API associée à votre organisation, depuis Clés API. Le CLI et MCP lisent GARFUNKEL_API_KEY. Chaque POST accepte une Idempotency-Key ; les nouvelles tentatives renvoient la réponse d’origine et ne vous facturent jamais deux fois.
Soumettre un traitement
La soumission renvoie immédiatement un identifiant de traitement (202). priority peut être standard (moins cher, de quelques minutes à quelques heures) ou fast. Définissez dry_run: true pour obtenir gratuitement une estimation avec validation de chaque élément.
curl -X POST https://garfunkel.gar-ai.com/api/v1/jobs \
-H "Authorization: Bearer $GARFUNKEL_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"items": [{ "url": "https://www.tiktok.com/@user/video/7412345678901234567" }],
"options": { "translate_to": "en" },
"dry_run": true
}'États des éléments : queued → fetching → processing → succeeded | failed | canceled.
Traitements de compte
« Chaque publication de @handle depuis le 2025-01-01. » Le comptage coûte 2 ¢ pour 20 publications encore inconnues de votre équipe. Le montant est retenu à l’avance et vous est recrédité à mesure que vous les analysez. La tâche attend ensuite dans awaiting_confirmation, avec pour chaque compte posts_found, oldest_post_at, reached_since et notices (par exemple, si une plateforme ne renvoie que les publications datant d’une date plus récente). Confirmez avec POST /jobs/{id}/confirm ou définissez options.max_credits pour confirmer automatiquement.
{
"items": [
{ "account": "@nike", "platform": "tiktok", "since": "2025-01-01", "max_posts": 1000 },
{ "account": "https://x.com/nasa", "since": "2025-01-01" }
],
"options": { "max_credits": 50000 }
}Téléversements
Les données sont envoyées directement vers le stockage, sans passer par l’API. Les fichiers qui ne sont associés à aucun traitement dans les 24 heures sont supprimés.
POST /api/v1/uploads
{ "filename": "clip.mp4", "content_type": "video/mp4", "size_bytes": 1234567 }
→ { "id": "upl_…", "upload_url": "<presigned PUT>", "method": "PUT", "headers": {…}, "expires_at": "…" }
# PUT the bytes straight to storage, then submit { "upload_id": "upl_…" } as a job item.Résultats
Un post analysé. Les vecteurs d’intégration sont renvoyés uniquement avec ?include=embedding. pacing provient de la détection des plans (bêta).
{
"item_id": "itm_01J…",
"job_id": "job_01J…",
"source": { "platform": "tiktok", "url": "…", "author": "…", "posted_at": "…",
"metrics": { "views": 0, "likes": 0, "comments": 0, "shares": 0 } },
"caption": "…",
"language": "es",
"transcript": { "text": "…", "segments": [{ "start": 0.0, "end": 2.1, "text": "…" }] },
"translation": { "language": "en", "caption": "…", "transcript": "…", "on_screen_text": "…" },
"summary": "…",
"tags": { "format": "…", "theme": "…", "tone": ["…"], "topics": ["…"], "keywords": ["…"] },
"hook": { "type": "…", "timing_s": 1.2, "confidence": 0.8 },
"pacing": { "beta": true, "shot_count": 14, "avg_shot_s": 2.1, "cuts_per_s": 0.47, "first_cut_s": 0.9 },
"embedding": { "dims": 1024 },
"credits_charged": 12,
"processed_at": "…"
}Points de terminaison
| Point de terminaison | Fonction |
|---|---|
| POST /api/v1/jobs | Soumettre des URL, des fichiers ou des comptes (dry_run pour obtenir une estimation gratuite). |
| GET /api/v1/jobs/{id} | État, nombre d’éléments par état, montants (en centimes) réservés, facturés et libérés, comptes et avis. |
| GET /api/v1/jobs/{id}/items | Éléments paginés ; filtrer avec ?status=failed. |
| POST /api/v1/jobs/{id}/confirm | Réserver le montant pour un traitement de compte en attente de confirmation. |
| POST /api/v1/jobs/{id}/cancel | Annuler les éléments en attente ; le montant réservé est reversé sur le solde. |
| POST /api/v1/jobs/{id}/retry | Relancer les éléments en échec (nouvelle estimation et nouvelle réservation). |
| POST /api/v1/uploads | Requête PUT pré-signée pour vos propres médias. |
| GET /api/v1/results | Filtrer avec job_id, platform, tag, q. |
| POST /api/v1/results/search | Recherche sémantique dans les vecteurs d’intégration. |
| GET /api/v1/results/export | Export CSV ou JSONL en flux. |
| GET /api/v1/credits | Solde (centimes + balance_usd), montants réservés, recharges, récompenses liées aux dépenses. |
| DELETE /api/v1/data | Supprimez toutes les données de votre organisation. |
Erreurs
Toutes les réponses autres que 2xx utilisent le même format. Codes : unauthorized, forbidden, not_found, invalid_request, insufficient_credits, rate_limited, idempotency_conflict, counting_in_progress, internal_error.
{ "error": { "code": "insufficient_credits",
"message": "Job needs $1.80; your balance is 42¢.",
"details": { "required": 180, "balance": 42 },
"retryable": false } }Les codes d’échec d’un élément sont stables et ne sont jamais facturés :
| post_not_found | Cette publication n’existe plus. |
| post_private | Cette publication n’est pas publique. |
| unsupported_url | Cette URL ne correspond pas à une publication TikTok, Instagram ou X. |
| media_unavailable | La plateforme n’a pas fourni le média. |
| media_too_large | La taille dépasse la limite autorisée. |
| upload_invalid | Impossible de lire le fichier envoyé. |
| provider_error | Échec du service en amont : vous pouvez réessayer. |
| internal_error | Une erreur s’est produite de notre côté : vous pouvez réessayer. |
CLI
export GARFUNKEL_API_KEY=gma_live_…
garfunkel submit urls.txt --category sports --dry-run # free estimate
garfunkel submit urls.txt --category sports --wait # run it
garfunkel results export job_… --format jsonl -o results.jsonl
# Whole accounts: counting is 2¢ per 20 posts (credited back when analyzed); you confirm the analysis
garfunkel submit --accounts accounts.txt --since 2025-01-01 --max-credits 50000Codes de sortie : 0 succès, 2 utilisation incorrecte, 3 authentification, 4 solde insuffisant, 5 traitement terminé avec des éléments en échec, 6 délai dépassé.
MCP
MCP distant via HTTP Streamable à l’adresse /api/mcp, avec OAuth (ajoutez l’URL dans Claude, ChatGPT ou Cursor et autorisez l’accès) ou une clé API. Outils : estimate_job, submit_job, create_upload, confirm_job, list_job_posts, get_job, get_team, wait_for_job, list_results, get_result, list_accounts, get_account, analyze_comments, refresh_metrics, get_comments, search_results, export_results, chat_with_data, get_credit_balance, show_post, create_checkout.
{
"mcpServers": {
"garfunkel": {
"type": "http",
"url": "https://garfunkel.gar-ai.com/api/mcp",
"headers": {
"Authorization": "Bearer gma_live_…"
}
}
}
}