انتقل إلى المحتوى

الـ Endpoints

Webhooks

Subscribe a URL to workspace events. This is what the Make instant triggers call when a scenario is turned on and off.

كيف تعمل الـ Webhooks

الـ Webhooks بتبعت حدث للـ URL بتاعك لما أي حاجة تحصل في الـ workspace: جهة اتصال جديدة، حجز، طلب اتدفع، أو مكالمة خلصت. كل تسليم موقّع علشان تتأكد إنه جاي من Entagl.

إعداد endpoint

اعمل endpoint بـ POST /webhooks. اختار أنواع الأحداث من القايمة اللي تحت (أو من GET /events)، أو استخدم wildcard زي contact.* أو *. الرد فيه الـ secret بتاع التوقيع مرة واحدة: احفظه. تطبيق Entagl على Make بيعمل ده بدالك لما scenario فيه Entagl trigger يتشغّل، وبيمسح الـ endpoint لما يتقفل.

الطلب
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"
  }'

الـ webhook اللي تقدر تعمله من صفحة القنوات → Webhooks في التطبيق بيستخدم الشكل الأصلي: الـ body بيبقى { event, workspace_id, occurred_at, data } وX-Entagl-Signature هو sha256= متبوع بـ HMAC-SHA256 للـ body الخام. كل اللي تحت بيتكلم عن الـ endpoints اللي بتتعمل من خلال الـ API.

شكل الحدث

كل تسليم هو POST فيه حدث بصيغة JSON. الـ type بيقول إيه اللي حصل، والـ data فيها تفاصيل النوع ده (شوف قايمة الأحداث). الـ actor بيقول مين تسبب فيه (ai أو human أو customer أو system أو api أو import أو provider)، وsource.connection_id بيقول أنهي credential، فالـ integration تقدر تتجاهل تغييراتها هي. أحداث التحديث كمان فيها changes بأسماء الـ fields اللي اتغيّرت.

contact.created
{
  "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-Signatureالتوقيع، شوف تحت.
  • X-Entagl-Event-Idالـ id بتاع الحدث. استخدمه علشان تتخطى المكرر.
  • X-Entagl-Event-Typeنوع الحدث، مثلاً contact.created.
  • X-Entagl-Delivery-Attempt1 في المحاولة الأولى، وبعدين 2 و3 …

تحقّق من التوقيع

الـ header بتاع X-Entagl-Signature شكله كده t=1767225600,v1=5257a869…. الـ t هو وقت الإرسال بثواني Unix. كل v1 هو HMAC-SHA256، بصيغة hex، للنص {t}.{raw body} متعمل بالـ secret بتاع الـ endpoint. احسبه بنفسك وقارنه بطريقة constant-time. ارفض الـ request لو t بعيد عن ساعتك بأكتر من 5 دقايق. بعد تدوير الـ secret بيبقى فيه قيمتين v1 لمدة 24 ساعة: اقبل الـ request لو واحدة منهم اتطابقت.

Node.js (Express)
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);

التسليم وإعادة المحاولة

  • رد بأي حالة 2xx في خلال 10 ثواني. الـ redirects مش بتتتبع.
  • أي حاجة غير كده تعتبر محاولة فاشلة. Entagl بيعيد المحاولة بعد 30 ثانية، ودقيقتين، و10 دقايق، وساعة، و6 ساعات، و24 ساعة، وبعدين بيعلّم التسليم إنه فشل (7 محاولات في المجموع).
  • 410 Gone بيوقف إعادة المحاولة فورًا وبيعطّل الـ endpoint.
  • الـ endpoint اللي يفضل يفشل 72 ساعة بيتعطّل ومالك الـ workspace بيوصله إشعار. شغّله تاني بـ PATCH /webhooks/:id و"status": "active".
  • التسليم ممكن يوصل أكتر من مرة، والأحداث ممكن توصل بترتيب مختلف. استخدم الـ id بتاع الحدث علشان تتخطى المكرر.
  • GET /webhooks/:id/deliveries بيعرض محاولات آخر 30 يوم؛ وPOST …/redeliver بيبعت واحدة تاني.

الخصوصية

