API, CLI y MCP
Todo lo que puedes hacer en la app también puedes hacerlo desde tu código y tus agentes: enviar enlaces, archivos o cuentas completas, esperar a que se etiqueten los posts y consultar los resultados. Una misma interfaz con tres formas de acceder. Los trabajos se procesan de forma asíncrona, puedes repetir las solicitudes sin duplicar acciones y ves el costo antes y después.
¿Es tu primera vez en Garfunkel? Así se analiza un post.
Inicio rápido
Crea una clave de API en la app, en Configuración → Desarrolladores, guárdala como GARFUNKEL_API_KEY y elige cómo acceder. Los clientes MCP también pueden iniciar sesión con OAuth en lugar de usar una clave.
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 jsonlAutenticación
Envía Authorization: Bearer gma_live_…: una clave de API asociada a una organización, disponible en Claves de API. La CLI y MCP leen GARFUNKEL_API_KEY. Cada POST acepta Idempotency-Key; si repites una solicitud, recibes la respuesta original y no se te cobra dos veces.
Enviar un trabajo
Al enviar una solicitud, recibes de inmediato el ID del trabajo (202). priority puede ser standard (más económico; tarda de minutos a horas) o fast. Usa dry_run: true para obtener una estimación gratis y validar cada elemento.
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
}'Estados de los elementos: queued → fetching → processing → succeeded | failed | canceled.
Trabajos de cuentas
«Todas las publicaciones de @handle desde 2025-01-01». El conteo cuesta 2 ¢ por cada 20 publicaciones nuevas para tu equipo. El importe se retiene por adelantado y se devuelve a medida que las analizas. Luego, el trabajo queda en espera en awaiting_confirmation, con los datos de cada cuenta: posts_found, oldest_post_at, reached_since y notices (por ejemplo, si la plataforma solo devuelve publicaciones desde una fecha posterior). Confirma con POST /jobs/{id}/confirm o configura options.max_credits para confirmar automáticamente.
{
"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 }
}Archivos
Los archivos se envían directamente al almacenamiento, sin pasar por la API. Los archivos que no se asocien a un trabajo en un plazo de 24 horas se eliminan.
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.Resultados
Un post analizado. Los vectores de representación solo se devuelven si incluyes ?include=embedding. pacing se obtiene mediante la detección de planos (beta).
{
"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": "…"
}Endpoints
| Endpoint | Qué hace |
|---|---|
| POST /api/v1/jobs | Envía URL, archivos o cuentas (dry_run para obtener una estimación gratis). |
| GET /api/v1/jobs/{id} | Estado, recuento por estado, importes (en centavos) reservados, cobrados o liberados, cuentas y avisos. |
| GET /api/v1/jobs/{id}/items | Elementos paginados; filtra con ?status=failed. |
| POST /api/v1/jobs/{id}/confirm | Reserva el importe de un trabajo de cuenta pendiente de confirmación. |
| POST /api/v1/jobs/{id}/cancel | Cancela los elementos en cola; el importe reservado vuelve al saldo. |
| POST /api/v1/jobs/{id}/retry | Vuelve a intentar los elementos fallidos (se vuelve a calcular el importe y se reserva de nuevo). |
| POST /api/v1/uploads | Solicitud PUT prefirmada para tus archivos multimedia. |
| GET /api/v1/results | Filtra por job_id, platform, tag, q. |
| POST /api/v1/results/search | Búsqueda semántica en los vectores de representación. |
| GET /api/v1/results/export | CSV o JSONL en flujo continuo. |
| GET /api/v1/credits | Saldo (centavos + balance_usd), reservado, recargas y recompensas por gasto. |
| DELETE /api/v1/data | Elimina todos los datos de tu organización. |
Errores
Todas las respuestas que no sean 2xx usan el mismo formato. Códigos: 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 } }Los códigos de error por elemento son estables y no generan cargos:
| post_not_found | La publicación ya no existe. |
| post_private | La publicación no es pública. |
| unsupported_url | No es un enlace a una publicación de TikTok, Instagram o X. |
| media_unavailable | La plataforma no proporcionó el contenido multimedia. |
| media_too_large | Supera el límite de tamaño. |
| upload_invalid | No se pudo leer el archivo subido. |
| provider_error | Error del proveedor externo. Se puede reintentar. |
| internal_error | Se produjo un error interno. Se puede reintentar. |
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 50000Códigos de salida: 0 correcto, 2 uso incorrecto, 3 autenticación, 4 saldo insuficiente, 5 finalizado con elementos fallidos, 6 tiempo de espera agotado.
MCP
MCP remoto por HTTP con streaming en /api/mcp, con OAuth (añade la URL en Claude, ChatGPT o Cursor y autoriza el acceso) o una clave de API. Herramientas: 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_…"
}
}
}
}