Getting Started with Webhooks
13 minutes to readDiscover how you can use Caspio Webhooks to automate integrations between apps. If you know this already and want to start implementing webhooks right away, go to the configuration steps.
Sample scenarios
You can use webhooks to integrate your Caspio applications with other systems and efficiently synchronize data between them. Consider the following sample use cases that unlock the potential of webhooks to automate data exchange between services:
- Data synchronization
When a customer submits an order on your website, send out order information from Caspio to multiple external systems that handle deliveries. This way you can automate the process, from generating shipping labels to updating the customer with tracking information. You can also use webhooks to back up your data in other services or other Caspio accounts. - Analytics
The moment a new lead is generated in your Caspio app, share the valuable details with an external system that specializes in analytics and reporting. You can use this automation to adjust your sales process and improve your overall performance. - Social media integration
Whenever a new blog post is published on your website, automatically post updates to your company’s social media accounts. - Chatbot integration
When a customer submits a support ticket, notify a chatbot system. Then, the chatbot can provide initial assistance to the customer and assign the ticket to the appropriate support agent. - Marketing campaigns
Notify an external marketing platform when a user completes a specific action, such as signing up for a newsletter or making a purchase. This automation can help you track user engagement and measure campaign success.

Data flow
The implementation of webhooks in Caspio is based on the following relationships between the main elements of this ecosystem:
- To start sending data to a target service, you configure a set of rules that govern the data transfer. This set of rules is called an outgoing webhook.
- As part of each webhook, you configure events that trigger data delivery. These events are specific activities that occur in the tables in your Caspio application.
- When a trigger event occurs, a webhook sends a POST request (a call) that contains a message with a specific header parameters and payload of data in JSON format. For table.recordUpdate events, a webhook sends a message only if a field value changes.
- If the POST request is accepted, the message is delivered, and the target service completes the appropriate actions based on the payload.
Header parameters
Every webhook message is delivered as a POST request that includes a set of HTTP headers. Use these headers to verify, deduplicate, and route incoming messages without parsing the request body:
- User-Agent – identifies the request as originating from Caspio. The current value is
Caspio-Webhook/1.0. - X-Caspio-Signature-Version – Specifies the version of the HMAC signature scheme used to sign the request. The current value is
v1. - X-Caspio-Signature – Contains the HMAC SHA-256 signature of the request. Use this signature to verify that the request was sent by Caspio and that its contents have not been modified in transit.
- X-Caspio-Delivery-Timestamp – Indicates when the webhook request was sent, expressed as a Unix timestamp. Use this value to enforce a replay protection window – for example, reject requests that are more than five minutes old.
- X-Caspio-Delivery-Id – Unique identifier for an individual delivery attempt. A new value is generated for each retry. Use this header for transport-level deduplication and to trace delivery attempts across logs.
- X-Caspio-Delivery-Attempt – Indicates the delivery attempt number, starting at 1. Use this value to identify retry attempts and monitor delivery behavior without checking Caspio delivery logs.
- X-Caspio-Message-Id – Contains the value of the
[@out-hook:messageId]payload field. This value remains the same across all retry attempts for the same event. Use it to implement application-level idempotency by ensuring that each event is processed only once, regardless of how many times it is delivered. - X-Caspio-Event-Type – Contains the value of the
[@out-hook:eventType]payload field, such astable.recordInsert,table.recordUpdate, ortable.recordDelete. Use this header to route webhook requests in a reverse proxy, message queue, or load balancer without parsing the request body.
Deduplicate messages on X-Caspio-Message-Id, not X-Caspio-Delivery-Id. The delivery ID changes on every retry, so each retry would look like a new message.
Payload
Think of a webhook payload as a notification that contains important information about an event that has happened in one system and needs to be shared with another system. This is the main part of the webhook message which is sent to the outgoing URL. The payload can contain fields related to the webhook itself as well as source table fields. Currently, the payload can consist of the following parameters that you can enter manually or through the Insert parameter dialog:
[@out-hook:eventId]– unique identifier of the event definition[@out-hook:messageId]– unique identifier of the message, generated based on the event definition and changes in Caspio tables, which you can use to verify if the message is already processed[@out-hook:callId]– unique identifier of the call that processes the webhook message[@out-hook:webhookId]– unique identifier of the outgoing webhook definition[@out-hook:webhookName]– unique name of the outgoing webhook definition[@out-hook:accountId]– unique identifier of the account from which the message is sent[@out-hook:secret]– signing secret, value that confirms that the message is sent from Caspio[@out-hook:eventDate]– timestamp that determines when the event that triggered the message happened in Caspio tables, which you can use to process messages in the correct order in your destination service[@out-hook:eventType]– action in the source object that triggered the message: table.recordInsert, table.recordDelete, or table.recordUpdate[@out-hook:objectName]– name of the table or directory where the event occurred[@out-hook:objectType]– type of the object where event occured: Table or Directory[@out-hook:objectId]– ID of the table or directory where event occured.[@out-hook:objectFields]– list of fields that will trigger a webhook (only used for the table.recordUpdate event)[@sys:IntegrationURL]– value of the Integration URL parameter available in the account settings[@field:<fieldName>]– value of the table field that you selected to send as a result of the event (in the “data” section of the default payload, all table fields are listed). For attachment data type, you may choose the value to be included:[@field:<attachmentFieldName>]– attachment file name, including the file extension[@field:<attachmentFieldName>/]– attachment file URL, which is valid for 3600 seconds to download the file
[@fielddatatype:<fieldName>]– data type of the table field that you selected
The values in the data parameter are formatted as the following JSON data types:
| Table Data Type | JSON DATA TYPE | Example |
|---|---|---|
Autonumber Currency Integer Number PK_ID | Number | "PK_ID": 7 |
| Yes/No | Boolean | "YES/NO": true |
Date/Time Attachment File GUID ID Prefixed Autonumber Random ID Text(255) Text(64k) Timestamp | String | "IssueDate": "2023-09-13T00:00:00" |
List-String List-Date | String with ID |
|
| List-Number | Number with ID | "ListNumber": {"2": 2,"3": 3} |
| Formula | Based on the return field type |
|
(Empty value)
| null For the following data types:
| |
“” For the remaining data types. |
Note: If a triggered action is enabled for the same event as the webhook, fields with list data types will not be sent in the payload.
You can use the default webhook payload or create a custom payload structure to meet your unique business requirements:
- Default payload consists of all webhook-related fields and a data section with either all or selected fields from the source table.
- Custom payload contains any webhook and data source table fields that you add.
Review the following examples of default and custom payloads:
Default payload
Custom payload
Note: Because the maximum size of a webhook message is 10 MB, consider how many table fields you want to include in your payload. By default, the payload contains all table fields.
Multicast
To make a single event trigger multiple webhooks at the same time, you can use multicast webhooks. In a multicast webhook scenario, a single event can trigger a webhook to send the same webhook message to multiple outgoing URLs. This approach is useful in scenarios where the same event needs to be distributed to multiple applications or systems.
Note: Access to multicast webhooks depends on your plan.
Call throttling
The external service to which you want to send data with outgoing webhooks might have limits on how many calls it can process. To prevent overload and ensure optimal performance, you can adjust the number of calls the webhooks make with call throttling.
If the number of calls to send exceeds the call throttling value, all the webhook messages are created and queued to be sent in batches. The number of messages in each batch is based on your call throttling settings. To check how many messages were created and sent, you can compare their numbers in the list of webhooks, events, or in logs. For more information, see Testing Webhooks.
Note: The maximum limit that you can set depends on your plan.
Automatic retries
When a delivery attempt fails for a transient reason, Caspio retries it automatically. There is nothing to enable and no settings to configure.
Retry schedule
Caspio makes up to six attempts over roughly 30 minutes:
| Attempt | Sent |
|---|---|
| 1 | Immediately |
| 2 | 30 seconds after the first attempt |
| 3 | 2 minutes |
| 4 | 6 minutes |
| 5 | 14 minutes |
| 6 | 30 minutes |
Each interval varies by up to 20% so that large numbers of retries do not arrive at your endpoint at the same moment. If no attempt receives a 2xx response, the message Status is set to Canceled. The schedule, the retry window, and the status codes that qualify for a retry are fixed and cannot be changed.
What is retried
- 5xx responses such as 500, 502, 503, and 504.
- 408 and 429 responses. If a 429 includes a
Retry-Afterheader, Caspio uses that delay for the next attempt instead of the default schedule, up to the end of the retry window. - Network and transport failures including TCP connection failures, TLS handshake failures, DNS resolution failures, and request timeouts. The request timeout is 30 seconds.
What is not retried
- 4xx responses other than 408 and 429. The message Status becomes Canceled after the first attempt, and the failure appears in Integrations logs.
- 2xx and 3xx responses are treated as success. Redirects are followed up to a small limit. Exceeding that limit is treated as a transport failure and is retried.
Identify attempts at your endpoint
X-Caspio-Message-Id(messageId)stays the same across every attempt of one event. Use it to recognize repeat deliveries.X-Delivery_ID(callId)is new for every attempt.X-Caspio-Delivery-Attempt(attemptNumber)carries the attempt number, starting at 1.
Make your endpoint idempotent
Because a message can arrive more than once, your endpoint must handle the same messageId twice without duplicating work. Record each messageId you have processed and ignore repeats.
Common mistakes to avoid:
- Deduplicating on
callId. It changes on every attempt, so every retry looks like a new message. Deduplicate onmessageIdinstead. - Returning 2xx before the work is saved. Caspio treats 2xx as success and stops retrying, so anything lost after that point is not resent.
- Returning a 4xx for a temporary problem. Most 4xx responses cancel the message immediately. Return 5xx, 408, or 429 when you want the delivery retried.
- Relying on
Retry-After. Caspio honors it where it can, but the retry window still applies. Do not assume a delay longer than the window will be observed.
Retries and call throttling
Every attempt counts against your call throttling limit. When the throttle is saturated, attempts queue in the order they were scheduled. Throttling can delay a retry but never cancels one, and the retry window continues to run from the first attempt. A Retry-After delay applies in addition to throttling, not instead of it.
Retries in Integrations logs
The first send is logged as Message sent with an Attempt of 1. Each retry is logged as Message retried with attempts 2 through 6. All attempts for one message share the same Message ID, so you can trace the full delivery history of an event.
Security
Every webhook message is signed so your endpoint can confirm it came from Caspio and was not altered in transit. The signature is sent in the X-Caspio-Signature header, and the scheme version in X-Caspio-Signature-Version.
Verify the signature
- Retrieve the Secret Key from your webhook configuration in Caspio.
- Compute an HMAC-SHA256 hash of the raw request body using your secret key.
- Compare your computed hash with the value in the
X-Caspio-Signaturerequest header. - If the values match, the request is authentic. If they do not match, reject the request.
Each delivery attempt is signed separately, so a retry carries a different signature from the original send. Verify the signature on every request rather than caching a result.
Always validate signatures in production endpoints. Skipping signature verification exposes your endpoint to spoofed requests from unauthorized sources.
Enforce a replay window
Signature verification alone does not stop an attacker from resending a message it captured earlier. Use X-Caspio-Delivery-Timestamp, which carries the send time in Unix seconds, to reject messages older than a window you choose. Five minutes is a common threshold.
If you endpoint cannot compute an HMAC
For receiving systems that cannot compute an HMAC, an optional compatibility mode includes the signing secret in the payload at the event level. Your endpoint compares that value against the secret key shown in the webhook definition. This is weaker than signature verification, because the secret travels with the message, so prefer HMAC verification wherever your stack supports it.
Restrict requests by IP address
To ensure that the webhooks accepted by your system are from trusted sources only, you can configure a list of allowed IP addresses. Learn more.
Caspio Webhook communications use HTTPS to ensure data is protected from interception, tampering, and unauthorized access.
Statistics
You can check the number of messages created, calls sent, and errors received for every webhook and event.
Logs
All activity for every webhook message that is sent is captured in detailed logs. You can use them to troubleshoot issues. Learn more.
Management through REST API
With REST API, you can manage your webhooks and events, which allows you to further automate related tasks and integrate more easily with more services. The tasks that you can complete through REST API include:
- Creating and managing webhooks
- Creating and managing events
- Customizing your payload
- Editing outgoing URLs
- Adjusting call throttling
To configure and manage webhooks through the REST API, create an API profile with the appropriate permissions for the webhooks and the tables or directories on which the webhooks will be triggered. To create a webhook or webhook event, the API profile must also have the create webhook or create event permission. Learn more
Errors
Webhook messages might sometimes fail to deliver or to be processed correctly. All requests that receive an HTML response with codes 4xx and 5xx are treated as errors. You can view details for all errors in logs.
Configuring webhooks
1. Create webhook
Configure a webhook definition and define the outgoing URLs.
2. Configure throttling
Set a limit on the number of calls your webhook makes.
3. Create events
Define the activities in the objects of your app that trigger the messages.
4. Test webhook
Check that the webhook definition sends the messages correctly.
code2
[
{
"objectId": 1246965,
"propertyName": "lifecyclestage",
"propertyValue": "subscriber",
"changeSource": "ACADEMY",
"eventId": 3816279340,
"subscriptionId": 25,
"portalId": 33,
"appId": 1160452,
"occurredAt": 1462216307945,
"eventType":"contact.propertyChange",
"attemptNumber": 0
},
{
"objectId": 1246978,
"changeSource": "IMPORT",
"eventId": 3816279480,
"subscriptionId": 22,
"portalId": 33,
"appId": 1160452,
"occurredAt": 1462216307945,
"eventType": "contact.creation",
"attemptNumber": 0
}
]
code1
{
"eventId": "[@out-hook:eventId]",
"messageId": "[@out-hook:messageId]",
"webhookId": "[@out-hook:webhookId]",
"accountId": "[@out-hook:accountId]",
"secret": "[@out-hook:secret]",
"eventDate": "[@out-hook:eventDate]",
"eventType": "[@out-hook:eventType]",
"objectName": "[@out-hook:objectName]",
"data": [ {
"PK_ID": "[@field:PK_ID]",
"First_Name": "[@field:First_Name]",
"Last_Name": "[@field:Last_Name]",
"Number": "[@field:Number]",
"Form": "[@field:Form]",
"Number2": "[@field:Number2]",
"PersonPicture": "[@field:PersonPicture]"
} ]
}