Webhooks Overview
Webhooks allow MeSomb to notify your application when an important event happens in your account.
Instead of repeatedly calling the MeSomb API to check whether a payment has changed, your application can expose a webhook endpoint. MeSomb will send an HTTP request to that endpoint whenever a subscribed event occurs.
Typical webhook use cases include:
- confirming that a payment transaction succeeded;
- updating an order after a checkout session is completed;
- releasing goods or services after a secure payment is funded;
- synchronizing payment status with your internal system;
- receiving dispute, refund, payout, or account lifecycle notifications.
How webhooks work
A webhook is an HTTP POST request sent by MeSomb to a URL that you configure.
Example flow:
Example webhook endpoint URL:
<span><span style="color: undefined">https://example.com/webhooks/mesomb</span></span>
<span><span style="color: undefined"></span></span>
Your endpoint must be publicly reachable over HTTPS.
Webhook event structure
All MeSomb webhook events use the same top-level structure.
<span><span style="color: var(--shiki-color-text)">{</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"id"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"adbbf6bd-1746-4545-a3ce-8b153a7a31b2"</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"object_type"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"payment"</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"event_type"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"payment.succeeded"</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"api_version"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"2026-05-01"</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"created_at"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"2026-05-07T22:15:30Z"</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"livemode"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">true</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"data"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"object"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"id"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"txn_01HX9K7A1R6F8MZK2Q9V7N4P5B"</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"object"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"payment_transaction"</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"status"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"succeeded"</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"amount"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">15000</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"currency"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"XAF"</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"reference"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"ORDER-10045"</span></span>
<span><span style="color: var(--shiki-color-text)"> }</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"previous_attributes"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"status"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"pending"</span></span>
<span><span style="color: var(--shiki-color-text)"> }</span></span>
<span><span style="color: var(--shiki-color-text)"> }</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>
Top-level fields
| Field | Type | Description |
id | string | Unique ID of the webhook event. Use this for deduplication. |
object_type | string | Always event. |
event_type | string | Name of the event, for example payment.success. |
api_version | string | MeSomb API version used for this event payload. |
created_at | string | Date and time when the event was created, in ISO 8601 UTC format. |
livemode | boolean | true for live events, false for test events. |
data.object | object | Snapshot of the resource affected by the event. |
data.previous_attributes | object | Previous values for fields that changed, when available. |
Event naming convention
MeSomb event names follow this format:
<span><span style="color: undefined">domain.resource.action</span></span>
<span><span style="color: undefined"></span></span>
Examples:
<span><span style="color: undefined">payment.transaction.succeeded</span></span>
<span><span style="color: undefined">checkout.session.completed</span></span>
<span><span style="color: undefined">secure_payment.transaction.released</span></span>
<span><span style="color: undefined">dispute.created</span></span>
<span><span style="color: undefined">payout.paid</span></span>
<span><span style="color: undefined"></span></span>
The event name should be used by your application to decide how to process the webhook.
Example:
<span><span style="color: var(--shiki-token-keyword)">if</span><span style="color: var(--shiki-color-text)"> event</span><span style="color: var(--shiki-token-punctuation)">[</span><span style="color: var(--shiki-token-string-expression)">"type"</span><span style="color: var(--shiki-token-punctuation)">]</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">==</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"payment.transaction.succeeded"</span><span style="color: var(--shiki-token-punctuation)">:</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">handle_successful_payment</span><span style="color: var(--shiki-token-punctuation)">(event[</span><span style="color: var(--shiki-token-string-expression)">"data"</span><span style="color: var(--shiki-token-punctuation)">][</span><span style="color: var(--shiki-token-string-expression)">"object"</span><span style="color: var(--shiki-token-punctuation)">])</span></span>
<span><span style="color: var(--shiki-token-keyword)">elif</span><span style="color: var(--shiki-color-text)"> event</span><span style="color: var(--shiki-token-punctuation)">[</span><span style="color: var(--shiki-token-string-expression)">"type"</span><span style="color: var(--shiki-token-punctuation)">]</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">==</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"checkout.session.completed"</span><span style="color: var(--shiki-token-punctuation)">:</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">handle_completed_checkout</span><span style="color: var(--shiki-token-punctuation)">(event[</span><span style="color: var(--shiki-token-string-expression)">"data"</span><span style="color: var(--shiki-token-punctuation)">][</span><span style="color: var(--shiki-token-string-expression)">"object"</span><span style="color: var(--shiki-token-punctuation)">])</span></span>
<span></span>
Webhook response requirements
Your webhook endpoint should return a 2xx HTTP status code when the event has been successfully received.
Recommended responses:
<span><span style="color: undefined">HTTP/1.1 200 OK</span></span>
<span><span style="color: undefined"></span></span>
or:
<span><span style="color: undefined">HTTP/1.1 204 No Content</span></span>
<span><span style="color: undefined"></span></span>
HTTP 408, HTTP 429, HTTP 5xx and temporary network failures are retried. Other HTTP 4xx responses end delivery of that event without automatic retries. Redirects are rejected: configure the final HTTPS URL directly.
Retry behavior
Each event has at most 6 automatic delivery attempts: the initial attempt and 5 retries. Retry delays are 30, 60, 120, 240 and 480 seconds, with an additional random delay of up to 10 seconds each. These are scheduling delays, not a guaranteed delivery deadline.
See the delivery and recovery guide for retry limits, automatic disabling rules and reactivation instructions.
Duplicate events and idempotency
Webhook events can be delivered more than once.
Always use the event ID to detect duplicate events:
<span><span style="color: var(--shiki-color-text)">{</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"id"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"adbbf6bd-1746-4545-a3ce-8b153a7a31b2"</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>
Recommended behavior:
- Receive the webhook.
- Verify the signature.
- Check whether the event ID has already been processed.
- If already processed, return
200 OKwithout running the business action again. - If not processed, process the event and store the event ID.
Webhook signature verification
Every webhook request sent by MeSomb is signed.
Your server should verify the X-MeSomb-Webhook-Signature header before processing the event.
Webhook signature verification protects your integration against fake or modified webhook requests.
Read the full guide in: Verifying webhook signatures.
Security recommendations
Before using webhooks in production:
- use HTTPS for your webhook endpoint;
- verify the
X-MeSomb-Webhook-Signatureheader; - use the raw request body for signature verification;
- reject old timestamps;
- store processed event IDs for deduplication;
- do not expose webhook secrets in frontend or mobile code;
- return
2xxonly when the event has been successfully received.
Example webhook handler flow
Recommended processing model
Webhook endpoints should respond quickly.
For production systems, avoid running heavy business logic directly inside the webhook HTTP request.
Recommended approach:
- Verify the signature.
- Store the event.
- Return a
2xxresponse. - Process the event asynchronously using a background worker.
This reduces timeout risks and improves webhook delivery reliability.
