Pular para a documentação
DocumentaçãoAPI REST

API REST

Gerencie agentes, chaves, acessos e o registro a partir de um script com uma chave de console.

Nesta página

Endereço e chave

Scripts chamam https://mcp.sallyport.cloud/v1 com uma chave de console. Um proprietário cria uma em Configurações, Chaves de API com Nova chave de API. Ela começa com sp_ck_ e aparece uma única vez.

Envie como Authorization: Bearer $SP_CONSOLE_KEY. A chave age como proprietário da organização inteira. Ela para de funcionar quando é revogada, ou quando o proprietário que a criou deixa de ser proprietário.

Algumas ações precisam de uma pessoa conectada e respondem 403 a uma chave de console. São elas criar chaves de console, responder aprovações, o login OAuth, as configurações de notificação, marcar sinais e baixar respostas guardadas.

Tokens de agente (sp_live_…, sp_test_…) são para /mcp e /p/. Em /v1 eles abrem uma rota só: GET /v1/bodies/{body_ref} para as chamadas do próprio agente.

Shell · a organização e seus espaços de trabalho
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

Respostas e erros

Um sucesso é {"data": …, "request_id": "…"} com 200, ou 201 quando algo foi criado. Corpos de requisição são JSON de até 1 MiB. Um campo que a rota não conhece é ignorado, exceto campos de regra aposentados como class_policy em /bindings, que recebem 422.

Um erro tem o mesmo formato em todas as rotas. message é uma frase curta em inglês; details traz o que um programa precisa.

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"
  }
}
Status e códigoO que significa
401 AUTH_FAILEDA chave está ausente, errada ou revogada.
403 FORBIDDENSeu papel não basta. details.required_role diz qual basta.
404 NOT_FOUND, 404 CALL_NOT_FOUNDNada com esse ID na sua organização, ou o ID não é um UUID.
409 CONFLICT, 409 CALL_CONFLICTO objeto está ocupado, mudou ou já está nesse estado. details diz qual.
410 APPROVAL_EXPIREDO cartão de aprovação fechou antes da resposta.
422 VALIDATION_FAILEDUm campo está errado. details.fields lista cada um com field, code e message.
400 BAD_REQUESTUm parâmetro de consulta que a rota não aceita. details.accepted lista os que ela aceita.
503 UNAVAILABLE, 500 INTERNALUma falha do lado do Sallyport. Repita um 503 após details.retry_after_ms.

Listas

A maioria das listas devolve todas as linhas de uma vez: data é {"items": […], "total": n, "page": 1, "limit": n}.

Chamadas, aprovações e eventos de auditoria vêm em páginas de {"items", "next_cursor", "total", "truncated"}. limit é 50 por padrão e no máximo 200. Devolva next_cursor como cursor até ele ser null.

Um filtro com vários valores os recebe separados por vírgula, como em state=completed,failed. A maioria das rotas de lista recusa um parâmetro que não conhece, então um filtro digitado errado nunca devolve tudo.

Dê a um script o próprio agente

POST /agents recebe name e workspace_id. environment é live (padrão) ou test; description, delegate_user_id e allowed_ips são opcionais. Pegue workspace_id de GET /workspaces.

Um agente novo recebe na hora todas as conexões ativas do seu espaço de trabalho e ambiente, todas rodando sem perguntar. Depois emita um token para ele. O exemplo usa jq para ler o ID do agente novo.

Shell · um agente e seu 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"

O token está em data.token, e esta resposta é o único lugar onde ele aparece. Começa com sp_live_ para um agente live e sp_test_ para um de teste.

label aceita até 100 caracteres, e expires_at é um horário RFC 3339 opcional no futuro. DELETE /agents/{id}/tokens/{token_id} revoga um token.

Adicione uma chave

POST /credentials guarda uma chave e cria as conexões dela no mesmo passo. Todos os agentes do mesmo espaço de trabalho e ambiente as recebem na hora.

Shell · uma chave do 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 nomeia o serviço, e GET /recipes lista todos. fields leva o segredo com os nomes de credential_fields da receita; a maioria dos serviços tem um campo só, value. environment é live por padrão.

A resposta descreve a chave sem o segredo. data.used_by.bindings lista as conexões novas: um id dali é o {binding_id} do proxy HTTP.

Nenhuma rota jamais devolve um segredo. Para trocá-lo, envie um objeto fields novo para POST /credentials/{id}/rotate.

Mude como um agente usa uma conexão

