Pular para o conteúdo

POST /api-keys

API · v1 · Produção · Revisado em · Markdown

Emitir credencial limitada. Contrato v1 · disponível em produção e homologação · operação createApiKeys. Guia funcional · Índice · Schemas · Testar em sandbox.

Permissão: api_keys:create. Exige sessão humana verificada; API keys não são aceitas. OAuth/MCP ainda não estão disponíveis. Use o access token da sessão humana do proprietário, obtido pelo login do ambiente e mantido somente no processo seguro; a chave de API não substitui essa sessão.

Disponível em produção e homologação; sujeito às capacidades do app e à configuração do provedor. Exige sessão humana verificada. Segredo somente na resposta inicial. Repetição do recibo confirmado retorna 409 secret_not_replayable e metadados sem novo segredo. Campos desconhecidos rejeitados. Consulte os ADRs para regras semânticas além do JSON Schema.

O efeito é autenticado, auditado e pode gerar publicação eventual e eventos do recurso. Links/domínios/templates podem precisar de propagação antes de aparecerem publicamente. Não muda identidade de link implicitamente. Dependências e capabilities podem bloquear a ação. O status confirma a persistência descrita, sem prometer propagação global imediata.

Nome Local Obrigatório Tipo e restrições
Idempotency-Key header sim UUID v4 por intenção. Recibo por 24h. Mudança de payload/precondição retorna 409. Segredo de chave não é reexibido. IdempotencyKey; {“type”:“string”,“maxLength”:36,“pattern”:“^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$”}

Content-Type: application/json. Campos desconhecidos são rejeitados no envelope.

Campo Tipo Obrigatório Significado e limites
name string sim Nome de exibição. Até 100 caracteres
appIds array sim Aplicativos permitidos à credencial. Até 100 itens
permissions array sim Permissões explícitas, sem wildcard. Até 100 itens
expiresAt string não Fim de validade; não amplia concessões. date-time

Omitir campos opcionais usa o default documentado ou preserva o valor em PATCH. null só é aceito nos campos cujo schema permite null, com efeito de limpar/desvincular indicado no guia. Arrays enviados substituem a coleção quando o endpoint define atualização completa; não implicam merge. Identificadores/owner/app de um recurso existente não são transferidos por PATCH. Herança de templates/UTMs segue o guia, sem alterar links anteriores por cópia automática.

{
"name": "Backend da loja",
"appIds": [
"app_loja"
],
"permissions": [
"apps:read",
"links:read",
"links:create"
]
}
{
"name": "Backend da loja",
"appIds": [
"app_loja"
],
"permissions": [
"apps:read",
"links:read",
"links:create"
]
}

AGILINK_HUMAN_SESSION deve ficar no servidor. Os placeholders abaixo são fictícios. Preserve Idempotency-Key e payload ao repetir uma intenção após timeout.

Janela do terminal
curl --request POST 'https://api.staging.agilink.io/v1/api-keys' \
--header 'Authorization: Bearer <credencial>' \
--header 'Idempotency-Key: 10000000-0000-4000-8000-000000000001' \
--header 'Content-Type: application/json' \
--data '{"name":"Backend da loja","appIds":["app_loja"],"permissions":["apps:read","links:read","links:create"]}'
// Node.js 22+. Defina AGILINK_HUMAN_SESSION no ambiente do servidor.
const response = await fetch('https://api.staging.agilink.io/v1/api-keys', {
method: 'POST',
headers: {
"Authorization": `Bearer ${process.env.AGILINK_HUMAN_SESSION}`,
"Idempotency-Key": "10000000-0000-4000-8000-000000000001",
"Content-Type": "application/json"
},
body: JSON.stringify({
"name": "Backend da loja",
"appIds": [
"app_loja"
],
"permissions": [
"apps:read",
"links:read",
"links:create"
]
}),
redirect: 'error', signal: AbortSignal.timeout(30000)
});
if (!response.ok) throw new Error('HTTP '+response.status+' requestId='+response.headers.get('X-Request-Id'));
const result = await response.json();
// Guarde result.data.secret no gerenciador de segredos; não registre em logs.
# Python 3.10+; pip install requests
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["AGILINK_HUMAN_SESSION"],
"Idempotency-Key": "10000000-0000-4000-8000-000000000001"
}
response = requests.request(
'POST', 'https://api.staging.agilink.io/v1/api-keys',
headers=headers, json={"name":"Backend da loja","appIds":["app_loja"],"permissions":["apps:read","links:read","links:create"]},
timeout=30, allow_redirects=False)
if not 200 <= response.status_code < 300:
raise RuntimeError(f'HTTP {response.status_code}; requestId={response.headers.get("X-Request-Id")}')
result = response.json()
# Guarde result["data"]["secret"] com segurança; não registre em logs.

Criado. Exemplo fictício.