افتراضيًا، الأحداث بتستبعد اللي العملاء كتبوه (نص الرسائل، النصوص المفرّغة، الملخصات، الملاحظات) وبيانات الاتصال بيهم (الأسماء، التليفونات، الإيميلات، أسماء المستخدمين). قايمة الأحداث بتوضّح الـ fields دي لكل حدث. علشان تستقبلها، فعّل include_content و/أو include_contact_details على الـ endpoint. مالك الـ workspace أو الـ admin بس يقدر يفعّلهم. في HIPAA workspaces بتفضل متتبعتش أبدًا، مهما كانت الإعدادات. لما field خاص يتستبعد، changes لسه بتذكر اسمه بس عمرها ما بتذكر قيمته القديمة.

قايمة الأحداث

كل أنواع الأحداث اللي Entagl بيبعتها دلوقتي. message.received وmessage.sent حجمهم كبير: الـ wildcard عمره ما بيشملهم، فاكتبهم بالاسم. GET /events بيرجّع نفس الكتالوج بصيغة JSON.

Contacts (11)

contact.createdContact created

Fires when a new contact is added: a first message from someone new, a manual add, an import or the API.

حقول بيانات جهة الاتصال:namefirst_namelast_namephoneemailcustom_fields

contact.updatedContact updated

Fires when any contact field or custom field changes. The envelope "changes" lists the changed fields and their previous values.

حقول بيانات جهة الاتصال:namefirst_namelast_namephoneemailcustom_fields

contact.deletedContact deleted

Fires when a contact is deleted. Carries ids only.

contact.tag_addedContact tag added

Fires when one or more tags are added to a contact.

contact.tag_removedContact tag removed

Fires when one or more tags are removed from a contact.

contact.stage_changedLifecycle stage changed

Fires when a contact moves to another funnel stage, or the stage is removed.

contact.assignedContact owner changed

Fires when a contact is assigned to a team member or unassigned.

contact.lead_capturedLead captured

Fires when the AI (or a form) marks a contact as a lead, with a short summary of what they want.

حقول المحتوى:summary

حقول بيانات جهة الاتصال:namephoneemail

contact.mergedContacts merged

Fires when two contacts are merged into one. The secondary contact id now redirects to the primary.

contact.opted_outContact opted out

Fires when a contact is marked do-not-contact or opts out of marketing messages.

note.createdContact note added

Fires when a team member adds a note to a contact.

حقول المحتوى:body

Conversations (7)

conversation.createdConversation opened

Fires when a new conversation starts on any channel.

conversation.reopenedConversation reopened

Fires when a closed conversation is opened again, by a new customer message or a team member.

conversation.closedConversation closed

Fires when a conversation is closed by a team member, the API or auto-close, with the closing note if any.

حقول المحتوى:closing_note_text

conversation.assignedConversation assignee changed

Fires when a conversation is assigned to a team member or unassigned.

conversation.ai_pausedAI paused on a conversation

Fires when AI replies are paused on a conversation (team member takeover, handover, spam, schedule or API).

conversation.ai_resumedAI resumed on a conversation

Fires when AI replies are switched back on for a conversation.

conversation.comment_createdConversation comment added

Fires when a team member (or the API) adds an internal comment to a conversation. Customers never see comments.

حقول المحتوى:body

Messages (3)

message.receivedIncoming message
حجم كبير: اشترك بالاسم

Fires for every message a customer sends, on any channel. High volume — subscribe only if you need every message.

حقول المحتوى:text

message.sentOutgoing message
حجم كبير: اشترك بالاسم

Fires for every message sent to a customer: AI replies, team replies, campaigns and automations.

حقول المحتوى:text

message.send_failedMessage failed to send

Fires when a message to a customer could not be delivered by the channel.

Handovers (2)

handover.requestedHandover requested

Fires when the AI hands a conversation to a human (customer asked for a person, complaint, or a question it could not answer).

حقول المحتوى:summary

حقول بيانات جهة الاتصال:customer_namecustomer_phone

handover.resolvedHandover resolved

Fires when a team member (or auto-resolve) marks a handover as handled.

AI (3)

