Ir a la documentación
DocumentaciónAPI REST

API REST

Gestiona agentes, claves, accesos y el registro desde un script con una clave de consola.

En esta página

Dirección y clave

Los scripts llaman a https://mcp.sallyport.cloud/v1 con una clave de consola. Un propietario la crea en Configuración, Claves API con Nueva clave API. Empieza por sp_ck_ y se muestra una sola vez.

Envíala como Authorization: Bearer $SP_CONSOLE_KEY. La clave actúa como propietario de toda la organización. Deja de funcionar cuando se revoca o cuando el propietario que la creó deja de serlo.

Algunas acciones necesitan una persona con sesión iniciada y responden 403 a una clave de consola. Son crear claves de consola, responder aprobaciones, el inicio de sesión OAuth, los ajustes de notificaciones, marcar señales y descargar respuestas guardadas.

Los tokens de agente (sp_live_…, sp_test_…) son para /mcp y /p/. En /v1 abren una sola ruta: GET /v1/bodies/{body_ref} para las llamadas del propio agente.

Shell · la organización y sus espacios de trabajo
export SP_CONSOLE_KEY='sp_ck_…'

curl --fail-with-body \
  --header "Authorization: Bearer $SP_CONSOLE_KEY" \
  https://mcp.sallyport.cloud/v1/tenants/me

curl --fail-with-body \
  --header "Authorization: Bearer $SP_CONSOLE_KEY" \
  https://mcp.sallyport.cloud/v1/workspaces

Respuestas y errores

Un éxito es {"data": …, "request_id": "…"} con 200, o 201 cuando se creó algo. Los cuerpos de solicitud son JSON de hasta 1 MiB. Un campo que la ruta no conoce se ignora, salvo campos de regla retirados como class_policy en /bindings, que reciben 422.

Un error tiene la misma forma en todas las rutas. message es una frase corta en inglés; details lleva lo que necesita un programa.

JSON · 422 de POST /v1/agents
{
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "Validation failed",
    "details": {
      "fields": [
        { "field": "workspace_id", "code": "not_a_uuid", "message": "Select a workspace" }
      ]
    },
    "request_id": "9e8df29b6763e0ddd8138df2790de68a"
  }
}
Estado y códigoQué significa
401 AUTH_FAILEDLa clave falta, es incorrecta o está revocada.
403 FORBIDDENTu rol no basta. details.required_role nombra el rol que sí basta.
404 NOT_FOUND, 404 CALL_NOT_FOUNDNo hay nada con ese ID en tu organización, o el ID no es un UUID.
409 CONFLICT, 409 CALL_CONFLICTEl objeto está ocupado, cambió o ya está en ese estado. details dice cuál.
410 APPROVAL_EXPIREDLa tarjeta de aprobación se cerró antes de la respuesta.
422 VALIDATION_FAILEDUn campo está mal. details.fields enumera cada uno con field, code y message.
400 BAD_REQUESTUn parámetro de consulta que la ruta no admite. details.accepted enumera los que sí.
503 UNAVAILABLE, 500 INTERNALUn fallo del lado de Sallyport. Repite un 503 tras details.retry_after_ms.

Listas

La mayoría de las listas devuelve todas las filas de una vez: data es {"items": […], "total": n, "page": 1, "limit": n}.

Las llamadas, las aprobaciones y los eventos de auditoría llegan en páginas de {"items", "next_cursor", "total", "truncated"}. limit es 50 por defecto y 200 como máximo. Devuelve next_cursor como cursor hasta que sea null.

Un filtro con varios valores los recibe separados por comas, como en state=completed,failed. La mayoría de las rutas de lista rechaza un parámetro que no conoce, así que un filtro mal escrito nunca devuelve todo.

Da a un script su propio agente

POST /agents recibe name y workspace_id. environment es live (por defecto) o test; description, delegate_user_id y allowed_ips son opcionales. Toma workspace_id de GET /workspaces.

Un agente nuevo recibe enseguida todas las conexiones activas de su espacio y entorno, y todas funcionan sin preguntar. Después emítele un token. El ejemplo usa jq para leer el ID del agente nuevo.

Shell · un agente y su token
export SP_WORKSPACE_ID='…'