Header Significado Exemplo
X-Request-Id Identificador gerado pelo servidor, inclusive para falhas e replays. conforme resposta
Cache-Control Respostas administrativas não podem ser armazenadas. no-store, no-transform
ETag Revisão forte, a enviar em If-Match na alteração. “20000000-0000-4000-8000-000000000001”
Location Endereço relativo do recurso criado. /v1/api-keys/30000000-0000-4000-8000-000000000001
{
"data": {
"key": {
"id": "30000000-0000-4000-8000-000000000001",
"name": "Backend da loja",
"prefix": "agl_test_AbCdEf",
"appIds": [
"app_loja"
],
"permissions": [
"apps:read",
"links:read",
"links:create"
],
"expiresAt": "2027-01-17T20:00:00Z",
"createdAt": "2026-10-19T20:00:00Z",
"lastUsedAt": null,
"revokedAt": null,
"revision": "20000000-0000-4000-8000-000000000001"
},
"secret": "agl_test_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
},
"meta": {
"requestId": "req_00000000000040008000000000000001"
}
}
Campo Tipo Obrigatório Significado e limites
data object sim Resultado tipado da operação.
data.key object sim Valor tipado; formato e restrições completos no schema abaixo.
data.key.id string sim Identificador estável do recurso. uuid
data.key.name string sim Nome de exibição. Até 100 caracteres
data.key.prefix string sim Prefixo de caminho, sem barras. Até 30 caracteres; Formato validado pelo schema
data.key.appIds array sim Aplicativos permitidos à credencial. Até 100 itens
data.key.permissions array sim Permissões explícitas, sem wildcard. Até 100 itens
data.key.expiresAt string sim Fim de validade; não amplia concessões. date-time
data.key.createdAt string sim Instante de criação com fuso. date-time
data.key.lastUsedAt string ou null sim Valor tipado; formato e restrições completos no schema abaixo.
data.key.revokedAt string ou null sim Valor tipado; formato e restrições completos no schema abaixo.
data.key.revision string sim Revisão forte para If-Match; muda ao editar. uuid
data.secret string sim Exibido apenas na emissão; armazene no servidor. Até 52 caracteres; Formato validado pelo schema
meta object sim Correlação e informações da resposta.
meta.requestId RequestId sim Identificador de correlação gerado pelo servidor.

Idempotency-Key UUID v4 é obrigatório, por intenção e credencial, por 24 horas. Em resultado incerto, repita exatamente o mesmo método, URL, corpo, revisão e chave. Alterar a intenção exige nova chave. Segredos de emissão não são reexibidos. Esta operação não exige If-Match. Não faça retry automático ilimitado.

