top of page

Webhook Documentation
For CRM As A Service

Welcome to the Webhook Documentation for CRM as a Service! This comprehensive developer's guide is your key to seamlessly integrating CRM functionality into your applications.
 

Microsoft Teams Teamswork ticketing blank tablet
Image by Florian Olivo

What is Webhook?

Webhooks are one of the most powerful automation tools available today. Think of them as real-time notifications that allow CRM As A Service to instantly "push" information to other applications your team uses

When a specific event happens in your CRM (like a new Lead is created or a Quotation is marked "Accepted"), a Webhook automatically sends that data to a unique URL, allowing you to trigger actions in external systems like marketing platforms, data dashboards, or custom databases.

For a complete technical deep-dive into webhook, please visit this link https://dev.to/abhivyaktii/exploring-webhooks-a-beginners-guide-4p9p.

Configuring the Webhook in the CRM

Your first step is to tell CRM as a Service where and when to send data.

  1. Navigate to the Webhooks Menu: In the CRM app, go to Settings > Automations > Webhooks. Click + Webhook.

  2. Configure Your Endpoint: An "Add New Webhook" pop-up will appear. As a developer, here is what these fields mean for your implementation:

image.png
  • Webhook name: A clear, descriptive name for your reference.

  • Event entity: The CRM record you want to monitor (e.g., "Lead," "Opportunity").

  • Event action: The specific action that triggers the Webhook (e.g., "Create," "Update").

  • URL: This is your server's public endpoint. CRM as a Service will send a POST request to this HTTPS URL.

  • Secret key: This is your shared secret. You must create and securely store this complex key (e.g., in your server's environment variables). It is used to validate that the request is authentic.
     

Click Save. Your Webhook is now active and will begin sending payloads when the specified events occur.

Validating Data is Sent and Received

Once your Webhook is active, you can monitor its health directly from the Webhook list view in CRM as a Service. The Response code column is your primary indicator of success or failure.

Successful Delivery

When your endpoint receives the request and acknowledges it correctly, the CRM will display a green status box.

image.png

The green 201 box under "Response code" confirms that the connection works perfectly. It is proof that the data didn't just hit the server, but was accepted and processed correctly.

Failed Delivery(No Response)

image.png

If the Webhook fails to reach your server (e.g., DNS issues, server timeout, or incorrect URL), the system will not receive an acknowledgement

Validating the X-Crm-Signature-256 (Security)

This is the most critical step. Do not trust the payload until you validate its signature. This process confirms the request came from your CRM and was not altered. The signature is an HMAC SHA256 digest, computed using your Secret key and the raw request body.

Here is a general implementation example using C+/ TypeScript:

TypeScript:

function validateHmac(secretKey: string, data: any, receivedHmac: string) { 
  // Compute the HMAC using the secret key and SHA256 
  const computedHmac = crypto 
        .createHmac('sha256', secretKey) 
        .update(data) 
        .digest('hex'); 
 
  // Securely compare the received HMAC with the computed one 
  return crypto.timingSafeEqual( 
    Buffer.from(receivedHmac, 'hex'), 
    Buffer.from(computedHmac, 'hex') 
  ); 

C+:

public static bool ValidateHmac(string secretKey, string data, string receivedHmac) 
        { 
            // Convert the secret key and message to byte arrays 
            var keyBytes = Encoding.UTF8.GetBytes(secretKey); 
            var dataBytes = Encoding.UTF8.GetBytes(data); 
 
            // Compute the HMAC using SHA256 
            using (var hmac = new HMACSHA256(keyBytes)) 
            { 
                var computedHmacBytes = hmac.ComputeHash(dataBytes); 
                var computedHmac = BitConverter.ToString(computedHmacBytes).Replace("-", "").ToLower(); 
 
                // Securely compare the received HMAC with the computed one 
                return CryptographicOperations.FixedTimeEquals( 
                    Encoding.UTF8.GetBytes(receivedHmac), 
                    Encoding.UTF8.GetBytes(computedHmac) 
                ); 
            } 
        } 
```

Payload Field Definitions

The JSON payload provides a clear, structured log of the event. Here is the definition of each field you will receive:

Field
Type
Description
id
string

The unique identifier of this delivery event.

event
string

The event type (for example, ticket.created or alert.sla_rt_breached).

timestamp
string

The time the event occurred, formatted as an ISO 8601 date string.

version
string

The payload schema version (current: v1).

tenantId
string

The unique identifier of the Microsoft 365 tenant.

instanceId
string

The unique identifier of the Ticketing instance.

data
object

Event-specific data. Always contains ticket, ticketUrl, and user. May also contain changes, status, comment, attachment, or alert depending on the event type.

data.ticket
object

The current ticket entity, following the Ticketing GET /tickets/{ticketId} resource shape.

data.ticketUrl
string

A reference to the ticket entity endpoint: /tickets/{ticket-guid}.

data.user
object

The user who triggered the event.

data.changes
array

Present on ticket.updated, ticket.assigned, and ticket.status_changed. Lists only the fields that changed, each with field, from, and to.

data.status
object

Present on ticket.status_changed and ticket.resolved. Contains from, to, targetId, transitionLabel, and resolution when applicable.

data.comment
object

Present on comment.created. Contains comment id, isPrivate, and source.

data.attachment
object

Present on attachment events. Contains attachment metadata only. File content is not included.

data.alert
object

Present on alert events. Contains alert-specific metadata relevant to the event type.

Receiving the Payload

The CRM will send a POST request with the following:

  • Headers: The most important header is X-Crm-Signature-256. This contains the HMAC signature.

  • Body: A JSON payload containing the event data.

Example Responses

The following samples shows a real webhook request as displayed using Postman. You can use this example to understand the structure of the HTTP headers and body your endpoint will receive.

1.) CREATE Response:

Description: When a new item is create, itemAfter will contain the full object of the newly created item. This example demonstrates the creation of a new Opportunity.

Example Header:

host: "your-own-domain"

...
x-crm-signature-256: "56a112c124f0e63xxxxxxxxxxxxxxxxxxx97c587abf92aa2bb"
...

Example Body:

Body: { "action": "CREATE", "entity": "Leads", "itemId": "220", "createdOn": "2025-11-10T04:19:11.637Z", "creator": { "id": "xxxxx-xxxx-xxxx-xxxxxxx-xxxx", "name": "Alex Wilber", "email": "AlexW@M365.OnMicrosoft.com" }, "tenantId": "xxxxx-xxxx-xxxx-xxxxxxx-xxxx", "itemAfter": { "id": "220", "title": "Creating a new Lead", "_value": { "code": "USD", "amount": 0 }, "origin": "", "leadRating": "", "note": "", "createdOn": "2025-11-10T04:19:11.541Z", "updatedOn": "2025-11-10T04:19:11.541Z", "archivedOn": "", "convertedOn": "", "lastActivityClosedOn": "2025-11-10T04:19:11.541Z", "owner": { "id": "xxxxx-xxxx-xxxx-xxxxxxx-xxxx", "name": "Alex Wilber", "email": "AlexW@M365.OnMicrosoft.com" }, "creator": { "id": "xxxxx-xxxx-xxxx-xxxxxxx-xxxx", "name": "Alex Wilber", "email": "AlexW@M365.OnMicrosoft.com" }, "lastUpdatedBy": { "id": "exxxxx-xxxx-xxxx-xxxxxxx-xxxx", "name": "Alex Wilber", "email": "AlexW@M365.OnMicrosoft.com" }, "organization": { "id": "132", "name": "Test" }, "contact": {}, "tenantId": "xxxxx-xxxx-xxxx-xxxxxxx-xxxx", "isArchived": false, "isConverted": false, "formVersion": 20, "customFields": { "e5f1f1b6-19bc-45e2-bf06-febf5b88b110": "", "27ca3541-4a49-4f7a-af6a-071e76647340": [ "3ad8be38-949b-4990-98fb-e2250526a362" ], "992f665c-33a4-490e-bfe5-9df470052935": "", "2da764f6-0451-47fe-aa56-e62f0c0fc60c": "", "39617cb2-8db9-4d65-b848-ed35d8035233": "", "159d382c-3107-43e1-b1ed-4eed3747bc3e": [], "f6978a73-3393-4c30-99be-998f96ae5c00": "", "0634edda-a068-4bc2-ada0-58fdf41137f9": [ "e0e1539d-4329-407a-9f36-a3da9b9863b2" ] }, "customFieldsDropdownIndex": { "e5f1f1b6-19bc-45e2-bf06-febf5b88b110": "", "27ca3541-4a49-4f7a-af6a-071e76647340": 0, "2da764f6-0451-47fe-aa56-e62f0c0fc60c": "", "f6978a73-3393-4c30-99be-998f96ae5c00": "", "0634edda-a068-4bc2-ada0-58fdf41137f9": 0 }, "_rid": "spk+AKg6jLpVVQAAAAAAAA==", "_self": "dbs/spk+AA==/colls/spk+AKg6jLo=/docs/spk+AKg6jLpVVQAAAAAAAA==/", "_etag": "\"22000bfc-0000-0700-0000-691167bf0000\"", "_attachments": "attachments/", "_ts": 1762748351 } }

2.) UPDATE Response:

Description: When an item is updated, itemBefore will contain the item's state before the change, and itemAfter will contain the state after the change.

Example Header:

host: "your-own-domain"
...
x-crm-signature-256: "5cb673081382xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxa673"
...

Example Body:

Body: { "action": "UPDATE", "entity": "Cases", "itemId": "1", "createdOn": "2025-11-10T07:21:43.207Z", "creator": { "id": "xxxxxxx-xxxx-xxxx-xxxxxxxxx", "name": "Alex Wilber", "email": "AlexW@M365.OnMicrosoft.com" }, "tenantId": "xxxxxxx-xxxx-xxxx-xxxxxxxxx", "itemBefore": { "id": "1", "status": "Open", "title": "Test Case", "description": "", "caseTypeId": "1", "organization": { "id": "105", "name": "Test Inc" }, "contact": { "id": "107", "name": "Test Person" }, "priority": "", "expectedDate": "2025-09-17", "createdOn": "2025-09-17T02:05:53.399Z", "updatedOn": "2025-10-28T06:16:47.833Z", "owner": { "id": "xxxxxxx-xxxx-xxxx-xxxxxxxxx", "name": "Allan Deyoung", "email": "AllanD@M365.OnMicrosoft.com" }, "creator": { "id": "xxxxxxx-xxxx-xxxx-xxxxxxxxx", "name": "Allan Deyoung", "email": "AllanD@M365.OnMicrosoft.com" }, "lastUpdatedBy": { "id": "xxxxxxx-xxxx-xxxx-xxxxxxxxx", "name": "Alex Wilber", "email": "AlexW@M365.OnMicrosoft.com" }, "tenantId": "xxxxxxx-xxxx-xxxx-xxxxxxxxx", "customFields": {}, "customFieldsDropdownIndex": { "priority": "" }, "version": 1, "workflow": [ { "id": "Open", "label": "Open", "nextSteps": [ { "targetId": "Closed", "transitionLabel": "Close", "recordComment": false }, { "targetId": "In Progress", "transitionLabel": "Start", "recordComment": false }, { "targetId": "Closed", "transitionLabel": "Cancel", "recordComment": true }, { "targetId": "Resolved", "transitionLabel": "Resolve", "recordComment": true } ] }, { "id": "In Progress", "label": "In Progress", "nextSteps": [ { "targetId": "Resolved", "transitionLabel": "Resolve", "recordComment": true }, { "targetId": "Closed", "transitionLabel": "Close", "recordComment": true } ] }, { "id": "Resolved", "label": "Resolved", "nextSteps": [ { "targetId": "Closed", "transitionLabel": "Close", "recordComment": true }, { "targetId": "Reopened", "transitionLabel": "Reopen", "recordComment": true } ] }, { "id": "Closed", "label": "Closed", "nextSteps": [ { "targetId": "Reopened", "transitionLabel": "Reopen", "recordComment": true } ] }, { "id": "Reopened", "label": "Reopened", "nextSteps": [ { "targetId": "Closed", "transitionLabel": "Close", "recordComment": true }, { "targetId": "Resolved", "transitionLabel": "Resolve", "recordComment": true } ] } ], "_rid": "eSACAJw+l13WAAAAAAAAAA==", "_self": "dbs/eSACAA==/colls/eSACAJw+l10=/docs/eSACAJw+l13WAAAAAAAAAA==/", "_etag": "\"2a00a6d3-0000-0700-0000-69005fd20000\"", "_attachments": "attachments/", "_ts": 1761632210 }, "itemAfter": { "id": "1", "status": "Open", "title": "Test Case", "description": "Testing Description", "caseTypeId": "1", "organization": { "id": "105", "name": "Test Inc" }, "contact": { "id": "107", "name": "Test Person" }, "priority": "", "expectedDate": "2025-09-17", "createdOn": "2025-09-17T02:05:53.399Z", "updatedOn": "2025-11-10T07:21:43.173Z", "owner": { "id": "xxxxxxx-xxxx-xxxx-xxxxxxxxx", "name": "Allan Deyoung", "email": "AllanD@M365.OnMicrosoft.com" }, "creator": { "id": "xxxxxxx-xxxx-xxxx-xxxxxxxxx", "name": "Allan Deyoung", "email": "AllanD@M365.OnMicrosoft.com" }, "lastUpdatedBy": { "id": "xxxxxxx-xxxx-xxxx-xxxxxxxxx", "name": "Alex Wilber", "email": "AlexW@M365.OnMicrosoft.com" }, "tenantId": "xxxxxxx-xxxx-xxxx-xxxxxxxxx", "customFields": {}, "customFieldsDropdownIndex": { "priority": "" }, "version": 2, "workflow": [ { "id": "Open", "label": "Open", "nextSteps": [ { "targetId": "Closed", "transitionLabel": "Close", "recordComment": false }, { "targetId": "In Progress", "transitionLabel": "Start", "recordComment": false }, { "targetId": "Closed", "transitionLabel": "Cancel", "recordComment": true }, { "targetId": "Resolved", "transitionLabel": "Resolve", "recordComment": true } ] }, { "id": "In Progress", "label": "In Progress", "nextSteps": [ { "targetId": "Resolved", "transitionLabel": "Resolve", "recordComment": true }, { "targetId": "Closed", "transitionLabel": "Close", "recordComment": true } ] }, { "id": "Resolved", "label": "Resolved", "nextSteps": [ { "targetId": "Closed", "transitionLabel": "Close", "recordComment": true }, { "targetId": "Reopened", "transitionLabel": "Reopen", "recordComment": true } ] }, { "id": "Closed", "label": "Closed", "nextSteps": [ { "targetId": "Reopened", "transitionLabel": "Reopen", "recordComment": true } ] }, { "id": "Reopened", "label": "Reopened", "nextSteps": [ { "targetId": "Closed", "transitionLabel": "Close", "recordComment": true }, { "targetId": "Resolved", "transitionLabel": "Resolve", "recordComment": true } ] } ], "_rid": "eSACAJw+l13WAAAAAAAAAA==", "_self": "dbs/eSACAA==/colls/eSACAJw+l10=/docs/eSACAJw+l13WAAAAAAAAAA==/", "_etag": "\"d600afbd-0000-0700-0000-691192870000\"", "_attachments": "attachments/", "_ts": 1762759303 } }

3.) DELETE Response

Description: When an item is deleted, itemBefore will contain the full object of the item before it was deleted, and itemAfter will be null.

Example Header:

host: "your-own-domain"

...
x-crm-signature-256: "71725cd91133bxxxxxxxxxxxxxxxxxxxxx514ad102b17ebcf553ccde"
...

Example

Body: { "action": "DELETE", "entity": "Cases", "itemId": "1", "createdOn": "2025-11-10T07:59:54.326Z", "creator": { "id": "xxxxxxx-xxxx-xxxx-xxxxxxxx", "name": "Alex Wilber", "email": "AlexW@M365.OnMicrosoft.com" }, "tenantId": "xxxxxxx-xxxx-xxxx-xxxxxxxx", "itemBefore": { "id": "1", "status": "Open", "title": "Test Case", "description": "Testing Description", "caseTypeId": "1", "organization": { "id": "105", "name": "Test Inc" }, "contact": { "id": "107", "name": "Test Person" }, "priority": "", "expectedDate": "2025-09-17", "createdOn": "2025-09-17T02:05:53.399Z", "updatedOn": "2025-11-10T07:21:43.173Z", "owner": { "id": "xxxxxxx-xxxx-xxxx-xxxxxxxx", "name": "Allan Deyoung", "email": "AllanD@M365x.OnMicrosoft.com" }, "creator": { "id": "xxxxxxx-xxxx-xxxx-xxxxxxxx", "name": "Allan Deyoung", "email": "AllanD@M365x.OnMicrosoft.com" }, "lastUpdatedBy": { "id": "xxxxxxx-xxxx-xxxx-xxxxxxxx", "name": "Alex Wilber", "email": "AlexW@M365.OnMicrosoft.com" }, "tenantId": "xxxxxxx-xxxx-xxxx-xxxxxxxx", "customFields": {}, "customFieldsDropdownIndex": { "priority": "" }, "version": 2, "workflow": [ { "id": "Open", "label": "Open", "nextSteps": [ { "targetId": "Closed", "transitionLabel": "Close", "recordComment": false }, { "targetId": "In Progress", "transitionLabel": "Start", "recordComment": false }, { "targetId": "Closed", "transitionLabel": "Cancel", "recordComment": true }, { "targetId": "Resolved", "transitionLabel": "Resolve", "recordComment": true } ] }, { "id": "In Progress", "label": "In Progress", "nextSteps": [ { "targetId": "Resolved", "transitionLabel": "Resolve", "recordComment": true }, { "targetId": "Closed", "transitionLabel": "Close", "recordComment": true } ] }, { "id": "Resolved", "label": "Resolved", "nextSteps": [ { "targetId": "Closed", "transitionLabel": "Close", "recordComment": true }, { "targetId": "Reopened", "transitionLabel": "Reopen", "recordComment": true } ] }, { "id": "Closed", "label": "Closed", "nextSteps": [ { "targetId": "Reopened", "transitionLabel": "Reopen", "recordComment": true } ] }, { "id": "Reopened", "label": "Reopened", "nextSteps": [ { "targetId": "Closed", "transitionLabel": "Close", "recordComment": true }, { "targetId": "Resolved", "transitionLabel": "Resolve", "recordComment": true } ] } ], "_rid": "eSACAJw+l13WAAAAAAAAAA==", "_self": "dbs/eSACAA==/colls/eSACAJw+l10=/docs/eSACAJw+l13WAAAAAAAAAA==/", "_etag": "\"d600afbd-0000-0700-0000-691192870000\"", "_attachments": "attachments/", "_ts": 1762759303 } }

bottom of page