Aller au contenu

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 jsonl

Authentification

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 terminaisonFonction
POST /api/v1/jobsSoumettre 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}/confirmRéserver le montant pour un traitement de compte en attente de confirmation.
POST /api/v1/jobs/{id}/cancelAnnuler les éléments en attente ; le montant réservé est reversé sur le solde.
POST /api/v1/jobs/{id}/retryRelancer les éléments en échec (nouvelle estimation et nouvelle réservation).
POST /api/v1/uploadsRequête PUT pré-signée pour vos propres médias.
GET /api/v1/resultsFiltrer avec job_id, platform, tag, q.
POST /api/v1/results/searchRecherche sémantique dans les vecteurs d’intégration.
GET /api/v1/results/exportExport CSV ou JSONL en flux.
GET /api/v1/creditsSolde (centimes + balance_usd), montants réservés, recharges, récompenses liées aux dépenses.
DELETE /api/v1/dataSupprimez 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_foundCette publication n’existe plus.
post_privateCette publication n’est pas publique.
unsupported_urlCette URL ne correspond pas à une publication TikTok, Instagram ou X.
media_unavailableLa plateforme n’a pas fourni le média.
media_too_largeLa taille dépasse la limite autorisée.
upload_invalidImpossible de lire le fichier envoyé.
provider_errorÉchec du service en amont : vous pouvez réessayer.
internal_errorUne 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 50000

Codes 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_…"
      }
    }
  }
}