conversation.followup_sentFollow-up sent

Fires when the AI sends an automatic follow-up to a customer who went quiet.

ai_turn.failedAI reply failed

Fires when the AI could not produce a reply for a customer message (a fallback message may have been sent instead).

message_feedback.submittedAI reply rated

Fires when a team member gives thumbs up or down to an AI reply.

حقول المحتوى:comment

Bookings (6)

booking.createdBooking created

Fires when an appointment is created for a customer.

حقول المحتوى:conversation_summarydocuments

حقول بيانات جهة الاتصال:customer_namecustomer_phone

booking.documents.addedBooking documents added

Fires when a customer shares a document or photo in a conversation after their booking was created. Delivers only the new file(s).

حقول المحتوى:documents

حقول بيانات جهة الاتصال:customer_namecustomer_phone

booking.updatedBooking updated

Fires when any booking detail changes (time, service, duration, location, notes). The envelope "changes" lists what changed.

حقول بيانات جهة الاتصال:customer_namecustomer_phone

booking.rescheduledBooking rescheduled

Fires when a booking moves to a new date or time.

حقول بيانات جهة الاتصال:customer_namecustomer_phone

booking.cancelledBooking cancelled

Fires when a booking is cancelled by the customer (through the AI), a team member, or the API.

حقول بيانات جهة الاتصال:customer_namecustomer_phone

booking.status_changedBooking status changed

Fires when a booking status changes, e.g. confirmed, completed or no-show.

حقول بيانات جهة الاتصال:customer_namecustomer_phone

Reminders (4)

reminder.createdReminder created

Fires when a reminder is created.

حقول المحتوى:titlenote

reminder.firedReminder due

Fires when a reminder becomes due and the assignees are notified.

حقول المحتوى:titlenote

reminder.closedReminder closed

Fires when a reminder is marked done.

حقول المحتوى:titlenote

appointment_reminder.sentAppointment reminder sent

Fires when an automatic appointment reminder (WhatsApp template or SMS) is sent to a customer.

Orders (6)

order.createdOrder created

Fires when an order is created by the AI, a team member, a store sync or the API.

حقول بيانات جهة الاتصال:customer_namecustomer_phone

order.updatedOrder updated

Fires when any order detail or item changes. The envelope "changes" lists what changed.

حقول بيانات جهة الاتصال:customer_namecustomer_phone

order.status_changedOrder status changed

Fires when an order status changes (for example confirmed, shipped, delivered).

حقول بيانات جهة الاتصال:customer_namecustomer_phone

order.paidOrder paid

Fires when an order is marked as paid.

حقول بيانات جهة الاتصال:customer_namecustomer_phone

order.cancelledOrder cancelled

Fires when an order is cancelled.

حقول بيانات جهة الاتصال:customer_namecustomer_phone

order.payment_proof_uploadedPayment proof uploaded

Fires when a customer (through the AI) or a team member attaches a payment receipt to an order.

Products (3)

product.createdProduct created

Fires when a product is added to the catalog.

product.updatedProduct updated

Fires when a product changes (price, stock, details).

product.deletedProduct deleted

Fires when a product is removed from the catalog.

Calls (3)

call.endedCall ended

Fires after every AI phone or WhatsApp call, with outcome and (opt-in) summary and transcript.

حقول المحتوى:summarytranscript

حقول بيانات جهة الاتصال:from_numberto_number

call.missedMissed call

Fires when an incoming call was not answered or an outgoing call got no answer.

حقول المحتوى:summarytranscript

حقول بيانات جهة الاتصال:from_numberto_number

call.voicemail_receivedVoicemail received

Fires when a caller leaves a voicemail.

حقول المحتوى:transcript_text

حقول بيانات جهة الاتصال:from_number

Campaigns (3)

campaign.completedCampaign finished sending

Fires when a broadcast campaign finished sending to all recipients.

campaign_recipient.repliedCampaign reply

Fires when a recipient replies to a campaign message.

campaign_recipient.failedCampaign message failed

Fires when a campaign message could not be delivered to a recipient.

Forms (1)

form.submittedForm submitted

Fires when a customer submits a form (website widget, hosted link or in-chat intake).

