Makini
v4 (Latest)
  • v4 (Latest)
  • v3 (Legacy)
User Guide
API ReferenceMCPPlatforms
User Guide
API ReferenceMCPPlatforms
Website
v4 (Latest)
  • v4 (Latest)
  • v3 (Legacy)
v4 (Latest)
  • v4 (Latest)
  • v3 (Legacy)
  1. Webhooks
  • Getting Started
    • On-premise systems
    • Authentication
    • Testing with API Tools
    • Account setup
    • Connection Credits
  • Core Concepts
    • Connections
    • Unified Data Model
    • Custom mappings
    • Data mappings
    • Sync schedules and history
  • Admin API
  • Account & Team
    • Team access and SSO
  • Makini Link
    • Embedded connection settings
    • Launching Makini Link
    • Magic links
  • Management API
    • Management API authentication
    • Managing connections
    • Managing your application
  • Webhooks
    • Signatures and retries
    • Webhook events
  • Working with the API
    • Access tokens
    • Errors
    • Filtering
    • Makini Query Language
    • Raw data and passthrough
    • Reading data
    • Relations and expand
    • Writing data
  1. Webhooks

Verifying webhooks

Every webhook Makini sends is signed with your endpoint's secret and retried on your schedule. This page shows how to verify a delivery, reject replays, handle duplicates and pick a retry policy.

What each delivery carries#

Makini sends a POST with a JSON body and these headers:
HeaderValue
Content-Typeapplication/json
User-Agentmakini-webhooks/1.0
X-Makini-EventThe event name, such as sync.completed.
X-Makini-DeliveryThe delivery id. Identical on every retry, and equal to the body's id.
X-Makini-TimestampUnix time in seconds when this attempt was signed.
X-Makini-Signaturesha256= followed by the hex HMAC-SHA256 of <timestamp>.<raw body>.
X-Makini-AttemptThe attempt number, starting at 1.

The signing secret#

Makini generates a secret when you add a webhook and shows it once. It starts with whsec_. Use the whole string, prefix included, as the HMAC key, exactly as shown: don't decode it. Keep it in your secret manager, never in source control.

Verify the signature#

1
Read the raw body
Take the request body as raw bytes, before any JSON parsing. Parsing and re-serializing changes the bytes and breaks the signature.
2
Build the signed string
Join the X-Makini-Timestamp header, a period, and the raw body: <timestamp>.<raw body>.
3
Compute and compare
Compute HMAC-SHA256 of that string with your secret, hex-encode it, and prefix sha256=. Compare it with X-Makini-Signature using a constant-time comparison.
4
Check the timestamp
Reject the request if the timestamp is more than five minutes away from your clock.
Node.js
Python
Go

Reject replays#

The timestamp is part of the signed string, so nobody can change it without breaking the signature. Rejecting old timestamps stops a captured request from being replayed later. Five minutes is a good window.
Makini signs every attempt afresh with a new timestamp, so retries always pass a tight window. Keep your server clock synced with NTP.

Handle duplicates and order#

Delivery is at least once: in rare cases, such as a timeout after you already processed a request, the same delivery arrives again. Deduplicate on X-Makini-Delivery:
Record each delivery id once you've processed it, and skip ids you've already seen.
Keep ids for at least 24 hours. That's the longest Makini keeps retrying a delivery.
Makini delivers in parallel, so events can arrive out of order. Order by occurredAt, or by each record's updatedAt, rather than by arrival.

Answer fast#

Return any 2xx within 10 seconds. Do the real work after you respond: put the event on a queue and answer 200. Makini ignores the response body.
Your responseWhat Makini does
2xxDelivered.
429 or 5xxRetries on your policy.
No answer within 10 seconds, or no connectionRetries on your policy.
3xxFinal. Redirects are not followed, so register the final URL.
Any other 4xxFinal. Retrying would get the same answer.
Makini also re-checks your URL before every attempt and never sends to a private or reserved network address.

Retry policies#

Choose a policy per webhook, under Delivery → Retry policy:
PolicyAttemptsWaits between attemptsCovers
No retry1NoneOne attempt
Standard (default)530 s, 1 min, 2 min, 4 minAbout 7 minutes
Extended81, 2, 4, 8, 16, 32, 60 minAbout 2 hours
Custom1 to 10Your choiceYour choice
A Custom policy takes three settings:
Max attempts: 1 to 10, counting the first delivery.
Initial delay: 1 to 3,600 seconds before the first retry.
Backoff: Exponential (the wait doubles each time), Linear (the wait grows by the initial delay each time) or Fixed (the same wait every time).
Every wait is capped at one hour, and a delivery that is still pending 24 hours after its event is closed as abandoned. A policy change applies to new events: deliveries already queued keep the schedule they started with.
Pick Extended for receivers with maintenance windows. Pair any policy with the updatedSince read described in Webhook events, and a long outage on your side never loses a change.

The delivery log#

Monitoring → Webhook logs lists every delivery with its event, endpoint, status, attempts and time. Filter by status or endpoint.
StatusMeaning
QueuedWaiting for its first attempt.
Retrying (2/5)An attempt failed and more are scheduled.
Delivered 200Your endpoint accepted it, with the status it returned.
Failed 404Final: a non-retryable answer, or the last attempt failed. Shows the last status, timeout or error.
AbandonedStill pending 24 hours after the event.
The log keeps 30 days of deliveries. Each webhook's card under Settings → Webhooks also shows its latest result at a glance.
Access to the log is a permission of its own, so support staff can check deliveries without seeing your endpoint settings.

Troubleshooting#

The signature never matches.
Deliveries fail with a 3xx status.
Deliveries fail with 401 or 403 before my code runs.
The URL is refused when I save it.
Modified at 2026-10-16 14:20:56
Previous
Managing your application
Next
Webhook events
Built with