Cada par de agente e conexão tem uma regra. class_policy associa read, write e destructive a auto, ask ou deny, e um par novo começa com os três em auto.

Shell · perguntar a uma pessoa em toda chamada
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 substitui a regra inteira. Uma classe que você omite vira ask, e um step_up, path_prefix_override, methods_override ou rate_per_hour omitido é apagado. Envie os que você quer manter.

Campos opcionais: step_up (none, ou totp para um código do autenticador ao aprovar uma chamada destrutiva), path_prefix_override, methods_override e rate_per_hour. Os três últimos só podem estreitar a conexão.

DELETE /agents/{id}/bindings/{binding_id} tira uma conexão do agente. POST /agents/{id}/bindings devolve conexões: binding_ids ou "all": true, com um rule opcional no mesmo formato.

Leia as chamadas e o registro

GET /calls percorre as chamadas em páginas, as mais novas primeiro. Filtros: workspace_id, agent_id, binding_id, state, class, decision, channel, host, q, session, from e to.

Uma chamada traz call_id, agent, binding, class, decision (run, ask ou deny), state, summary, upstream_status, duration_ms, contagens de bytes, error_code e body_ref.

Estados: admitted, awaiting_approval, dispatching, executing, completed, denied, failed, outcome_unknown e cancelled. GET /calls/{call_id} acrescenta a intenção, a linha do tempo e os números de sequência da chamada no registro.

GET /audit/events percorre o registro em páginas, o mais novo primeiro. GET /audit/export baixa a cadeia como linhas JSON: um cabeçalho e depois um evento por linha. from_seq e to_seq limitam um intervalo.

Limite um agente a endereços conhecidos

allowed_ips em POST /agents e PATCH /agents/{id} aceita até 100 endereços IP ou faixas CIDR. Uma lista vazia permite qualquer endereço, e um PATCH sem o campo mantém a lista atual.

Shell · permitir um endereço
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 é o endereço de onde saem as requisições do agente. GET /me/ip, rodado nessa máquina, mostra o endereço que o Sallyport vê.

Uma requisição de qualquer outro endereço recebe 403 SOURCE_IP_NOT_ALLOWED em /mcp, /p/ e /v1/bodies. Chamadas já em andamento não são interrompidas.

Apps conectados

GET /oauth/consents lista os clientes de IA que entraram com OAuth, uma linha por pessoa, cliente e agente. Um membro recebe as próprias linhas; um proprietário, um administrador ou uma chave de console recebe as de todos.

Cada linha traz id, client_id, client_name, registration (cimd para um cliente identificado pelo próprio site, dcr para um que se registrou sozinho), verified, domain, publisher, redirect (kind: web, app ou loopback, e host), agent (id, name), workspace_id, connected_by (id, name, email), connected_at, renewed_at, last_used_at e mine.

DELETE /oauth/consents/{id} desconecta a conexão inteira. As chamadas dela param na hora, em todos os computadores de onde o cliente entrou, e o cliente precisa entrar de novo para voltar.

A tela de consentimento lê GET /oauth/consent?request=…, só para uma pessoa conectada. Além do client ID e do endereço de retorno, ela traz client.verified, client.domain, client.publisher, redirect (kind, host) e workspaces. Cada espaço de trabalho tem access: grants (existing, all ou none) e as connections que o agente vai usar, cada uma com id, name, channel e asks_first.

Uma linha também traz sub_agents: os agentes que o cliente criou para as suas máquinas, cada um com id, name e box, a máquina para a qual existe. Em GET /agents, esse agente tem created_by_client com client_id, client_name e box. Ele só tem parent_agent_id sob uma conexão que é ela mesma um agente, feita com scope=mcp agents. Os demais agentes têm null nos dois. Uma linha com manages_agents: true é a conexão de uma plataforma: ela gerencia agentes e não é um agente.

Tokens para as máquinas de uma plataforma

Uma plataforma que roda agentes em máquinas próprias entra uma vez com scope=agents. Esse consentimento é um acesso para gerenciar agentes, não um agente: a pessoa vê um cartão curto sem lista de serviços. Com o access token da conexão, ela cria um agente para cada máquina em POST https://mcp.sallyport.cloud/v1/agents. O agente começa sem acesso: uma pessoa escolhe o que ele pode usar na página dele no console.

Shell · um agente para uma 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"}'

