Pular para o conteúdo

PUT /templates/{templateId}/draft

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

Consultar/salvar rascunho com revisão própria. Contrato v1 · disponível em produção e homologação · operação setTemplatesTemplateIdDraft. Guia funcional · Índice · Schemas · Testar em sandbox.

Permissão: templates:update. 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. O status confirma a persistência descrita, sem prometer propagação global imediata.

Nome Local Obrigatório Tipo e restrições
templateId 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}"$”}

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

Campo Tipo Obrigatório Significado e limites
config TemplateConfig sim Valor tipado; formato e restrições completos no schema abaixo.
config.schemaVersion objeto não Valor tipado; formato e restrições completos no schema abaixo.
config.kind objeto não Valor tipado; formato e restrições completos no schema abaixo.
config.baseTemplateId android / ios / recovery não Valor tipado; formato e restrições completos no schema abaixo.
config.rendererContractVersion objeto não Valor tipado; formato e restrições completos no schema abaixo.
config.appearance object não Valor tipado; formato e restrições completos no schema abaixo.
config.appearance.light object não Valor tipado; formato e restrições completos no schema abaixo.
config.appearance.light.background string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
config.appearance.light.surface string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
config.appearance.light.border string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
config.appearance.light.text string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
config.appearance.light.muted string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
config.appearance.light.accent string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
config.appearance.light.secondary string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
config.appearance.light.tertiary string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
config.appearance.dark object não Valor tipado; formato e restrições completos no schema abaixo.
config.appearance.dark.background string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
config.appearance.dark.surface string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
config.appearance.dark.border string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
config.appearance.dark.text string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
config.appearance.dark.muted string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
config.appearance.dark.accent string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
config.appearance.dark.secondary string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
config.appearance.dark.tertiary string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
config.appearance.fontFamily system / sans / serif não Valor tipado; formato e restrições completos no schema abaixo.
config.appearance.radius small / medium / large não Valor tipado; formato e restrições completos no schema abaixo.
config.appearance.spacing compact / comfortable não Valor tipado; formato e restrições completos no schema abaixo.
config.appearance.logoAssetId string não Valor tipado; formato e restrições completos no schema abaixo. Até 100 caracteres
config.content object não Conteúdo UTF-8 enviado inline; não é URL para busca.
config.content.heading string não Valor tipado; formato e restrições completos no schema abaixo. Até 120 caracteres
config.content.supportingText string não Valor tipado; formato e restrições completos no schema abaixo. Até 1000 caracteres
config.content.actionLabels object não Valor tipado; formato e restrições completos no schema abaixo.
config.content.details array não Valor tipado; formato e restrições completos no schema abaixo. Até 4 itens
config.content.details[].label string sim Valor tipado; formato e restrições completos no schema abaixo. Até 80 caracteres
config.content.details[].value string sim Valor tipado; formato e restrições completos no schema abaixo. Até 1000 caracteres
config.variables array não Valor tipado; formato e restrições completos no schema abaixo. Até 20 itens
config.variables[].key string sim Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
config.variables[].label string não Valor tipado; formato e restrições completos no schema abaixo. Até 80 caracteres
config.variables[].type text / number / boolean não Valor tipado; formato e restrições completos no schema abaixo.
config.variables[].required boolean não Valor tipado; formato e restrições completos no schema abaixo.
config.variables[].maxLength integer não Valor tipado; formato e restrições completos no schema abaixo. Mínimo 1; Máximo 4000
config.variables[].defaultValue string,number,boolean não Valor tipado; formato e restrições completos no schema abaixo.

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.

{
"config": {
"schemaVersion": 1,
"kind": "preset",
"baseTemplateId": "android",
"rendererContractVersion": 1,
"appearance": {
"light": {
"background": "#f8fafc",
"surface": "#ffffff",
"border": "#e2e8f0",
"text": "#0f172a",
"muted": "#64748b",
"accent": "#0284c7",
"secondary": "#059669",
"tertiary": "#f1f5f9"
},
"dark": {
"background": "#0c0d0e",
"surface": "#141517",
"border": "#26272b",
"text": "#f4f4f5",
"muted": "#a1a1aa",
"accent": "#0284c7",
"secondary": "#10b981",
"tertiary": "#1c1d20"
},
"fontFamily": "system",
"radius": "large",
"spacing": "comfortable"
},
"content": {},
"variables": []
}
}
{
"config": {
"schemaVersion": 1,
"kind": "preset",
"baseTemplateId": "android",
"rendererContractVersion": 1,
"appearance": {
"light": {
"background": "#f8fafc",
"surface": "#ffffff",
"border": "#e2e8f0",
"text": "#0f172a",
"muted": "#64748b",
"accent": "#0284c7",
"secondary": "#059669",
"tertiary": "#f1f5f9"
},
"dark": {
"background": "#0c0d0e",
"surface": "#141517",
"border": "#26272b",
"text": "#f4f4f5",
"muted": "#a1a1aa",
"accent": "#0284c7",
"secondary": "#10b981",
"tertiary": "#1c1d20"
},
"fontFamily": "system",
"radius": "large",
"spacing": "comfortable"
},
"content": {},
"variables": []
}
}

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.