AGENT_ID=$(curl --fail-with-body --silent \
  --request POST \
  --header "Authorization: Bearer $SP_CONSOLE_KEY" \
  --header "Content-Type: application/json" \
  --data "{\"name\":\"Nightly report\",\"workspace_id\":\"$SP_WORKSPACE_ID\"}" \
  https://mcp.sallyport.cloud/v1/agents | jq -r .data.id)

curl --fail-with-body \
  --request POST \
  --header "Authorization: Bearer $SP_CONSOLE_KEY" \
  --header "Content-Type: application/json" \
  --data '{"label":"CI"}' \
  "https://mcp.sallyport.cloud/v1/agents/$AGENT_ID/tokens"

El token está en data.token, y esta respuesta es el único lugar donde aparece. Empieza por sp_live_ para un agente live y por sp_test_ para uno de prueba.

label admite hasta 100 caracteres, y expires_at es una hora RFC 3339 opcional en el futuro. DELETE /agents/{id}/tokens/{token_id} revoca un token.

Añade una clave

POST /credentials guarda una clave y crea sus conexiones en el mismo paso. Todos los agentes del mismo espacio y entorno las reciben enseguida.

Shell · una clave de GitHub
export GITHUB_TOKEN='…'

curl --fail-with-body \
  --request POST \
  --header "Authorization: Bearer $SP_CONSOLE_KEY" \
  --header "Content-Type: application/json" \
  --data "{\"name\":\"GitHub\",\"workspace_id\":\"$SP_WORKSPACE_ID\",\"recipe_key\":\"github\",\"fields\":{\"value\":\"$GITHUB_TOKEN\"}}" \
  https://mcp.sallyport.cloud/v1/credentials

recipe_key nombra el servicio, y GET /recipes los enumera. fields lleva el secreto con los nombres de credential_fields de la receta; la mayoría de los servicios tiene un solo campo, value. environment es live por defecto.

La respuesta describe la clave sin su secreto. data.used_by.bindings enumera las conexiones nuevas: un id de ahí es el {binding_id} del proxy HTTP.

Ninguna ruta devuelve jamás un secreto. Para sustituirlo, envía un objeto fields nuevo a POST /credentials/{id}/rotate.

Cambia cómo usa un agente una conexión

Cada par de agente y conexión tiene una regla. class_policy asigna a read, write y destructive uno de auto, ask o deny, y un par nuevo empieza con los tres en auto.

Shell · preguntar a una persona en cada llamada
export SP_BINDING_ID='…'

curl --fail-with-body \
  --request PUT \
  --header "Authorization: Bearer $SP_CONSOLE_KEY" \
  --header "Content-Type: application/json" \
  --data '{"class_policy":{"read":"ask","write":"ask","destructive":"ask"}}' \
  "https://mcp.sallyport.cloud/v1/agents/$AGENT_ID/bindings/$SP_BINDING_ID"

PUT sustituye la regla entera. Una clase que omites pasa a ask, y un step_up, path_prefix_override, methods_override o rate_per_hour omitido se borra. Envía los que quieras conservar.

Campos opcionales: step_up (none, o totp para un código del autenticador al aprobar una llamada destructiva), path_prefix_override, methods_override y rate_per_hour. Los tres últimos solo pueden estrechar la conexión.

DELETE /agents/{id}/bindings/{binding_id} quita una conexión al agente. POST /agents/{id}/bindings devuelve conexiones: binding_ids o "all": true, con un rule opcional de la misma forma.

Lee las llamadas y el registro

GET /calls recorre las llamadas por páginas, las más nuevas primero. Filtros: workspace_id, agent_id, binding_id, state, class, decision, channel, host, q, session, from y to.

Una llamada lleva call_id, agent, binding, class, decision (run, ask o deny), state, summary, upstream_status, duration_ms, conteos de bytes, error_code y body_ref.

Estados: admitted, awaiting_approval, dispatching, executing, completed, denied, failed, outcome_unknown y cancelled. GET /calls/{call_id} añade la intención, la cronología y los números de secuencia de la llamada en el registro.

GET /audit/events recorre el registro por páginas, lo más nuevo primero. GET /audit/export descarga la cadena como líneas JSON: una cabecera y luego un evento por línea. from_seq y to_seq acotan un rango.

Limita un agente a direcciones conocidas

allowed_ips en POST /agents y PATCH /agents/{id} admite hasta 100 direcciones IP o rangos CIDR. Una lista vacía permite cualquier dirección, y un PATCH sin el campo conserva la lista actual.

Shell · permitir una dirección
export SP_AGENT_IP='…'

curl --fail-with-body \
  --request PATCH \
  --header "Authorization: Bearer $SP_CONSOLE_KEY" \
  --header "Content-Type: application/json" \
  --data "{\"allowed_ips\":[\"$SP_AGENT_IP\"]}" \
  "https://mcp.sallyport.cloud/v1/agents/$AGENT_ID"

SP_AGENT_IP es la dirección de la que salen las solicitudes del agente. GET /me/ip, ejecutado en esa máquina, muestra la dirección que ve Sallyport.

Una solicitud desde cualquier otra dirección recibe 403 SOURCE_IP_NOT_ALLOWED en /mcp, /p/ y /v1/bodies. Las llamadas que ya están en curso no se detienen.

Apps conectadas

GET /oauth/consents devuelve los clientes de IA que iniciaron sesión con OAuth, una fila por persona, cliente y agente. Un miembro recibe sus filas; un propietario, un administrador o una clave de consola reciben las de todos.

Cada fila lleva id, client_id, client_name, registration (cimd para un cliente identificado por su sitio web, dcr para uno que se registró por su cuenta), verified, domain, publisher, redirect (kind: web, app o loopback, y host), agent (id, name), workspace_id, connected_by (id, name, email), connected_at, renewed_at, last_used_at y mine.

DELETE /oauth/consents/{id} desconecta la conexión entera. Sus llamadas se detienen al instante en todos los ordenadores desde los que el cliente inició sesión, y el cliente vuelve iniciando sesión de nuevo.

La pantalla de consentimiento lee GET /oauth/consent?request=…, solo para una persona con sesión iniciada. Además del client ID y la dirección de redirección, trae client.verified, client.domain, client.publisher, redirect (kind, host) y workspaces. Cada espacio de trabajo tiene access: grants (existing, all o none) y las connections que usará el agente, cada una con id, name, channel y asks_first.

Una fila también trae sub_agents: los agentes que el cliente creó para sus máquinas, cada uno con id, name y box, la máquina para la que existe. En GET /agents ese agente tiene created_by_client con client_id, client_name y box. Tiene parent_agent_id solo bajo una conexión que es en sí un agente, hecha con scope=mcp agents. Los demás agentes tienen null en ambos. Una fila con manages_agents: true es la conexión de una plataforma: gestiona agentes y no es un agente.

Tokens para las máquinas de una plataforma

Una plataforma que ejecuta agentes en máquinas propias inicia sesión una vez con scope=agents. Ese consentimiento es un acceso para gestionar agentes, no un agente: la persona ve una tarjeta corta sin lista de servicios. Con el access token de la conexión crea un agente para cada máquina en POST https://mcp.sallyport.cloud/v1/agents. El agente empieza sin acceso: una persona elige qué puede usar en su página de la consola.

Shell · un agente para una máquina
curl -sS https://mcp.sallyport.cloud/v1/agents \
  -H "Authorization: Bearer $SP_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "api-worker", "box": "5f0c2d1e-9a4b-4c1e-8f3a-2b7d9e6c1a40"}'

La respuesta trae agent_id y access_url, la página de acceso del agente. Añada &return_to= con su propia página, y la persona vuelve con un botón. Una máquina tiene un agente: un segundo POST responde 409 con box_has_agent. GET /v1/agents lista los agentes de la persona con created_by_client, box y paused. PATCH y DELETE /v1/agents/{id} renombran, pausan o eliminan solo los agentes que creó este cliente. Ninguna llamada de esta API da ni quita acceso. Envíe allowed_ips en POST o PATCH, y los tokens del agente funcionan solo desde esas direcciones: un token copiado fuera de la máquina no sirve en ningún otro sitio. La lista que la persona fije en la consola se aplica encima.

Para el token de una máquina, la plataforma cambia el access token de la conexión en POST https://mcp.sallyport.cloud/token (RFC 8693) y nombra el agente en sallyport_agent. El token dura una hora.

Shell · un token para una máquina
curl -sS https://mcp.sallyport.cloud/token \
  -d grant_type=urn:ietf:params:oauth:grant-type:token-exchange \
  -d client_id=https://detachbox.com/.well-known/sallyport-client.json \
  -d subject_token="$SP_ACCESS_TOKEN" \
  -d subject_token_type=urn:ietf:params:oauth:token-type:access_token \
  -d sallyport_agent="$AGENT_ID"

La respuesta trae access_token, expires_in, sallyport_agent_id, sallyport_agent_name y sallyport_agent_url. No hay refresh token: la plataforma intercambia de nuevo. Un rechazo trae sallyport_reason: subject_token_expired, consent_ended, agents_scope_missing, agent_not_bound, agent_deleted o agent_paused.

POST https://mcp.sallyport.cloud/revoke (RFC 7009) recibe token y client_id. El token de una máquina termina todos los tokens de esa máquina. El refresh token termina la conexión entera, como «Desconectar».

GET https://mcp.sallyport.cloud/v1/access con Authorization: Bearer responde por el agente de ese token, el de una máquina: services, el número de conexiones que puede usar, access_url, su página de acceso, y connections, las mismas entradas que list_access. Mientras no tenga servicios, message lo dice en una línea. Un token que no sirve recibe 401 con WWW-Authenticate: Bearer y error="invalid_token". El token propio de la conexión recibe services: 0 y una línea que dice que no usa ningún servicio. En /mcp y /p/ recibe 403 con error="insufficient_scope" y scope="mcp".

Servidores MCP listos

GET /v1/mcp-servers enumera los servidores MCP remotos que la consola ofrece al añadir uno. Son los servidores alojados por los propios proveedores, cada uno con su dirección y su forma de iniciar sesión. Cualquier miembro puede leerlo. Elegir uno solo rellena el formulario, y lo que guardas es una conexión MCP remota normal, ver Clientes MCP y servidores remotos.

JSON · GET /v1/mcp-servers, se muestra un elemento
{
  "data": {
    "items": [
      {
        "key": "datadog-site",
        "name": "Datadog (other sites)",
        "vendor": "Datadog",
        "url": "https://mcp.{site}/v1/mcp",
        "url_part": {
          "name": "site",
          "label": { "en": "Your Datadog site domain, for example datadoghq.eu or us5.datadoghq.com", "ru": "…", "es": "…", "pt": "…", "fr": "…", "de": "…" },
          "example": "datadoghq.eu"
        },
        "auth": "oauth",
        "dynamic_registration": true,
        "bearer_alternative": false,
        "api_key_header": null,
        "api_key_prefix": null,
        "key_url": null,
        "recipe": "datadog",
        "docs_url": "https://docs.datadoghq.com/mcp_server/setup/",
        "description": { "en": "Query logs, metrics, traces, monitors and incidents on your Datadog site.", "ru": "…", "es": "…", "pt": "…", "fr": "…", "de": "…" }
      }
    ],
    "total": 1,
    "page": 1,
    "limit": 1
  },
  "request_id": "5d0c2f7e8a1b4c6d9e0f1a2b3c4d5e6f"
}
CampoSignificado
url, url_partLa dirección del servidor. Si url_part no es null, la dirección lleva {name}. Esa parte es propia de cada cliente: label la pide en seis idiomas, example muestra una.
authoauth inicia sesión en el proveedor, bearer acepta un token creado allí, api_key envía una clave en la cabecera api_key_header tras api_key_prefix, none no necesita nada.
dynamic_registrationPor la vía OAuth el proveedor registra Sallyport por sí mismo. false significa que introduces un ID de cliente creado en el proveedor.
bearer_alternative, key_urlEl servidor OAuth también acepta un token creado en el proveedor, y la página donde creas ese token o clave.
recipeEl servicio del catálogo del mismo proveedor, o null.
description, docs_urlLo que hace el servidor, una frase en cada uno de los seis idiomas, y la página del proveedor sobre el servidor.

Todas las rutas

Las rutas cuelgan de https://mcp.sallyport.cloud/v1. Miembro significa cualquier rol en la organización. Una clave de consola cuenta como propietario.

RutasQuiénPara qué
GET /tenants/me, PATCH /tenants/memiembro, propietarioLa organización: nombre, ajustes, contadores.
POST /tenants/me/pause, POST /tenants/me/resumepropietarioDetener y reanudar todas las llamadas de agentes. La pausa lleva reason.
GET /me/ipcualquieraLa dirección que Sallyport ve para quien llama.
GET, POST /workspaces; GET, PATCH /workspaces/{id}miembro, administradorEspacios de trabajo. Se crean con slug, name y kind (team o client).
GET /workspaces/{id}/report?period=YYYY-MMauditorUn mes de un espacio: totales, servicios, llamadas destructivas.
GET, POST /agents; GET, PATCH, DELETE /agents/{id}miembro, administradorAgentes. Borrar responde 409 mientras una llamada del agente está en curso.
POST /agents/{id}/pause, POST /agents/{id}/resumeadministradorDetener un agente y reanudarlo. La pausa lleva reason.
GET, POST /agents/{id}/tokens; DELETE /agents/{id}/tokens/{token_id}administradorTokens de agente.
GET, POST /agents/{id}/bindings; PUT, DELETE /agents/{id}/bindings/{binding_id}miembro, administradorLas conexiones que usa un agente y su regla en cada una.
GET, PUT /agents/{id}/limitsmiembro, administradorconcurrency_limit, rate_per_hour y read_budget.multiplier.
GET, POST /credentials; GET, PATCH, DELETE /credentials/{id}administradorClaves. Borrar una clave borra sus conexiones.
POST /credentials/{id}/rotate, PATCH /credentials/{id}/origin, GET /credentials/{id}/usage, POST /credentials/{id}/oauth/startadministradorSustituir el secreto, anotar si el original está revocado en el proveedor, ver quién usa la clave. oauth/start inicia el inicio de sesión en el proveedor y necesita una persona con sesión iniciada.
GET, POST /bindings; GET, PATCH, DELETE /bindings/{id}miembro, administradorConexiones. PATCH compara If-Match con config_version cuando lo envías.
POST /bindings/{id}/pause, /resume, /check-key, /oauth/startadministradorDetener una conexión, reanudarla, volver a comprobar su clave. oauth/start inicia sesión en un servidor MCP remoto y necesita una persona con sesión iniciada.
GET, POST /ssh-hosts; GET, PATCH, DELETE /ssh-hosts/{id}administradorServidores para comandos SSH.
POST /database-connections/testadministradorProbar la dirección y la contraseña de una base de datos antes de guardarlas.
POST /email-connections/testadministradorProbar un buzón y su contraseña antes de guardarlos.
GET /policies/rule-changes, POST /policies/rule-changes/{id}/revertmiembro, administradorEl historial de cambios de reglas, y deshacer uno.
GET /recipes, GET /recipes/{key}miembroEl catálogo de servicios, ver Recetas.
GET /mcp-serversmiembroServidores MCP remotos listos para una conexión nueva.
GET, POST /grants; POST /grants/{id}/revokemiembro, administradorPermisos con plazo de un agente sobre una conexión. Un aprobador también puede revocarlos.
GET /approvals, GET /approvals/{call_id}, GET /approvals/{call_id}/payloadaprobadorTarjetas de aprobación y la solicitud exacta detrás de cada una. Un auditor puede leer la lista.
POST /approvals/{call_id}/open, /decide, /transferaprobadorProlongar una tarjeta, responderla, pasarla a otro aprobador. Responder exige una persona con sesión iniciada.
GET /access-requests, GET /access-requests/{request_id}miembroSolicitudes que hicieron los agentes por un servicio que no pudieron usar.
POST /access-requests/{request_id}/provision, /declineadministradorResponder a una solicitud con una clave, o rechazarla con reason.
GET /calls, GET /calls/live, GET /calls/{call_id}auditorHistorial de llamadas, llamadas en curso, una llamada.
POST /calls/{call_id}/canceladministradorDetener una llamada que no ha terminado.
GET /bodies/{body_ref}/meta, GET /bodies/{body_ref}auditor; la descarga también el agenteTamaño y caducidad de una respuesta guardada, y la respuesta misma. La descarga admite Range.
GET /audit/events, GET /audit/exportauditorEl registro, por páginas o como un archivo de líneas JSON. Solo con un rol en toda la organización, no en un espacio de trabajo.
GET /signals, POST /signals/{id}/ackmiembro, administradorActividad inusual, y marcarla como vista.
GET /reports, GET /reports/{id}, GET /insightsmiembroInformes semanales y estadísticas de aprobaciones.
GET /billing, POST /billing/planadministrador, propietarioPlan y uso, y pedir otro plan.
GET, POST /webhooks; PATCH, DELETE /webhooks/{id}administradorEventos del registro enviados a tu dirección HTTPS. El secreto de firma se muestra una vez.
GET /webhooks/{id}/deliveries, POST /webhooks/{id}/deliveries/{delivery_id}/retryadministradorHistorial de entregas, y reenviar una fallida.
GET /members, PATCH /members/{user_id}miembro, administradorPersonas y sus roles.
GET, POST /members/invitations; DELETE /members/invitations/{id}administradorInvitaciones por correo.
GET /members/{user_id}/offboarding, POST /members/{user_id}/offboardadministradorTraspasar lo que tenía una persona que se va.
GET, POST /guests; POST /guests/{id}/relink; DELETE /guests/{id}administradorAprobadores del cliente que entran con un enlace por correo.
GET /onboarding, POST /onboarding/steps/{key}miembroLa lista de primeros pasos.
GET, POST /console-keys; DELETE /console-keys/{id}propietarioClaves de consola. Crear una exige un propietario con sesión iniciada.
GET /oauth/consents, DELETE /oauth/consents/{id}miembro, administradorApps conectadas, y desconectar una. Un miembro gestiona las suyas, un administrador las de todos.
/notifications/…, /oauth/consent, /guest/step-uppersonaPantallas de la consola para una persona con sesión iniciada.