A resposta traz agent_id e access_url, a página de acesso do agente. Acrescente &return_to= com a sua própria página, e a pessoa volta com um botão. Uma máquina tem um agente: um segundo POST responde 409 com box_has_agent. GET /v1/agents lista os agentes da pessoa com created_by_client, box e paused. PATCH e DELETE /v1/agents/{id} renomeiam, pausam ou excluem só os agentes que este cliente criou. Nenhuma chamada desta API dá ou tira acesso. Envie allowed_ips no POST ou no PATCH, e os tokens do agente funcionam só a partir desses endereços: um token copiado da máquina não vale nada em outro lugar. A lista que a pessoa define no console vale por cima.

Para o token de uma máquina, a plataforma troca o access token da conexão em POST https://mcp.sallyport.cloud/token (RFC 8693) e nomeia o agente em sallyport_agent. O token vale uma hora.

Shell · um token para uma 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"

A resposta traz access_token, expires_in, sallyport_agent_id, sallyport_agent_name e sallyport_agent_url. Não há refresh token: a plataforma troca de novo. Uma recusa traz sallyport_reason: subject_token_expired, consent_ended, agents_scope_missing, agent_not_bound, agent_deleted ou agent_paused.

POST https://mcp.sallyport.cloud/revoke (RFC 7009) recebe token e client_id. O token de uma máquina encerra todos os tokens dessa máquina. O refresh token encerra a conexão inteira, como “Desconectar”.

GET https://mcp.sallyport.cloud/v1/access com Authorization: Bearer responde pelo agente desse token, o de uma máquina: services, o número de conexões que ele pode usar, access_url, a página de acesso dele, e connections, as mesmas entradas de list_access. Enquanto não tiver serviços, message diz isso em uma linha. Um token que não serve recebe 401 com WWW-Authenticate: Bearer e error="invalid_token". O token próprio da conexão recebe services: 0 e uma linha dizendo que ela não usa nenhum serviço. Em /mcp e /p/ ele recebe 403 com error="insufficient_scope" e scope="mcp".

Servidores MCP prontos

GET /v1/mcp-servers lista os servidores MCP remotos que o console oferece ao adicionar um. São os servidores hospedados pelos próprios fornecedores, cada um com seu endereço e sua forma de entrar. Qualquer membro pode ler. Escolher um só preenche o formulário, e o que você salva é uma conexão MCP remota comum, veja Clientes MCP e servidores remotos.

