POST /domains/{domainId}/dns-records
API · v1 · Produção · Revisado em · Markdown
Criar registro permitido. Contrato v1 · disponível em produção e homologação · operação createDomainsDomainIdDnsRecords. Guia funcional · Índice · Schemas · Testar em sandbox.
Autenticação e efeito
Seção intitulada “Autenticação e efeito”Permissão: dns:create. Sessão humana ou chave de servidor limitada ao proprietário e aos aplicativos autorizados. OAuth/MCP ainda não estão disponíveis. Uma chave de exemplo deve incluir somente esta permissão e as leituras necessárias ao seu fluxo, restrita a app_loja; emita-a na área autenticada de desenvolvedores.
Disponível em produção e homologação; sujeito às capacidades do app e à configuração do provedor. OAuth só será aceito após B1b. 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. 202 aceita trabalho assíncrono; acompanhe Location/estado e respeite Retry-After.
Parâmetros
Seção intitulada “Parâmetros”| Nome | Local | Obrigatório | Tipo e restrições |
|---|---|---|---|
domainId |
path | sim | OpaqueId; {“type”:“string”,“maxLength”:500,“minLength”:1,“pattern”:“^[^/\u0000-\u001f\u007f]+$”} |
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}$”} |
If-Match |
header | sim | ETag forte obtido em consulta. Ausência 428; revisão antiga 412. IfMatch; {“type”:“string”,“maxLength”:38,“pattern”:“^"[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"$”} |
Corpo e semântica
Seção intitulada “Corpo e semântica”Content-Type: application/json. Campos desconhecidos são rejeitados no envelope.
| Campo | Tipo | Obrigatório | Significado e limites |
|---|---|---|---|
type |
A / AAAA / CNAME / TXT / MX | sim | Valor tipado; formato e restrições completos no schema abaixo. |
name |
string | sim | Nome de exibição. Até 253 caracteres |
content |
string | sim | Conteúdo UTF-8 enviado inline; não é URL para busca. Até 2048 caracteres |
ttl |
integer | sim | Valor tipado; formato e restrições completos no schema abaixo. Mínimo 1; Máximo 86400 |
proxied |
boolean | não | Valor tipado; formato e restrições completos no schema abaixo. |
priority |
integer | não | Valor tipado; formato e restrições completos no schema abaixo. Mínimo 0; Máximo 65535 |
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.
Request mínimo
Seção intitulada “Request mínimo”{ "type": "TXT", "name": "_example.go.example.com", "content": "example", "ttl": 300}Request completo de referência
Seção intitulada “Request completo de referência”{ "type": "TXT", "name": "_example.go.example.com", "content": "example", "ttl": 300, "proxied": false}AGILINK_API_KEY deve ficar no servidor. Os placeholders abaixo são fictícios. Preserve Idempotency-Key e payload ao repetir uma intenção após timeout.
curl --request POST 'https://api.staging.agilink.io/v1/domains/domain_example/dns-records' \ --header 'Authorization: Bearer <credencial>' \ --header 'Idempotency-Key: 10000000-0000-4000-8000-000000000001' \ --header 'If-Match: "20000000-0000-4000-8000-000000000001"' \ --header 'Content-Type: application/json' \ --data '{"type":"TXT","name":"_example.go.example.com","content":"example","ttl":300,"proxied":false}'JavaScript / TypeScript
Seção intitulada “JavaScript / TypeScript”// Node.js 22+. Defina AGILINK_API_KEY no ambiente do servidor.const response = await fetch('https://api.staging.agilink.io/v1/domains/domain_example/dns-records', { method: 'POST', headers: { "Authorization": `Bearer ${process.env.AGILINK_API_KEY}`, "Idempotency-Key": "10000000-0000-4000-8000-000000000001", "If-Match": "\"20000000-0000-4000-8000-000000000001\"", "Content-Type": "application/json"}, body: JSON.stringify({ "type": "TXT", "name": "_example.go.example.com", "content": "example", "ttl": 300, "proxied": false}), 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();console.log(result);# Python 3.10+; pip install requestsimport osimport requestsheaders = { "Authorization": "Bearer " + os.environ["AGILINK_API_KEY"], "Idempotency-Key": "10000000-0000-4000-8000-000000000001", "If-Match": "\"20000000-0000-4000-8000-000000000001\""}response = requests.request( 'POST', 'https://api.staging.agilink.io/v1/domains/domain_example/dns-records', headers=headers, json={"type":"TXT","name":"_example.go.example.com","content":"example","ttl":300,"proxied":False}, 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()print(result)Response 202
Seção intitulada “Response 202”Sucesso. 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 |
Operação a acompanhar. | /v1/operations/op_example |
Retry-After |
Segundos até a próxima consulta. | 1 |
{ "data": { "id": "op_example", "appId": "app_loja", "type": "link.resync", "status": "queued", "createdAt": "2026-10-19T20:00:00Z", "updatedAt": "2026-10-19T20:00:00Z", "revision": "20000000-0000-4000-8000-000000000001", "result": null, "error": null }, "meta": { "requestId": "req_00000000000040008000000000000001" }}| Campo | Tipo | Obrigatório | Significado e limites |
|---|---|---|---|
data |
Operation | sim | Resultado tipado da operação. |
data.id |
string | sim | Identificador estável do recurso. Até 500 caracteres; Formato validado pelo schema |
data.appId |
string ou null | sim | Aplicativo proprietário; precisa estar autorizado. |
data.type |
string | sim | Valor tipado; formato e restrições completos no schema abaixo. Até 100 caracteres |
data.status |
queued / running / succeeded / partially_succeeded / failed / cancel_requested / cancelled | sim | Estado atual; consulte as transições no guia do recurso. |
data.createdAt |
string | sim | Instante de criação com fuso. date-time |
data.updatedAt |
string | sim | Instante da última alteração. date-time |
data.revision |
string | sim | Revisão forte para If-Match; muda ao editar. uuid |
data.result |
object,null | sim | Resultado confirmado; null enquanto indisponível. |
data.error |
object ou null | sim | Erro sanitizado, sem credenciais ou corpo privado. |
data.error.code |
invalid_request / validation_failed / unauthenticated / insufficient_permission / not_found / resource_conflict / idempotency_conflict / operation_in_progress / secret_not_replayable / invalid_cursor / revision_conflict / precondition_required / payload_too_large / unsupported_media_type / rate_limited / feature_disabled / resource_expired / dependency_unavailable / internal_error | sim | Valor tipado; formato e restrições completos no schema abaixo. |
data.error.message |
string | sim | Valor tipado; formato e restrições completos no schema abaixo. Até 1000 caracteres |
data.error.details |
array | não | Valor tipado; formato e restrições completos no schema abaixo. Até 50 itens |
data.error.details[].field |
string | não | Valor tipado; formato e restrições completos no schema abaixo. Até 200 caracteres |
data.error.details[].reason |
string | não | Valor tipado; formato e restrições completos no schema abaixo. Até 100 caracteres |
data.error.details[].permission |
string | não | Valor tipado; formato e restrições completos no schema abaixo. Até 100 caracteres |
data.error.requestId |
RequestId | sim | Identificador de correlação gerado pelo servidor. |
data.error.documentationUrl |
string | sim | Valor tipado; formato e restrições completos no schema abaixo. Até 4096 caracteres; uri; Formato validado pelo schema |
data.error.resource |
object | não | Valor tipado; formato e restrições completos no schema abaixo. |
data.error.resource.type |
string | sim | Valor tipado; formato e restrições completos no schema abaixo. Até 100 caracteres |
data.error.resource.id |
string | sim | Identificador estável do recurso. Até 500 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. |
Falhas, revisão e repetição
Seção intitulada “Falhas, revisão e repetição”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. If-Match forte é obrigatório; ausência 428, revisão antiga 412. Reconsulte e reconcilie antes de tentar nova edição. 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. |
| 412 | Revisão não corresponde à atual. |
| 413 | Corpo excede o limite. |
| 415 | Content-Type incompatível. |
| 422 | JSON bem formado com dados de domínio inválidos. |
| 428 | If-Match obrigatório ausente. |
| 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. |
Exemplo 401
Seção intitulada “Exemplo 401”{ "error": { "code": "unauthenticated", "message": "Credencial inválida, expirada ou revogada.", "requestId": "req_00000000000040008000000000000001", "documentationUrl": "https://docs.agilink.io/api/errors/#unauthenticated" }}Exemplo 403
Seção intitulada “Exemplo 403”{ "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" }}Exemplo 409
Seção intitulada “Exemplo 409”{ "error": { "code": "idempotency_conflict", "message": "Conflito de identidade/idempotência; operação em andamento ou segredo já exibido.", "requestId": "req_00000000000040008000000000000001", "documentationUrl": "https://docs.agilink.io/api/errors/#idempotency-conflict" }}Exemplo 412
Seção intitulada “Exemplo 412”{ "error": { "code": "revision_conflict", "message": "Revisão não corresponde à atual.", "requestId": "req_00000000000040008000000000000001", "documentationUrl": "https://docs.agilink.io/api/errors/#revision-conflict" }}Exemplo 429
Seção intitulada “Exemplo 429”{ "error": { "code": "rate_limited", "message": "Quota excedida. Respeitar Retry-After.", "requestId": "req_00000000000040008000000000000001", "documentationUrl": "https://docs.agilink.io/api/errors/#rate-limited" }}Schema completo e próximos passos
Seção intitulada “Schema completo e próximos passos”Schema de request
{ "type": "object", "additionalProperties": false, "properties": { "type": { "enum": [ "A", "AAAA", "CNAME", "TXT", "MX" ] }, "name": { "type": "string", "maxLength": 253 }, "content": { "type": "string", "maxLength": 2048 }, "ttl": { "type": "integer", "minimum": 1, "maximum": 86400 }, "proxied": { "type": "boolean" }, "priority": { "type": "integer", "minimum": 0, "maximum": 65535 } }, "required": [ "type", "name", "content", "ttl" ]}Schema de response
{ "type": "object", "additionalProperties": false, "properties": { "data": { "$ref": "#/components/schemas/Operation" }, "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.