Inicio rápido

Emite un token pck_… en Configuración → Claves de API, luego configura TOKEN=pck_… y ejecuta cualquiera de los ejemplos a continuación. Reemplaza la URL de producción por http://localhost:3000 para desarrollo local.

# List recent runs (scope: runs:read)
curl -s https://www.margintide.com/api/v1/runs \
  -H "Authorization: Bearer $TOKEN"

# Trigger a run (scope: runs:trigger)
curl -s -X POST https://www.margintide.com/api/v1/runs \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"subset_tags": ["core-skus"]}'

# List recommendations (scope: recommendations:read)
curl -s "https://www.margintide.com/api/v1/recommendations?status=new" \
  -H "Authorization: Bearer $TOKEN"

# Accept a recommendation (scope: recommendations:write)
curl -s -X POST https://www.margintide.com/api/v1/recommendations/$REC_ID/accept \
  -H "Authorization: Bearer $TOKEN"

# Approve a pending_approval recommendation - triggers Shopify write-back
# (scope: recommendations:approve - Max / Enterprise plan required)
curl -s -X POST https://www.margintide.com/api/v1/recommendations/$REC_ID/approve \
  -H "Authorization: Bearer $TOKEN"

# Reject a pending_approval recommendation with a reason
# (scope: recommendations:approve)
curl -s -X POST https://www.margintide.com/api/v1/recommendations/$REC_ID/reject \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"reason": "price too aggressive for Q3 margin target"}'

# Snooze an alert (scope: alerts:write)
curl -s -X POST https://www.margintide.com/api/v1/alerts/$ALERT_ID/snooze \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"snooze_until": "2026-07-01T00:00:00Z", "reason": "supplier renegotiation"}'

# List catalog items (scope: catalog:read)
curl -s https://www.margintide.com/api/v1/catalog/items \
  -H "Authorization: Bearer $TOKEN"

# Export report data (scope: reports:read)
curl -s https://www.margintide.com/api/v1/reports/export \
  -H "Authorization: Bearer $TOKEN"

Autenticación y espacios de trabajo

Dos credenciales admitidas: Authorization: Bearer pck_… (un token de API — principal; funciona con cada ruta /api/v1/*), o un JWT de sesión de Supabase (solo apps propias — aprobar/rechazar desde el móvil, estado del espacio de trabajo). Los llamados con sesión que pertenecen a más de un espacio de trabajo deben enviar x-workspace-id; omitirlo devuelve 403 workspace_forbidden.

Un token de API pertenece exactamente a un espacio de trabajo, para siempre. Un llamador con N espacios de trabajo crea N tokens (uno por espacio de trabajo) para alcanzarlos todos — no existe un token entre espacios de trabajo.

Límites de solicitudes

Por defecto 60 solicitudes/minuto, presupuestadas de forma independiente por token pck_, por usuario de sesión y por concesión de OAuth. El presupuesto de un token pck_ se comparte entre esta API REST y el servidor MCP — las mismas solicitudes cuentan para ambos. Superar el presupuesto devuelve 429 rate_limited con un encabezado Retry-After (segundos hasta que se reinicie la ventana). No existe la familia de encabezados X-RateLimit-*.

Versionado y obsolescencia

Dentro de /api/v1 solo se envían cambios aditivos: nuevos puntos de conexión, nuevos campos de solicitud opcionales, nuevos campos de respuesta, nuevos valores de enumeración. Los clientes deben ignorar los campos y valores de enumeración desconocidos. Los cambios incompatibles se envían bajo un nuevo prefijo de ruta (/api/v2), nunca como una mutación de v1. Una operación v1 obsoleta se marca como deprecated: true en la especificación OpenAPI, se enumera aquí, y se notifica por correo a los propietarios/administradores del espacio de trabajo — la operación sigue funcionando durante al menos 6 meses después de ese aviso antes de eliminarse.

Operaciones obsoletas: ninguna.

Campos de confianza del estado del espacio de trabajo

GET /api/v1/workspace/status (alcance: workspace:read) también devuelve dos proyecciones de transparencia de solo lectura junto con lifecycle y usage — ambas son claves de respuesta obligatorias que son null cuando el estado subyacente está ausente, nunca se omiten.

support_access es no nulo solo mientras una sesión de soporte de la plataforma está activamente abierta contra el propio espacio de trabajo del llamador — la vista de transparencia del propietario sobre el flujo de acceso de soporte con consentimiento. Solo contiene active, admin_email, started_at y expires_at — nunca un id de sesión, código de consentimiento, token cifrado, ni datos de ningún otro espacio de trabajo.

account_deletion es no nulo solo mientras el usuario que llama tiene una solicitud de eliminación de cuenta activa (pendiente o bloqueada), limitada estrictamente a ese llamador. Contiene scheduled y effective_at — la fecha antes de la cual no se realizará la purga — para que un cliente pueda mostrar un aviso de eliminación pendiente sin una segunda solicitud.

¿Prefieres el acceso por MCP? La guía del servidor MCP explica cómo conectar Claude Desktop o un cliente MCP personalizado directamente - sin curl ni panel. Requiere un plan Max o Enterprise.

Hoja de referencia de errores

Reenviar un accept / dismiss / snooze / resolve / approve que ya surtió efecto devuelve 200 { "ok": true, "idempotent": true } - seguro para reintentar ante fallas de red. El endpoint de aprobación usa CAS (comparar e intercambiar) para escrituras exactamente una vez en tiendas Shopify.

EstadocódigoSignificado
400bad_requestEl cuerpo de la solicitud no pudo analizarse como JSON
401unauthorizedToken faltante / desconocido / revocado / vencido
403insufficient_scopeEl token no tiene el alcance requerido (el campo required lo indica)
403forbidden_roleSolo aprobar / rechazar: el rol del llamador en el espacio de trabajo está por debajo de approver|admin|owner
403token_unusableSolo rutas de mutación: el usuario que emitió este token fue eliminado - emite un token nuevo
403workspace_forbiddenLlamador con JWT de sesión sin acceso al espacio de trabajo resuelto - falta o es incorrecto x-workspace-id
402plan_limit / email_not_confirmed / budget codesEl límite del plan o la restricción de facturación rechazó la acción
422tier_ineligibleSolo aprobar: la escritura de comercio requiere plan Max o Enterprise - actualiza en Configuración → Facturación
422no_commerce_integrationSolo aprobar: no hay integración de Shopify conectada para este espacio de trabajo - conecta una en Configuración → Integraciones
404not_foundNo existe tal recurso en tu espacio de trabajo
409conflictTransición de estado no permitida desde el estado actual
422validation_errorEl cuerpo o parámetro de consulta no pasó la validación del esquema Zod (issues enumera los campos)
429rate_limitedLímite de solicitudes superado - por token (pck_) o por usuario (sesión) - respete Retry-After