JSON · GET /v1/mcp-servers, um item mostrado
{
  "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_partO endereço do servidor. Quando url_part não é null, o endereço traz {name}. Essa parte é de cada cliente: label a pede em seis idiomas, example mostra uma.
authoauth entra no fornecedor, bearer aceita um token criado lá, api_key envia uma chave no cabeçalho api_key_header depois de api_key_prefix, none não precisa de nada.
dynamic_registrationNo caminho OAuth o fornecedor registra o Sallyport sozinho. false significa que você informa um ID de cliente criado no fornecedor.
bearer_alternative, key_urlO servidor OAuth também aceita um token criado no fornecedor, e a página onde você cria esse token ou chave.
recipeO serviço do catálogo do mesmo fornecedor, ou null.
description, docs_urlO que o servidor faz, uma frase em cada um dos seis idiomas, e a página do fornecedor sobre o servidor.

Todas as rotas

Os caminhos ficam sob https://mcp.sallyport.cloud/v1. Membro significa qualquer papel na organização. Uma chave de console conta como proprietário.

RotasQuemPara quê
GET /tenants/me, PATCH /tenants/memembro, proprietárioA organização: nome, configurações, contadores.
POST /tenants/me/pause, POST /tenants/me/resumeproprietárioParar e retomar todas as chamadas de agentes. A pausa leva reason.
GET /me/ipqualquer umO endereço que o Sallyport vê para quem chama.
GET, POST /workspaces; GET, PATCH /workspaces/{id}membro, administradorEspaços de trabalho. Crie um com slug, name e kind (team ou client).
GET /workspaces/{id}/report?period=YYYY-MMauditorUm mês de um espaço de trabalho: totais, serviços, chamadas destrutivas.
GET, POST /agents; GET, PATCH, DELETE /agents/{id}membro, administradorAgentes. Excluir responde 409 enquanto uma chamada do agente está em andamento.
POST /agents/{id}/pause, POST /agents/{id}/resumeadministradorParar um agente e retomá-lo. A pausa leva 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}membro, administradorAs conexões que um agente usa e a regra dele em cada uma.
GET, PUT /agents/{id}/limitsmembro, administradorconcurrency_limit, rate_per_hour e read_budget.multiplier.
GET, POST /credentials; GET, PATCH, DELETE /credentials/{id}administradorChaves. Excluir uma chave exclui as conexões dela.
POST /credentials/{id}/rotate, PATCH /credentials/{id}/origin, GET /credentials/{id}/usage, POST /credentials/{id}/oauth/startadministradorTrocar o segredo, registrar se o original está revogado no fornecedor, ver quem usa a chave. oauth/start começa o login no fornecedor e exige uma pessoa conectada ao console.
GET, POST /bindings; GET, PATCH, DELETE /bindings/{id}membro, administradorConexões. PATCH compara If-Match com config_version quando você o envia.
POST /bindings/{id}/pause, /resume, /check-key, /oauth/startadministradorParar uma conexão, retomá-la, verificar a chave de novo. oauth/start faz login em um servidor MCP remoto e exige uma pessoa conectada ao console.
GET, POST /ssh-hosts; GET, PATCH, DELETE /ssh-hosts/{id}administradorServidores para comandos SSH.
POST /database-connections/testadministradorTestar o endereço e a senha de um banco de dados antes de salvar.
POST /email-connections/testadministradorTestar uma caixa de correio e a senha antes de salvar.
GET /policies/rule-changes, POST /policies/rule-changes/{id}/revertmembro, administradorO histórico de mudanças de regras, e desfazer uma.
GET /recipes, GET /recipes/{key}membroO catálogo de serviços, veja Receitas.
GET /mcp-serversmembroServidores MCP remotos prontos para uma nova conexão.
GET, POST /grants; POST /grants/{id}/revokemembro, administradorPermissões com prazo de um agente sobre uma conexão. Um aprovador também pode revogá-las.
GET /approvals, GET /approvals/{call_id}, GET /approvals/{call_id}/payloadaprovadorCartões de aprovação e a requisição exata por trás de cada um. Um auditor pode ler a lista.
POST /approvals/{call_id}/open, /decide, /transferaprovadorEstender um cartão, respondê-lo, passá-lo a outro aprovador. Responder exige uma pessoa conectada.
GET /access-requests, GET /access-requests/{request_id}membroPedidos que os agentes fizeram por um serviço que não conseguiram usar.
POST /access-requests/{request_id}/provision, /declineadministradorResponder a um pedido com uma chave, ou recusá-lo com reason.
GET /calls, GET /calls/live, GET /calls/{call_id}auditorHistórico de chamadas, chamadas em andamento, uma chamada.
POST /calls/{call_id}/canceladministradorParar uma chamada que não terminou.
GET /bodies/{body_ref}/meta, GET /bodies/{body_ref}auditor; o download também o agenteTamanho e validade de uma resposta guardada, e a própria resposta. O download aceita Range.
GET /audit/events, GET /audit/exportauditorO registro, em páginas ou como um arquivo de linhas JSON. Só com um papel na organização inteira, não em um espaço de trabalho.
GET /signals, POST /signals/{id}/ackmembro, administradorAtividade incomum, e marcá-la como vista.
GET /reports, GET /reports/{id}, GET /insightsmembroRelatórios semanais e estatísticas de aprovações.
GET /billing, POST /billing/planadministrador, proprietárioPlano e uso, e pedir outro plano.
GET, POST /webhooks; PATCH, DELETE /webhooks/{id}administradorEventos do registro enviados ao seu endereço HTTPS. O segredo de assinatura aparece uma vez.
GET /webhooks/{id}/deliveries, POST /webhooks/{id}/deliveries/{delivery_id}/retryadministradorHistórico de entregas, e reenviar uma que falhou.
GET /members, PATCH /members/{user_id}membro, administradorPessoas e seus papéis.
GET, POST /members/invitations; DELETE /members/invitations/{id}administradorConvites por e-mail.
GET /members/{user_id}/offboarding, POST /members/{user_id}/offboardadministradorPassar adiante o que uma pessoa que sai tinha.
GET, POST /guests; POST /guests/{id}/relink; DELETE /guests/{id}administradorAprovadores do cliente que entram por um link de e-mail.
GET /onboarding, POST /onboarding/steps/{key}membroA lista de primeiros passos.
GET, POST /console-keys; DELETE /console-keys/{id}proprietárioChaves de console. Criar uma exige um proprietário conectado.
GET /oauth/consents, DELETE /oauth/consents/{id}membro, administradorApps conectados, e desconectar um. Um membro cuida dos seus, um administrador dos de todos.
/notifications/…, /oauth/consent, /guest/step-uppessoaTelas do console para uma pessoa conectada.