Janela do terminal
curl --request PUT 'https://api.staging.agilink.io/v1/templates/90000000-0000-4000-8000-000000000001/draft' \
--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 '{"config":{"schemaVersion":1,"kind":"preset","baseTemplateId":"android","rendererContractVersion":1,"appearance":{"light":{"background":"#f8fafc","surface":"#ffffff","border":"#e2e8f0","text":"#0f172a","muted":"#64748b","accent":"#0284c7","secondary":"#059669","tertiary":"#f1f5f9"},"dark":{"background":"#0c0d0e","surface":"#141517","border":"#26272b","text":"#f4f4f5","muted":"#a1a1aa","accent":"#0284c7","secondary":"#10b981","tertiary":"#1c1d20"},"fontFamily":"system","radius":"large","spacing":"comfortable"},"content":{},"variables":[]}}'
// Node.js 22+. Defina AGILINK_API_KEY no ambiente do servidor.
const response = await fetch('https://api.staging.agilink.io/v1/templates/90000000-0000-4000-8000-000000000001/draft', {
method: 'PUT',
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({
"config": {
"schemaVersion": 1,
"kind": "preset",
"baseTemplateId": "android",
"rendererContractVersion": 1,
"appearance": {
"light": {
"background": "#f8fafc",
"surface": "#ffffff",
"border": "#e2e8f0",
"text": "#0f172a",
"muted": "#64748b",
"accent": "#0284c7",
"secondary": "#059669",
"tertiary": "#f1f5f9"
},
"dark": {
"background": "#0c0d0e",
"surface": "#141517",
"border": "#26272b",
"text": "#f4f4f5",
"muted": "#a1a1aa",
"accent": "#0284c7",
"secondary": "#10b981",
"tertiary": "#1c1d20"
},
"fontFamily": "system",
"radius": "large",
"spacing": "comfortable"
},
"content": {},
"variables": []
}
}),
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 requests
import os
import requests
headers = {
"Authorization": "Bearer " + os.environ["AGILINK_API_KEY"],
"Idempotency-Key": "10000000-0000-4000-8000-000000000001",
"If-Match": "\"20000000-0000-4000-8000-000000000001\""
}
response = requests.request(
'PUT', 'https://api.staging.agilink.io/v1/templates/90000000-0000-4000-8000-000000000001/draft',
headers=headers, json={"config":{"schemaVersion":1,"kind":"preset","baseTemplateId":"android","rendererContractVersion":1,"appearance":{"light":{"background":"#f8fafc","surface":"#ffffff","border":"#e2e8f0","text":"#0f172a","muted":"#64748b","accent":"#0284c7","secondary":"#059669","tertiary":"#f1f5f9"},"dark":{"background":"#0c0d0e","surface":"#141517","border":"#26272b","text":"#f4f4f5","muted":"#a1a1aa","accent":"#0284c7","secondary":"#10b981","tertiary":"#1c1d20"},"fontFamily":"system","radius":"large","spacing":"comfortable"},"content":{},"variables":[]}},
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)

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”
{
"data": {
"templateId": "60000000-0000-4000-8000-000000000001",
"config": {
"schemaVersion": 1,
"kind": "preset",
"baseTemplateId": "android",
"rendererContractVersion": 1,
"appearance": {
"light": {
"background": "#f8fafc",
"surface": "#ffffff",
"border": "#e2e8f0",
"text": "#0f172a",
"muted": "#64748b",
"accent": "#0284c7",
"secondary": "#059669",
"tertiary": "#f1f5f9"
},
"dark": {
"background": "#0c0d0e",
"surface": "#141517",
"border": "#26272b",
"text": "#f4f4f5",
"muted": "#a1a1aa",
"accent": "#0284c7",
"secondary": "#10b981",
"tertiary": "#1c1d20"
},
"fontFamily": "system",
"radius": "large",
"spacing": "comfortable"
},
"content": {},
"variables": []
},
"revision": "20000000-0000-4000-8000-000000000001",
"baseVersion": null,
"updatedAt": "2026-10-19T20:00:00Z"
},
"meta": {
"requestId": "req_00000000000040008000000000000001"
}
}
Campo Tipo Obrigatório Significado e limites
data TemplateDraft sim Resultado tipado da operação.
data.templateId Revision sim Valor tipado; formato e restrições completos no schema abaixo.
data.config TemplateConfig sim Valor tipado; formato e restrições completos no schema abaixo.
data.config.schemaVersion objeto não Valor tipado; formato e restrições completos no schema abaixo.
data.config.kind objeto não Valor tipado; formato e restrições completos no schema abaixo.
data.config.baseTemplateId android / ios / recovery não Valor tipado; formato e restrições completos no schema abaixo.
data.config.rendererContractVersion objeto não Valor tipado; formato e restrições completos no schema abaixo.
data.config.appearance object não Valor tipado; formato e restrições completos no schema abaixo.
data.config.appearance.light object não Valor tipado; formato e restrições completos no schema abaixo.
data.config.appearance.light.background string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
data.config.appearance.light.surface string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
data.config.appearance.light.border string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
data.config.appearance.light.text string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
data.config.appearance.light.muted string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
data.config.appearance.light.accent string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
data.config.appearance.light.secondary string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
data.config.appearance.light.tertiary string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
data.config.appearance.dark object não Valor tipado; formato e restrições completos no schema abaixo.
data.config.appearance.dark.background string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
data.config.appearance.dark.surface string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
data.config.appearance.dark.border string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
data.config.appearance.dark.text string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
data.config.appearance.dark.muted string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
data.config.appearance.dark.accent string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
data.config.appearance.dark.secondary string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
data.config.appearance.dark.tertiary string não Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
data.config.appearance.fontFamily system / sans / serif não Valor tipado; formato e restrições completos no schema abaixo.
data.config.appearance.radius small / medium / large não Valor tipado; formato e restrições completos no schema abaixo.
data.config.appearance.spacing compact / comfortable não Valor tipado; formato e restrições completos no schema abaixo.
data.config.appearance.logoAssetId string não Valor tipado; formato e restrições completos no schema abaixo. Até 100 caracteres
data.config.content object não Conteúdo UTF-8 enviado inline; não é URL para busca.
data.config.content.heading string não Valor tipado; formato e restrições completos no schema abaixo. Até 120 caracteres
data.config.content.supportingText string não Valor tipado; formato e restrições completos no schema abaixo. Até 1000 caracteres
data.config.content.actionLabels object não Valor tipado; formato e restrições completos no schema abaixo.
data.config.content.details array não Valor tipado; formato e restrições completos no schema abaixo. Até 4 itens
data.config.content.details[].label string sim Valor tipado; formato e restrições completos no schema abaixo. Até 80 caracteres
data.config.content.details[].value string sim Valor tipado; formato e restrições completos no schema abaixo. Até 1000 caracteres
data.config.variables array não Valor tipado; formato e restrições completos no schema abaixo. Até 20 itens
data.config.variables[].key string sim Valor tipado; formato e restrições completos no schema abaixo. Formato validado pelo schema
data.config.variables[].label string não Valor tipado; formato e restrições completos no schema abaixo. Até 80 caracteres
data.config.variables[].type text / number / boolean não Valor tipado; formato e restrições completos no schema abaixo.
data.config.variables[].required boolean não Valor tipado; formato e restrições completos no schema abaixo.
data.config.variables[].maxLength integer não Valor tipado; formato e restrições completos no schema abaixo. Mínimo 1; Máximo 4000
data.config.variables[].defaultValue string,number,boolean não Valor tipado; formato e restrições completos no schema abaixo.
data.revision Revision sim Revisão forte para If-Match; muda ao editar.
data.baseVersion integer ou null sim Valor tipado; formato e restrições completos no schema abaixo.
data.updatedAt DateTime sim Instante da última alteração.
meta Meta 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. 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.
{
"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": "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"
}
}
{
"error": {
"code": "revision_conflict",
"message": "Revisão não corresponde à atual.",
"requestId": "req_00000000000040008000000000000001",
"documentationUrl": "https://docs.agilink.io/api/errors/#revision-conflict"
}
}
{
"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": {
"config": {
"$ref": "#/components/schemas/TemplateConfig"
}
},
"required": [
"config"
]
}
Schema de response
{
"type": "object",
"additionalProperties": false,
"properties": {
"data": {
"$ref": "#/components/schemas/TemplateDraft"
},
"meta": {
"$ref": "#/components/schemas/Meta"
}
},
"required": [
"data",
"meta"
]
}

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