Status Significado
400 Cabeçalho, query, cursor ou JSON inválido.
401 Credencial inválida, expirada ou revogada.
403 Operação sem permissão ou capacidade desabilitada.
404 Recurso inexistente ou fora dos aplicativos autorizados.
409 Conflito de identidade/idempotência; operação em andamento ou segredo já exibido.
413 Corpo excede o limite.
415 Content-Type incompatível.
422 JSON bem formado com dados de domínio inválidos.
429 Quota excedida. Respeitar Retry-After.
500 Falha interna. Use requestId para diagnóstico.
503 Dependência indisponível; resultado da mutação pode ser incerto.
{
"error": {
"code": "unauthenticated",
"message": "Credencial inválida, expirada ou revogada.",
"requestId": "req_00000000000040008000000000000001",
"documentationUrl": "https://docs.agilink.io/api/errors/#unauthenticated"
}
}
{
"error": {
"code": "insufficient_permission",
"message": "Operação sem permissão ou capacidade desabilitada.",
"requestId": "req_00000000000040008000000000000001",
"documentationUrl": "https://docs.agilink.io/api/errors/#insufficient-permission"
}
}
{
"error": {
"code": "secret_not_replayable",
"message": "A chave já foi emitida. O segredo não pode ser reexibido.",
"requestId": "req_00000000000040008000000000000001",
"documentationUrl": "https://docs.agilink.io/api/errors/#secret-not-replayable",
"resource": {
"type": "api_key",
"id": "30000000-0000-4000-8000-000000000001"
}
}
}
{
"error": {
"code": "rate_limited",
"message": "Quota excedida. Respeitar Retry-After.",
"requestId": "req_00000000000040008000000000000001",
"documentationUrl": "https://docs.agilink.io/api/errors/#rate-limited"
}
}
Schema de request
{
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
"type": "string",
"maxLength": 100,
"minLength": 1
},
"appIds": {
"type": "array",
"items": {
"type": "string",
"maxLength": 500,
"minLength": 1,
"pattern": "^[^/\\u0000-\\u001f\\u007f]+$"
},
"maxItems": 100,
"minItems": 1,
"uniqueItems": true
},
"permissions": {
"type": "array",
"items": {
"enum": [
"analytics:read",
"apps:delete",
"apps:read",
"apps:update",
"assets:create",
"assets:delete",
"assets:read",
"batches:create",
"batches:read",
"campaigns:create",
"campaigns:delete",
"campaigns:read",
"campaigns:update",
"capabilities:read",
"dns:create",
"dns:delete",
"dns:read",
"dns:update",
"domains:create",
"domains:delete",
"domains:read",
"domains:verify",
"exports:create",
"exports:read",
"folders:create",
"folders:delete",
"folders:read",
"folders:update",
"identity:read",
"imports:commit",
"imports:create",
"imports:read",
"imports:validate",
"link_history:read",
"links:create",
"links:delete",
"links:preview",
"links:read",
"links:resync",
"links:update",
"links:validate",
"native_config:read",
"native_config:update",
"operations:cancel",
"operations:read",
"qr_codes:create",
"qr_codes:delete",
"qr_codes:read",
"qr_codes:update",
"recovery_config:read",
"recovery_config:update",
"routing_rules:read",
"routing_rules:update",
"tags:create",
"tags:delete",
"tags:read",
"tags:update",
"template_bindings:read",
"template_bindings:update",
"templates:create",
"templates:preview",
"templates:publish",
"templates:read",
"templates:retry",
"templates:snapshot",
"templates:update",
"templates:validate",
"usage:read",
"web_config:read",
"web_config:update",
"webhooks:create",
"webhooks:delete",
"webhooks:read",
"webhooks:retry",
"webhooks:rotate_secret",
"webhooks:test",
"webhooks:update"
]
},
"maxItems": 100,
"minItems": 1,
"uniqueItems": true
},
"expiresAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"name",
"appIds",
"permissions"
]
}
Schema de response
{
"type": "object",
"additionalProperties": false,
"properties": {
"data": {
"type": "object",
"additionalProperties": false,
"properties": {
"key": {
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"name": {
"type": "string",
"maxLength": 100,
"minLength": 1
},
"prefix": {
"type": "string",
"maxLength": 30,
"pattern": "^agl_(live|test)_[A-Za-z0-9_-]{4,12}$"
},
"appIds": {
"type": "array",
"items": {
"type": "string",
"maxLength": 500,
"minLength": 1,
"pattern": "^[^/\\u0000-\\u001f\\u007f]+$"
},
"maxItems": 100,
"minItems": 1,
"uniqueItems": true
},
"permissions": {
"type": "array",
"items": {
"enum": [
"analytics:read",
"apps:delete",
"apps:read",
"apps:update",
"assets:create",
"assets:delete",
"assets:read",
"batches:create",
"batches:read",
"campaigns:create",
"campaigns:delete",
"campaigns:read",
"campaigns:update",
"capabilities:read",
"dns:create",
"dns:delete",
"dns:read",
"dns:update",
"domains:create",
"domains:delete",
"domains:read",
"domains:verify",
"exports:create",
"exports:read",
"folders:create",
"folders:delete",
"folders:read",
"folders:update",
"identity:read",
"imports:commit",
"imports:create",
"imports:read",
"imports:validate",
"link_history:read",
"links:create",
"links:delete",
"links:preview",
"links:read",
"links:resync",
"links:update",
"links:validate",
"native_config:read",
"native_config:update",
"operations:cancel",
"operations:read",
"qr_codes:create",
"qr_codes:delete",
"qr_codes:read",
"qr_codes:update",
"recovery_config:read",
"recovery_config:update",
"routing_rules:read",
"routing_rules:update",
"tags:create",
"tags:delete",
"tags:read",
"tags:update",
"template_bindings:read",
"template_bindings:update",
"templates:create",
"templates:preview",
"templates:publish",
"templates:read",
"templates:retry",
"templates:snapshot",
"templates:update",
"templates:validate",
"usage:read",
"web_config:read",
"web_config:update",
"webhooks:create",
"webhooks:delete",
"webhooks:read",
"webhooks:retry",
"webhooks:rotate_secret",
"webhooks:test",
"webhooks:update"
]
},
"maxItems": 100,
"minItems": 1,
"uniqueItems": true
},
"expiresAt": {
"type": "string",
"format": "date-time"
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"lastUsedAt": {
"anyOf": [
{
"type": "string",
"format": "date-time"
},
{
"type": "null"
}
]
},
"revokedAt": {
"anyOf": [
{
"type": "string",
"format": "date-time"
},
{
"type": "null"
}
]
},
"revision": {
"type": "string",
"format": "uuid"
}
},
"required": [
"id",
"name",
"prefix",
"appIds",
"permissions",
"expiresAt",
"createdAt",
"lastUsedAt",
"revokedAt",
"revision"
]
},
"secret": {
"type": "string",
"maxLength": 52,
"pattern": "^agl_(live|test)_[A-Za-z0-9_-]{43}$"
}
},
"required": [
"key",
"secret"
]
},
"meta": {
"type": "object",
"additionalProperties": false,
"properties": {
"requestId": {
"$ref": "#/components/schemas/RequestId"
}
},
"required": [
"requestId"
]
}
},
"required": [
"data",
"meta"
]
}

Convenções e limites · Erros · Receitas completas · Guia funcional.