Endpoints
Webhooks
Subscribe a URL to workspace events. This is what the Make instant triggers call when a scenario is turned on and off.
Como os webhooks funcionam
Os webhooks enviam um evento para a sua URL quando algo acontece no workspace: um novo contato, um agendamento, um pedido pago, uma chamada concluída. Cada entrega é assinada, para você conferir que veio do Entagl.
Configure um endpoint
Crie um endpoint com POST /webhooks. Escolha os tipos de evento na lista abaixo (ou em GET /events), ou use um curinga como contact.* ou *. A resposta inclui o secret de assinatura uma única vez: guarde-o. O app do Entagl para o Make faz isso por você quando um scenario com um trigger do Entagl é ativado, e exclui o endpoint quando ele é desativado.
curl -X POST "https://api.entagl.com/api/v1/webhooks" \
-H "Authorization: Bearer ai_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/entagl/webhooks",
"events": ["contact.created", "booking.*"],
"description": "CRM sync"
}'O webhook que você configura na página Canais → Webhooks do app usa o formato original: o corpo é { event, workspace_id, occurred_at, data } e X-Entagl-Signature é sha256= seguido de um HMAC-SHA256 do corpo bruto. Tudo o que vem abaixo descreve endpoints criados pela API.
Formato do evento
Cada entrega é um POST com um evento JSON. type diz o que aconteceu e data traz os detalhes desse tipo (veja a lista de eventos). actor diz quem causou o evento (ai, human, customer, system, api, import ou provider) e source.connection_id diz qual credencial, para que uma integração possa ignorar as próprias mudanças. Os eventos de atualização também trazem changes com os nomes dos campos alterados.
{
"id": "evt_5c1f0a9e7b2d4e3f8a6c0b1d2e3f4a5b",
"object": "event",
"type": "contact.created",
"api_version": "2026-10-01",
"occurred_at": "2026-10-01T14:32:11.482Z",
"created_at": "2026-10-01T14:32:11.482Z",
"workspace_id": "00000000-0000-0000-0000-000000000000",
"actor": {
"type": "api",
"id": "user_9f2c1a"
},
"resource": {
"type": "contact",
"id": "6789"
},
"source": {
"connection_id": "apikey:42",
"via": "api"
},
"data": {
"contact_id": 6789,
"name": "Jane Doe",
"first_name": "Jane",
"last_name": "Doe",
"phone": "+15551234567",
"email": "jane@example.com",
"channel": "instagram",
"tags": [
"vip",
"botox"
],
"stage": {
"funnel_id": 3,
"stage_id": 14,
"stage_name": "Qualified"
},
"assigned_to_user_id": "user_9f2c1a",
"language": "en",
"custom_fields": {
"budget": "500-1000",
"preferred_branch": "Downtown"
},
"created_at": "2026-09-28T10:02:44.000Z",
"updated_at": "2026-10-01T14:32:11.482Z"
},
"changes": null
}- Content-Typeapplication/json
- User-AgentEntagl-Webhooks/2.0
- X-Entagl-SignatureAssinatura, veja abaixo.
- X-Entagl-Event-IdO ID do evento. Use para ignorar duplicatas.
- X-Entagl-Event-TypeO tipo do evento, ex.: contact.created.
- X-Entagl-Delivery-Attempt1 na primeira tentativa, depois 2, 3 …
Verifique a assinatura
O header X-Entagl-Signature tem este formato: t=1767225600,v1=5257a869…. t é o horário de envio em segundos Unix. Cada v1 é um HMAC-SHA256, em hexadecimal, do texto {t}.{raw body} gerado com o secret do seu endpoint. Calcule você mesmo e compare em tempo constante. Rejeite a requisição quando t estiver a mais de 5 minutos do seu relógio. Depois de uma rotação de secret, há dois valores v1 por 24 horas: aceite a requisição se qualquer um deles bater.
import crypto from 'node:crypto';
import express from 'express';
const app = express();
// The secret returned once by POST /api/v1/webhooks (or by rotate-secret).
const SECRET = process.env.ENTAGL_WEBHOOK_SECRET;
// Read the RAW body: the signature covers the exact bytes Entagl sent.
app.post('/entagl/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
const rawBody = req.body.toString('utf8');
if (!verifyEntaglSignature(req.get('X-Entagl-Signature') || '', rawBody, SECRET)) {
return res.status(400).send('invalid signature');
}
const event = JSON.parse(rawBody);
// Deliveries can repeat: skip an event.id you have already handled.
console.log(event.type, event.id);
res.sendStatus(200); // any 2xx within 10 seconds counts as delivered
});
function verifyEntaglSignature(header, rawBody, secret, toleranceSeconds = 300) {
const parts = header.split(',').map((p) => p.trim());
const t = Number(parts.find((p) => p.startsWith('t='))?.slice(2));
if (!Number.isFinite(t) || Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false;
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
return parts
.filter((p) => p.startsWith('v1='))
.some((p) => {
const got = p.slice(3);
return got.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(got), Buffer.from(expected));
});
}
app.listen(3000);Entrega e novas tentativas
- Responda com qualquer status
2xxem até 10 segundos. Redirecionamentos não são seguidos. - Qualquer outra resposta é uma tentativa falha. O Entagl tenta de novo após 30 segundos, 2 minutos, 10 minutos, 1 hora, 6 horas e 24 horas, e então marca a entrega como falha (7 tentativas no total).
410 Goneinterrompe as tentativas na hora e desativa o endpoint.- Um endpoint que continua falhando por 72 horas é desativado e o proprietário do workspace é avisado. Reative-o com
PATCH /webhooks/:ide"status": "active". - Uma entrega pode chegar mais de uma vez, e os eventos podem chegar fora de ordem. Use o ID do evento para ignorar duplicatas.
GET /webhooks/:id/deliveriesmostra os últimos 30 dias de tentativas;POST …/redeliverenvia uma de novo.
Privacidade
Por padrão, os eventos deixam de fora o que os clientes escreveram (texto das mensagens, transcrições, resumos, notas) e os dados de contato deles (nomes, telefones, e-mails, nomes de usuário). A lista de eventos mostra esses campos para cada evento. Para recebê-los, defina include_content e/ou include_contact_details no endpoint. Só o proprietário ou um admin do workspace pode ativá-los. Em workspaces HIPAA, eles nunca são enviados, seja qual for a configuração. Quando um campo privado é omitido, changes ainda lista o nome dele, mas nunca o valor antigo.
Lista de eventos
Todos os tipos de evento que o Entagl envia hoje. message.received e message.sent têm alto volume: um curinga nunca os inclui, então liste-os pelo nome. GET /events retorna o mesmo catálogo em JSON.
Contacts (11)
contact.createdContact createdFires when a new contact is added: a first message from someone new, a manual add, an import or the API.
Campos de dados de contato:namefirst_namelast_namephoneemailcustom_fields
contact.updatedContact updatedFires when any contact field or custom field changes. The envelope "changes" lists the changed fields and their previous values.
Campos de dados de contato:namefirst_namelast_namephoneemailcustom_fields
contact.deletedContact deletedFires when a contact is deleted. Carries ids only.
contact.tag_addedContact tag addedFires when one or more tags are added to a contact.
contact.tag_removedContact tag removedFires when one or more tags are removed from a contact.
contact.stage_changedLifecycle stage changedFires when a contact moves to another funnel stage, or the stage is removed.
contact.assignedContact owner changedFires when a contact is assigned to a team member or unassigned.
contact.lead_capturedLead capturedFires when the AI (or a form) marks a contact as a lead, with a short summary of what they want.
Campos de conteúdo:summary
Campos de dados de contato:namephoneemail
contact.mergedContacts mergedFires when two contacts are merged into one. The secondary contact id now redirects to the primary.
contact.opted_outContact opted outFires when a contact is marked do-not-contact or opts out of marketing messages.
note.createdContact note addedFires when a team member adds a note to a contact.
Campos de conteúdo:body
Conversations (7)
conversation.createdConversation openedFires when a new conversation starts on any channel.
conversation.reopenedConversation reopenedFires when a closed conversation is opened again, by a new customer message or a team member.
conversation.closedConversation closedFires when a conversation is closed by a team member, the API or auto-close, with the closing note if any.
Campos de conteúdo:closing_note_text
conversation.assignedConversation assignee changedFires when a conversation is assigned to a team member or unassigned.
conversation.ai_pausedAI paused on a conversationFires when AI replies are paused on a conversation (team member takeover, handover, spam, schedule or API).
conversation.ai_resumedAI resumed on a conversationFires when AI replies are switched back on for a conversation.
conversation.comment_createdConversation comment addedFires when a team member (or the API) adds an internal comment to a conversation. Customers never see comments.
Campos de conteúdo:body
Messages (3)
message.receivedIncoming messageFires for every message a customer sends, on any channel. High volume — subscribe only if you need every message.
Campos de conteúdo:text
message.sentOutgoing messageFires for every message sent to a customer: AI replies, team replies, campaigns and automations.
Campos de conteúdo:text
message.send_failedMessage failed to sendFires when a message to a customer could not be delivered by the channel.
Handovers (2)
handover.requestedHandover requestedFires when the AI hands a conversation to a human (customer asked for a person, complaint, or a question it could not answer).
Campos de conteúdo:summary
Campos de dados de contato:customer_namecustomer_phone
handover.resolvedHandover resolvedFires when a team member (or auto-resolve) marks a handover as handled.
AI (3)
conversation.followup_sentFollow-up sentFires when the AI sends an automatic follow-up to a customer who went quiet.
ai_turn.failedAI reply failedFires when the AI could not produce a reply for a customer message (a fallback message may have been sent instead).
message_feedback.submittedAI reply ratedFires when a team member gives thumbs up or down to an AI reply.
Campos de conteúdo:comment
Bookings (6)
booking.createdBooking createdFires when an appointment is created for a customer.
Campos de conteúdo:conversation_summarydocuments
Campos de dados de contato:customer_namecustomer_phone
booking.documents.addedBooking documents addedFires when a customer shares a document or photo in a conversation after their booking was created. Delivers only the new file(s).
Campos de conteúdo:documents
Campos de dados de contato:customer_namecustomer_phone
booking.updatedBooking updatedFires when any booking detail changes (time, service, duration, location, notes). The envelope "changes" lists what changed.
Campos de dados de contato:customer_namecustomer_phone
booking.rescheduledBooking rescheduledFires when a booking moves to a new date or time.
Campos de dados de contato:customer_namecustomer_phone
booking.cancelledBooking cancelledFires when a booking is cancelled by the customer (through the AI), a team member, or the API.
Campos de dados de contato:customer_namecustomer_phone
booking.status_changedBooking status changedFires when a booking status changes, e.g. confirmed, completed or no-show.
Campos de dados de contato:customer_namecustomer_phone
Reminders (4)
reminder.createdReminder createdFires when a reminder is created.
Campos de conteúdo:titlenote
reminder.firedReminder dueFires when a reminder becomes due and the assignees are notified.
Campos de conteúdo:titlenote
reminder.closedReminder closedFires when a reminder is marked done.
Campos de conteúdo:titlenote
appointment_reminder.sentAppointment reminder sentFires when an automatic appointment reminder (WhatsApp template or SMS) is sent to a customer.
Orders (6)
order.createdOrder createdFires when an order is created by the AI, a team member, a store sync or the API.
Campos de dados de contato:customer_namecustomer_phone
order.updatedOrder updatedFires when any order detail or item changes. The envelope "changes" lists what changed.
Campos de dados de contato:customer_namecustomer_phone
order.status_changedOrder status changedFires when an order status changes (for example confirmed, shipped, delivered).
Campos de dados de contato:customer_namecustomer_phone
order.paidOrder paidFires when an order is marked as paid.
Campos de dados de contato:customer_namecustomer_phone
order.cancelledOrder cancelledFires when an order is cancelled.
Campos de dados de contato:customer_namecustomer_phone
order.payment_proof_uploadedPayment proof uploadedFires when a customer (through the AI) or a team member attaches a payment receipt to an order.
Products (3)
product.createdProduct createdFires when a product is added to the catalog.
product.updatedProduct updatedFires when a product changes (price, stock, details).
product.deletedProduct deletedFires when a product is removed from the catalog.
Calls (3)
call.endedCall endedFires after every AI phone or WhatsApp call, with outcome and (opt-in) summary and transcript.
Campos de conteúdo:summarytranscript
Campos de dados de contato:from_numberto_number
call.missedMissed callFires when an incoming call was not answered or an outgoing call got no answer.
Campos de conteúdo:summarytranscript
Campos de dados de contato:from_numberto_number
call.voicemail_receivedVoicemail receivedFires when a caller leaves a voicemail.
Campos de conteúdo:transcript_text
Campos de dados de contato:from_number
Campaigns (3)
campaign.completedCampaign finished sendingFires when a broadcast campaign finished sending to all recipients.
campaign_recipient.repliedCampaign replyFires when a recipient replies to a campaign message.
campaign_recipient.failedCampaign message failedFires when a campaign message could not be delivered to a recipient.
Forms (1)
form.submittedForm submittedFires when a customer submits a form (website widget, hosted link or in-chat intake).
Campos de conteúdo:fields
Account (3)
channel.disconnectedChannel disconnectedFires when a channel stops working (token expired, access removed) or is disconnected.
channel.reconnectedChannel healthy againFires when a previously failing channel works again.
credits.threshold_reachedCredits running lowFires when credit usage crosses 80%, 100% or 120% of the plan allowance.
Workspace (3)
tag.createdTag createdFires when a tag is added to the workspace tag list.
tag.updatedTag updatedFires when a workspace tag is renamed or recolored.
tag.deletedTag deletedFires when a workspace tag is deleted (it is removed from every contact).
Os caminhos são relativos à URL base. Cada card lista a permissão que a chamada exige e todos os parâmetros, com tipo e limites.
/webhooksList webhook endpoints.
/webhooksCreate a webhook endpoint. The signing secret is returned once, in this response.
Corpo JSON
- urlobrigatóriostring (URL)
https:// URL that receives events, up to 2,048 characters. Private and internal addresses are refused (422 unsafe_url).
- eventsobrigatórioarray of strings
1–100 event types from GET /events, "<prefix>.*" (e.g. "contact.*") or "*". Wildcards never include message.received and message.sent; list those explicitly.
- descriptionopcionalstring
Up to 200 characters.
- filtersopcionalobject
Optional narrowing: channels (array of channel names, up to 20), actor_types (array, up to 7), sources (object of event type → source keys), ignore_own_changes (boolean — skip events caused by this same connection; on by default for connector-created endpoints).
- include_contentopcionalboolean
Include message text, transcripts and notes. Owner or admin only; refused on HIPAA workspaces.
- include_contact_detailsopcionalboolean
Include names, phones, emails and handles. Owner or admin only; refused on HIPAA workspaces.
- created_viaopcionalenum
Which tool created the endpoint.
Valores permitidos:
apimakezapiern8n
- A workspace can have up to 100 endpoints (409 endpoint_limit_reached).
/webhooks/:idRetrieve a webhook endpoint with its status and last delivery result.
Parâmetros de caminho
- idobrigatóriostring
Endpoint ID (starts with "we_").
/webhooks/:idUpdate an endpoint, or pause and re-activate it.
Parâmetros de caminho
- idobrigatóriostring
Endpoint ID.
Corpo JSON
- urlopcionalstring (URL)
New receiving URL.
- eventsopcionalarray of strings
New event list.
- descriptionopcionalstring | null
Up to 200 characters.
- filtersopcionalobject
Optional narrowing: channels (array of channel names, up to 20), actor_types (array, up to 7), sources (object of event type → source keys), ignore_own_changes (boolean — skip events caused by this same connection; on by default for connector-created endpoints).
- include_contentopcionalboolean
Owner or admin only to turn on.
- include_contact_detailsopcionalboolean
Owner or admin only to turn on.
- statusopcionalenum
Re-activating resets the failure count.
Valores permitidos:
activepaused
- On an endpoint that includes content or contact details, only an owner or admin can change url, events or filters.
/webhooks/:idDelete an endpoint (a Make trigger calls this when its scenario is turned off).
Parâmetros de caminho
- idobrigatóriostring
Endpoint ID.
/webhooks/:id/rotate-secretIssue a new signing secret. The previous secret keeps signing deliveries for 24 hours.
Parâmetros de caminho
- idobrigatóriostring
Endpoint ID.
/webhooks/:id/testSend a signed sample event to the endpoint now and return the result (delivered, status, error, duration_ms).
Parâmetros de caminho
- idobrigatóriostring
Endpoint ID.
Corpo JSON
- eventopcionalstring
Event type to sample. Defaults to the endpoint's first non-wildcard event, else a generic "webhook.test" event.
/webhooks/:id/deliveriesRecent delivery attempts, newest first. Deliveries are kept for 30 days.
Parâmetros de caminho
- idobrigatóriostring
Endpoint ID.
/webhooks/:id/deliveries/:deliveryId/redeliverQueue a delivery to be sent again. Answers 202.
Parâmetros de caminho
- idobrigatóriostring
Endpoint ID.
- deliveryIdobrigatóriointeger
Delivery ID from the deliveries list.