حقول المحتوى:fields

Account (3)

channel.disconnectedChannel disconnected

Fires when a channel stops working (token expired, access removed) or is disconnected.

channel.reconnectedChannel healthy again

Fires when a previously failing channel works again.

credits.threshold_reachedCredits running low

Fires when credit usage crosses 80%, 100% or 120% of the plan allowance.

Workspace (3)

tag.createdTag created

Fires when a tag is added to the workspace tag list.

tag.updatedTag updated

Fires when a workspace tag is renamed or recolored.

tag.deletedTag deleted

Fires when a workspace tag is deleted (it is removed from every contact).

المسارات نسبية للـ base URL. كل كارت بيوضّح الصلاحية اللي الاستدعاء محتاجها وكل parameter، مع نوعه وحدوده.

GET
/webhooks

List webhook endpoints.

الصلاحية: integrations
مقسّم لصفحات
POST
/webhooks

Create a webhook endpoint. The signing secret is returned once, in this response.

الصلاحية: integrations

الـ body بصيغة JSON

  • urlمطلوبstring (URL)

    https:// URL that receives events, up to 2,048 characters. Private and internal addresses are refused (422 unsafe_url).

  • eventsمطلوبarray 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.

  • descriptionاختياريstring

    Up to 200 characters.

  • filtersاختياريobject

    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_contentاختياريboolean

    Include message text, transcripts and notes. Owner or admin only; refused on HIPAA workspaces.

  • include_contact_detailsاختياريboolean

    Include names, phones, emails and handles. Owner or admin only; refused on HIPAA workspaces.

  • created_viaاختياريenum

    Which tool created the endpoint.

    القيم المسموحة:apimakezapiern8n

  • A workspace can have up to 100 endpoints (409 endpoint_limit_reached).
GET
/webhooks/:id

Retrieve a webhook endpoint with its status and last delivery result.

الصلاحية: integrations

معاملات المسار

  • idمطلوبstring

    Endpoint ID (starts with "we_").

PATCH
/webhooks/:id

Update an endpoint, or pause and re-activate it.

الصلاحية: integrations

معاملات المسار

  • idمطلوبstring

    Endpoint ID.

الـ body بصيغة JSON

  • urlاختياريstring (URL)

    New receiving URL.

  • eventsاختياريarray of strings

    New event list.

  • descriptionاختياريstring | null

    Up to 200 characters.

  • filtersاختياريobject

    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_contentاختياريboolean

    Owner or admin only to turn on.

  • include_contact_detailsاختياريboolean

    Owner or admin only to turn on.

  • statusاختياريenum

    Re-activating resets the failure count.

    القيم المسموحة:activepaused

  • On an endpoint that includes content or contact details, only an owner or admin can change url, events or filters.
DELETE
/webhooks/:id

Delete an endpoint (a Make trigger calls this when its scenario is turned off).

الصلاحية: integrations

معاملات المسار

  • idمطلوبstring

    Endpoint ID.

POST
/webhooks/:id/rotate-secret

Issue a new signing secret. The previous secret keeps signing deliveries for 24 hours.

الصلاحية: integrations

معاملات المسار

  • idمطلوبstring

    Endpoint ID.

POST
/webhooks/:id/test

Send a signed sample event to the endpoint now and return the result (delivered, status, error, duration_ms).

الصلاحية: integrations

معاملات المسار

  • idمطلوبstring

    Endpoint ID.

الـ body بصيغة JSON

  • eventاختياريstring

    Event type to sample. Defaults to the endpoint's first non-wildcard event, else a generic "webhook.test" event.

GET
/webhooks/:id/deliveries

Recent delivery attempts, newest first. Deliveries are kept for 30 days.

الصلاحية: integrations
مقسّم لصفحات

معاملات المسار

  • idمطلوبstring

    Endpoint ID.

POST
/webhooks/:id/deliveries/:deliveryId/redeliver

Queue a delivery to be sent again. Answers 202.

الصلاحية: integrations

معاملات المسار

  • idمطلوبstring

    Endpoint ID.

  • deliveryIdمطلوبinteger

    Delivery ID from the deliveries list.