Webhook
O Webhook é uma configuração que executa automaticamente uma ação previamente definida quando algo acontece no Space (por exemplo, criação ou publicação de Content). A ação é uma de duas: enviar uma requisição HTTP para uma URL externa (url) ou executar um Script dentro do Space (script). É usado para integração com sistemas externos ou automação. Por exemplo, você pode configurá-lo para chamar um servidor de notificações interno sempre que um Content de produto for publicado, ou para executar um trabalho subsequente com um Script previamente definido.
Você especifica exatamente um entre url e script. Especificar ambos, ou deixar ambos vazios, é rejeitado. O Webhook é um recurso subordinado ao Space na CMA, e seu caminho tem como base /spaces/{spaceId}/webhooks.
Estrutura do recurso
A seguir está a resposta da consulta individual do Webhook "Notificação de alteração de produto". Junto com sys (atributos de sistema), ele tem campos de configuração como destino de envio, eventos assinados e condições de disparo.
{
"sys": {
"id": "3trmXRM3RqbgSnifyg7PWhk01Examp",
"type": "Webhook",
"space": { "sys": { "id": "HnQ32YiH", "type": "Refer", "targetType": "Space" } },
"createdBy": { "sys": { "id": "3p4tcFbQRwz503VXdtHXNI5dZH5TVB", "type": "Refer", "targetType": "User" } },
"createdAt": "2026-06-18T11:30:00.000Z",
"updatedBy": { "sys": { "id": "3p4tcFbQRwz503VXdtHXNI5dZH5TVB", "type": "Refer", "targetType": "User" } },
"updatedAt": "2026-06-18T11:30:00.000Z",
"version": 1
},
"name": "Notificação de alteração de produto",
"filters": [
{ "doc": "sys.contentType.sys.id", "op": "EQ", "value": "3trmXRLdJF4GBlAjtcuoZ7Pnxj8dlA" }
],
"headers": [
{ "key": "X-Source", "value": "weegloo", "secret": false }
],
"httpBasicUsername": "dailywear",
"topics": ["Content.Create", "Content.Publish"],
"transformation": { "method": "POST", "contentType": "application/json", "includeBody": true },
"url": "https://api.dailywear.example/webhooks/products",
"activate": true,
"runAs": "HookOwner"
}Principais chaves:
sys.id: identificador único do Webhook. Entra no{webhookId}dos caminhos de consulta individual, modificação e exclusão.url: URL de destino externa a ser chamada quando o evento ocorrer. Especifique exatamente um entre ele escript.script: referência ao Script a executar no lugar de uma chamada externa. Especifique exatamente um entre ele eurl. Não está presente no exemplo acima. É explicado abaixo em url e script (apenas um).runAs: identidade de usuário com a qual oscripté executado. É explicado abaixo em runAs.topics: array que define quais eventos serão assinados. O formato é explicado abaixo em topics.filters: condições que efetivamente disparam, dentre os eventos assinados. É explicado abaixo em filters.transformation: configuração que altera o formato da requisição de saída (método, corpo etc.). É explicado abaixo em transformation.
Atributos de sistema (sys)
Todo Webhook armazena os atributos de sistema comuns no objeto sys. space, createdBy e updatedBy entram no formato Refer ({ "sys": { "id", "type": "Refer", "targetType" } }).
| Atributo | Tipo | Descrição |
|---|---|---|
id | string | Identificador único do recurso. |
type | string | Tipo do recurso. Para Webhook é sempre "Webhook". |
space | Refer<Space> | O Space ao qual este Webhook pertence. |
createdBy | Refer<User> | Usuário que criou. |
createdAt | string (date-time) | Momento da criação. |
updatedBy | Refer<User> | Último usuário que modificou. |
updatedAt | string (date-time) | Momento da última modificação. |
version | integer (≥1) | Versão do recurso. Aumenta em 1 a cada modificação. |
O Webhook é um recurso de configuração, portanto não tem o conceito de publicação. Diferentemente de Content ou Content Type, ele não possui atributos de estado de publicação como publish, archive ou status, apenas o version para rastreamento de alterações. Ligar e desligar não é controlado por publicação, mas pelo campo de corpo activate.
Atributos do corpo
O corpo do Webhook (os valores de configuração enviados na criação e modificação e retornados na resposta) é composto pelos seguintes campos.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
name | string (1~64) | ✅ | Nome do Webhook. |
url | string (url) | △ | URL de destino externa a ser chamada quando o evento ocorrer. Apenas um entre este e script. Consulte url e script (apenas um) abaixo. |
script | Refer<Script> | △ | Referência ao Script a executar no lugar de uma chamada externa. Apenas um entre este e url. Consulte url e script (apenas um) abaixo. |
runAs | WebhookRunAs | Identidade de usuário com a qual o script é executado. HookOwner (padrão) ou EventUser. Consulte runAs abaixo. | |
activate | boolean | ✅ | Se está ativado. Se false, nada é executado mesmo quando o evento ocorre. |
topics | string[] | ✅ | Array de eventos a assinar. Consulte topics abaixo. |
filters | Filter[] | ✅ | Array de condições de disparo. Se vazio, todos os eventos assinados disparam. Consulte filters abaixo. |
headers | WebhookHeader[] (0~30) | ✅ | Array de cabeçalhos HTTP a enviar na chamada de url. |
httpBasicUsername | string (1~32) | Nome de usuário da autenticação HTTP Basic da chamada de url. | |
httpBasicPassword | string (1~32) | Senha da autenticação HTTP Basic da chamada de url. É somente de escrita. Não aparece na resposta. | |
transformation | Transformation | ✅ | Personalização da requisição que sai para url. Consulte transformation abaixo. |
Você especifica exatamente um entre url e script marcados com △. Especificar ambos, ou deixar ambos vazios, é rejeitado.
Cada item de headers é composto por key (obrigatório), value (obrigatório) e secret (opcional, boolean). Se você deixar secret como true, esse valor fica ocultado no registro de envio (consulte WebhookLog abaixo). No entanto, ao consultar este Webhook, o valor aparece em texto original. O único que fica de fora da resposta é o httpBasicPassword, portanto considere que o valor colocado em um cabeçalho secret é visível para qualquer papel que possa ler este Webhook e mantenha esse papel restrito.
topics
Cada item de topics tem o formato {recurso}.{ação}. Por exemplo: Content.Create, Content.Publish, Media.Create.
A ação é uma das seguintes ou *, que significa todas as ações do recurso (por exemplo, Content.*).
| Ação | Significado |
|---|---|
All | Todas as ações. |
Create | Criação. |
Read | Consulta. |
Edit | Edição. |
Save | Salvar (modificação). O evento de modificação é Save. Não é Update. |
Delete | Exclusão. |
Publish | Publicação. |
Unpublish | Cancelamento de publicação. |
Archive | Arquivamento. |
Unarchive | Desarquivamento. |
filters
filters é um array que restringe, dentre os topics assinados, as condições que efetivamente disparam o Webhook. Cada filtro tem o seguinte formato.
{ "doc": "sys.contentType.sys.id", "op": "EQ", "value": "3trmXRLdJF4GBlAjtcuoZ7Pnxj8dlA" }doc: caminho do campo a comparar. É um dentresys.id,sys.contentType.sys.id,sys.createdBy.sys.idesys.updatedBy.sys.id.op: operador de comparação. É um dentreEQ,NE,IN,NOT_IN,REGEXeNOT_REGEX.value: valor de comparação. ParaEQ,NE,REGEXeNOT_REGEXinforme uma string; paraINeNOT_INinforme um array de strings.
Quando há vários filtros, todos precisam ser satisfeitos para disparar (AND). Se filters estiver vazio, todos os eventos dos topics assinados disparam.
transformation
transformation altera o formato da requisição HTTP que sai para url (não se aplica a um Webhook que usa script). Se não for especificado, todo o payload do recurso sai como está, com o POST padrão.
| Chave | Tipo | Descrição |
|---|---|---|
method | string | Método HTTP. Um dentre GET, POST, PUT, DELETE e PATCH. |
contentType | string | Content-Type do corpo da requisição. O corpo é serializado nesse formato (abaixo). |
body | object | Objeto que compõe o corpo a enviar usando templates de JSON Pointer. |
includeBody | boolean | Se o corpo do recurso de disparo deve ser enviado junto. |
Em que formato o corpo é enviado
contentType define o formato de serialização do corpo. A comparação ignora maiúsculas e minúsculas e parâmetros como ;charset=…, observando apenas a parte inicial. Se você não o especificar, ou se o valor estiver vazio, o corpo é enviado como application/json. Se includeBody for false ou method for GET, nenhum corpo é enviado e, nesse caso, também não é anexado o Content-Type.
O corpo que um Webhook envia é sempre um objeto. Isso porque o template body é um objeto e, quando você não define nenhum template, o recurso disparado inteiro sai como está.
contentType declarado | Content-Type realmente enviado | Corpo enviado |
|---|---|---|
| (nenhum) | application/json | JSON |
application/json | O valor declarado como está | JSON |
application/x-www-form-urlencoded | O valor declarado como está | product[sku]=TUMBLER-500&product[price]=24000 |
text/plain | application/json | JSON |
Qualquer outro (text/xml e afins) | O valor declarado como está | JSON |
text/plain não consegue conter um objeto, portanto o corpo é enviado com o formato corrigido para um que consiga contê-lo. O cabeçalho nunca informa algo diferente do corpo real. Se o destino precisar receber o corpo como texto, contentType não resolve isso, então verifique o contrato do lado receptor.
form-urlencoded expande um objeto em chaves com colchetes e um array em índices.
| Corpo | Chaves e valores expandidos |
|---|---|
{ "product": { "sku": "TUMBLER-500", "price": 24000 } } | product[sku]=TUMBLER-500&product[price]=24000 |
{ "tags": ["kitchen", "insulated"] } | tags[0]=kitchen&tags[1]=insulated |
{ "items": [{ "sku": "TUMBLER-500" }] } | items[0][sku]=TUMBLER-500 |
{ "memo": null } | memo= |
As chaves e os valores saem com codificação percentual em UTF-8. A tabela acima os mostra decodificados para tornar visível a estrutura das chaves. Mesmo que um valor contenha & ou +, ele não é confundido com um separador de pares nem com um espaço, e é entregue como está.
Expandir o aninhamento em chaves com colchetes é uma convenção amplamente usada, não uma especificação do próprio formato. Verifique se o lado receptor restaura product[sku] em um objeto aninhado e, se não restaurar, componha o template body com chaves planas.
Veja um exemplo de transformation que envia um formulário.
"transformation": {
"method": "POST",
"contentType": "application/x-www-form-urlencoded",
"includeBody": true,
"body": {
"sku": "{ /payload/fields/sku/ko-KR }",
"price": "{ /payload/fields/price/ko-KR }"
}
}Quando um Content cujo sku é TUMBLER-500 e cujo price é 24000 dispara o Webhook, o corpo sai como sku=TUMBLER-500&price=24000.
url e script (apenas um)
Quando um Webhook é disparado, ele executa uma de duas coisas. Se você especificar url, ele envia uma requisição HTTP para essa URL externa (o formato da requisição é definido por transformation, headers e httpBasic*). Se você especificar script, ele não sai para fora, mas executa um Script dentro do Space.
url: URL de destino externa (http/https). Destinos bloqueados, como redes privadas ou loopback, são rejeitados.script: oReferpara o Script a executar.
Você deve especificar exatamente um entre os dois. Especificar ambos, ou deixar ambos vazios, é rejeitado, e o código devolvido varia conforme o caminho (consulte Erros).
"script": { "sys": { "id": "3trmXRMZcTAjDnphewjj1AaxYcaxlK", "type": "Refer", "targetType": "Script" } }Quando disparado, o Script é executado com permissões delegadas, e as permissões de recurso por statement não são reverificadas em tempo de execução. O que é permitido já é verificado quando o Script é criado. Para o modelo detalhado de execução e permissões, consulte Semântica de execução, restrições e segurança do Script.
runAs
runAs define com qual identidade de usuário o script é executado. Essa identidade se torna o createdBy/updatedBy de qualquer recurso criado ou modificado durante a execução, e o filtro createdBy: ":self" dentro de um Script também é resolvido com base nessa identidade. É apenas atribuição (attribution), não um limite de permissão. O que ele pode fazer é determinado pela verificação de permissões realizada quando o Script é criado.
| Valor | Identidade de execução |
|---|---|
HookOwner | Usuário que criou o Webhook (sys.createdBy). Valor padrão. |
EventUser | Usuário que causou aquele evento (alteração), ou seja, o sys.updatedBy do recurso disparado. |
Em um Webhook que usa apenas url, o runAs é ignorado. Se não for especificado, é HookOwner.
WebhookLog
Cada vez que um Webhook tenta um envio, fica um registro. É somente de consulta e não tem endpoints de criação, modificação nem exclusão. O caminho é /spaces/{spaceId}/webhooks/{webhookId}/logs.
{
"sys": {
"id": "3trmXRM3RqbgSnifyg7PWhc01Exam",
"type": "WebhookLog",
"space": { "sys": { "id": "HnQ32YiH", "type": "Refer", "targetType": "Space" } },
"requestId": "3trmXRM3qWnLb7Vd1yPcYs04kKrjq",
"statusCode": 200,
"errors": [],
"eventType": "Create",
"url": "https://api.dailywear.example/webhooks/products",
"requestAt": "2026-06-18T11:35:00.100Z",
"responseAt": "2026-06-18T11:35:00.350Z",
"request": {
"url": "https://api.dailywear.example/webhooks/products",
"method": "POST",
"headers": { "Content-Type": "application/json", "X-Source": "weegloo" },
"body": "{\"sys\":{\"type\":\"Content\"}}"
},
"response": {
"url": "https://api.dailywear.example/webhooks/products",
"headers": { "Content-Type": "application/json" },
"body": "{\"ok\":true}",
"statusCode": 200
},
"createdBy": { "sys": { "id": "3trmXRM3RqbgSnifyg7PWhk01Examp", "type": "Refer", "targetType": "Webhook" } },
"createdAt": "2026-06-18T11:35:00.350Z",
"updatedBy": { "sys": { "id": "3trmXRM3RqbgSnifyg7PWhk01Examp", "type": "Refer", "targetType": "Webhook" } },
"updatedAt": "2026-06-18T11:35:00.350Z"
}
}Todos os valores ficam dentro de sys e não há atributos do corpo. As chaves sem valor ficam de fora da resposta.
Qual Webhook gerou o registro é indicado pelo sys.createdBy. Não é um usuário, mas o Refer daquele Webhook, e o sys.updatedBy também é o mesmo Webhook.
| Atributo | Tipo | Descrição |
|---|---|---|
id | string | Identificador único do registro. |
type | string | Sempre "WebhookLog". |
space | Refer<Space> | O Space ao qual este registro pertence. |
requestId | string | Identificador de rastreamento desta tentativa de envio. |
statusCode | integer | Código de status HTTP da resposta recebida. |
errors | string[] | Lista de motivos de falha. No registro de um Webhook que envia para uma URL, ela está sempre vazia (é o código de status que informa a falha). Só no registro de um Webhook que executa um Script via script é que a mensagem de falha desse Script aparece. |
eventType | string | É o nome da ação que provocou este envio (por exemplo, Create ou Publish). Não vem no formato Content.Create, que se escreve em topics; apenas a ação, a parte final. |
url | string | URL de destino do envio. |
requestAt | string (date-time) | Momento em que a requisição foi enviada. |
responseAt | string (date-time) | Momento em que a resposta foi recebida. |
request | object | A requisição enviada. A estrutura interna está abaixo. Fica de fora na consulta de lista. |
response | object | A resposta recebida. A estrutura interna está abaixo. Fica de fora na consulta de lista. |
createdBy | Refer<Webhook> | O Webhook que gerou este registro. |
createdAt | string (date-time) | Momento de criação do registro. |
updatedBy | Refer<Webhook> | O mesmo que createdBy. |
updatedAt | string (date-time) | O mesmo que createdAt. |
request e response têm, cada um, as seguintes chaves.
request:url(a URL de destino a que a requisição foi enviada),method(o método HTTP),headers(o mapa dos cabeçalhos enviados) ebody(a string do corpo enviado).response:url(a URL de que a resposta veio),headers(o mapa dos cabeçalhos recebidos),body(a string do corpo recebido) estatusCode(o código de status recebido).
O registro de um Webhook que executa um Script via script tem outro formato. Como não há endereço para onde enviar, não existe url, e o method do request é fixo em "SCRIPT". O body do request traz o payload que provocou esse envio, e o body do response traz o valor que aquele Script devolveu (ou a mensagem de falha).
O valor de um cabeçalho com secret ativado é armazenado ocultado. O valor real não fica no registro.
Corpos longos são armazenados encurtados. O critério é de 65.536 caracteres para o body do request e de 8.192 caracteres para o body do response. Se for mais longo que isso, o começo e o fim são preservados e o meio é omitido, e o número de caracteres omitidos fica anotado nesse lugar. Se o corpo for JSON, para não quebrar a estrutura apenas os valores de string longos são encurtados da mesma forma, portanto as chaves e os valores curtos permanecem como estão.
O critério que separa sucesso de falha varia conforme a forma de integração. Um Webhook que envia para uma URL tem sucesso se a resposta for 2xx ou 3xx. Um Webhook que executa um Script via script tem sucesso quando o statusCode é menor que 400 e o errors está vazio. Esse único julgamento determina, ao mesmo tempo, o período de retenção abaixo e a taxa de sucesso do estado de envio.
A consulta de lista devolve sem request e sem response. Isso porque o valor padrão de select do endpoint de lista é -sys.response,-sys.request. Para ver também o corpo da requisição enviada e da resposta recebida, use a consulta individual ou especifique select você mesmo, sobrescrevendo esse valor padrão.
O registro de um envio bem-sucedido desaparece após 1 hora, e o de um envio malsucedido, após 3 dias. Não há na resposta um campo com o horário de expiração; quando chega a hora, o registro desaparece por si só. Um valor que precise ser guardado por mais tempo que isso deve ser salvo separadamente no servidor que recebe, ou registrado como Content pelo Script executado via script.
Erros
São os códigos que você encontra ao lidar com o Webhook. Para os códigos comuns a todos os recursos, consulte Erros comuns.
| Código | Condição |
|---|---|
WGL400042 | Na criação (POST) ou na substituição completa (PUT), url e script foram ambos especificados ou ambos deixados vazios. |
WGL422061 | Na modificação parcial (PATCH), url e script foram ambos especificados ou ambos deixados vazios. |
WGL422050 | O url aponta para um destino bloqueado, como uma rede privada ou loopback. |
API
A URL base de todos os endpoints abaixo é https://cma.weegloo.com/v1, e é necessário um token Bearer no cabeçalho Authorization que autentique na CMA. A modificação (PUT) e a modificação parcial (PATCH) devem enviar também o cabeçalho X-Weegloo-Version (o sys.version do recurso atual) para o controle de concorrência otimista.
Documentos relacionados
- Content: dados de corpo que disparam o Webhook.
- Media: recurso de arquivo que pode disparar o Webhook.
- Script: endpoint de backend declarativo a executar via
script. Inclui o modelo de execução e de permissões. - SpaceRole: configuração de papel que contém permissões como a execução de Script (
Execute).
