Published: July 16, 2026
Webhooks let Maildroppa notify another application when something important happens in your account.
Instead of repeatedly asking Maildroppa whether a subscriber was created, updated, unsubscribed, or assigned a tag, your application can receive an HTTPS request shortly after the event occurs.
The Webhooks page is the central place for this account-wide integration. You can create several endpoints, choose the events each endpoint receives, add authentication headers, test the connection, inspect delivery attempts, and replay a production event when necessary.
An account webhook follows this process:
POST request to the saved endpoint URL.If several endpoints subscribe to the same event, each endpoint receives its own delivery. The business event has the same Event ID for all of them, while every delivery has its own Delivery ID.
Account webhooks are different from a “Send a webhook” step inside an Automation. Account webhooks listen for selected account events across Maildroppa. An Automation webhook is sent only when a subscriber reaches that particular step. Both use the account's webhook Signing secret, so rotating the secret affects every outgoing webhook receiver that verifies Maildroppa signatures.
Open “Settings”, expand “Developers”, and select “Webhooks”.
The page contains three main areas:
When you have more than one endpoint, select an endpoint row to display its Delivery history. If you have not selected one explicitly, Maildroppa shows the history of the first endpoint in the list.
Prepare a receiver on your server before configuring Maildroppa. The receiver should:
POST requests with an application/json body.2xx status only after the event has been accepted safely.A reliable pattern is to verify the request, store the Event ID and payload in a durable queue or database, return 200 or 204, and process the business action afterward.
Do not expose a development computer, local network address, or unprotected script as a production webhook receiver. Maildroppa accepts only public HTTPS targets and checks the destination again when a delivery is sent.
Every Maildroppa webhook request is signed. Your receiver uses the Signing secret to verify that the request was created by Maildroppa and that the body was not changed in transit.
At the top of the page, the Signing secret panel shows one of these states:
Click “Generate secret” when the status is Missing.
Maildroppa displays the new secret immediately. It begins with whsec_. Click “Copy” and store it in the secret manager or protected environment configuration used by your receiver.
The complete value is shown only immediately after generation or rotation. When you reload or leave the page, Maildroppa shows only that a secret exists and when it was last updated. It does not reveal the stored secret again.
If the receiver no longer has the current secret, click “Rotate secret” and save the newly displayed value.
Rotation replaces the previous secret immediately. Maildroppa does not retain both values for a transition period. Update every receiver that uses this account secret before sending further tests or relying on production deliveries.
New deliveries, scheduled retries, tests, and replays are signed with the current secret at the time of the HTTP request. This means that a delivery created before rotation can still be signed with the new secret when it is attempted afterward.
Do not place the Signing secret in browser code, a public repository, a URL, an error page, or an ordinary application log.
Only the server-side receiver needs the secret. If you believe it has been exposed, rotate it and update all receivers immediately.
Each request contains these Maildroppa headers:
X-Maildroppa-Event-Id — Identifies the business event.X-Maildroppa-Delivery-Id — Identifies this particular delivery.X-Maildroppa-Timestamp — The signing time as Unix seconds.X-Maildroppa-Signature — The versioned HMAC signature.Maildroppa also sends:
Content-Type: application/jsonUser-Agent: Maildroppa-Webhooks/1.0The signature has this format:
v1=<lowercase hexadecimal HMAC>
Maildroppa creates it with HMAC-SHA256. The signed content is the timestamp, followed by a period, followed by the exact raw JSON request body:
<timestamp>.<raw request body>
Use the Signing secret as the HMAC key.
The following Node.js example shows the essential verification step. rawBody must be the original request bytes, not JSON that has already been parsed and serialized again.
import crypto from 'node:crypto';
export function verifyMaildroppaWebhook({ rawBody, timestamp, signature, signingSecret }) {
const signedPayload = Buffer.concat([Buffer.from(`${timestamp}.`, 'utf8'), rawBody]);
const expectedSignature = `v1=${crypto
.createHmac('sha256', signingSecret)
.update(signedPayload)
.digest('hex')}`;
const received = Buffer.from(signature, 'utf8');
const expected = Buffer.from(expectedSignature, 'utf8');
return received.length === expected.length && crypto.timingSafeEqual(received, expected);
}
After verifying the signature, also compare the timestamp with your server time. Reject requests outside a short tolerance chosen for your infrastructure, such as five minutes. This reduces the risk that a captured valid request is replayed much later.
Only parse and process the JSON after both checks have passed.
A signature usually fails for one of these reasons:
<timestamp>..v1= prefix is omitted from the comparison.Log the Event ID and Delivery ID when verification fails, but never log the Signing secret or sensitive custom header values.
Click “Add endpoint” in the Endpoints section.
The editor contains four parts:
New endpoints start as Active, and all events shown in the editor are selected initially. Review the selection before saving so the receiver gets only the notifications it actually needs.
Enter the complete public URL that should receive Maildroppa requests, for example:
https://integrations.example.com/webhooks/maildroppa
The URL must meet these requirements:
https://.{ or }.#.443.localhost, a raw IP address, or a hostname that resolves to a blocked private or reserved network.Query parameters are supported, but do not put API keys or other secrets in the URL. URLs are visible in the endpoint list and delivery data. Use a Custom header for credentials instead.
Maildroppa does not follow redirects. Save the final HTTPS destination rather than a URL that returns 301, 302, 307, or 308.
The destination hostname is resolved again before sending. A hostname that later resolves to a private or blocked address is rejected even if it was valid when the endpoint was saved.
Select at least one event. An endpoint receives only the event types selected in its editor.
The page offers these event choices:
subscriber.createdSent when a subscriber is created in the Maildroppa account.
Use this event to create the corresponding contact in a CRM, customer data platform, internal database, or another permission-aware system.
Do not interpret this event as proof that every signup has completed Double Opt-in. The subscriber status in the payload describes the current state.
subscriber.updatedSent when built-in subscriber information or custom field values change.
Use the complete subscriber object in the payload as the current Maildroppa representation. Avoid assuming that only one particular property changed.
Tag assignments and removals have their own event types so they can be handled separately.
subscriber.unsubscribedSent when the subscriber moves to the unsubscribed state through an unsubscribe action.
Use this event to suppress the contact in connected systems. Do not automatically resubscribe the person because another system still marks the contact as active.
subscriber.tag_addedSent when a tag is assigned to a subscriber.
The payload contains the subscriber and the tag involved in this particular change.
subscriber.tag_removedSent when a tag is removed from a subscriber.
The payload contains the updated subscriber and the removed tag. The removed tag is provided separately even though it is no longer present in the subscriber's current tags array.
form.submittedSent when a visitor submits a Maildroppa signup form.
Treat this as a form-submission signal, not as confirmation that Double Opt-in has been completed. Any workflow that requires a confirmed subscription must continue to respect the subscriber's current status and the confirmation process.
You can send different events to different systems. For example:
Separate endpoints reduce unnecessary traffic and make failures easier to diagnose. Each endpoint has its own event selection, URL, custom headers, active status, tests, and Delivery history.
Custom headers are optional. Use them when the receiver requires an API key, bearer token, tenant identifier, or another fixed header.
Click “Add header”, then enter the Header name and Header value. Suitable examples include:
Authorization: Bearer your-token
X-Integration-Key: your-secret-key
You can add up to 20 custom headers.
Header names:
Header values:
The following names are reserved and cannot be replaced by a custom header:
Content-TypeContent-LengthHostUser-AgentX-Maildroppa-This prevents a custom value from replacing Maildroppa's delivery and signature headers.
Maildroppa encrypts custom header values before storing them. Saved values are not returned to the browser in readable form.
When you edit the endpoint later, the value field shows “Stored value kept”. Leave it empty when the existing secret should remain unchanged. Enter a new value to replace it.
If you change the header name, enter the value again. Maildroppa keeps a stored secret only while its original header name remains unchanged.
Removing a header row removes that header from future deliveries after the endpoint is saved.
Custom header values are treated as sensitive in stored request information. They are masked rather than displayed in Delivery history.
Leave “Active” selected when the endpoint is ready to receive events immediately.
Clear it when you want to save the configuration without starting deliveries. You can activate the endpoint later from the endpoint list.
An inactive endpoint:
Activating an endpoint does not backfill events that occurred while it was inactive.
Click “Save” when the URL, event selection, headers, and status are correct.
Each endpoint row shows:
The available actions are:
Select the main part of a row to open that endpoint's Delivery history below the list.
An account event creates a delivery with a snapshot of the endpoint URL, payload, and custom headers at that time.
Editing the URL or custom headers affects newly created deliveries. A delivery that was already queued keeps its original destination and stored header configuration.
Changing the selected events also affects only events that occur afterward. Maildroppa does not create deliveries retroactively for event types that were not selected when the event occurred.
The Signing secret is different: it is read when the HTTP request is prepared. A pending delivery or replay can therefore use a newly rotated Signing secret even when its payload and endpoint snapshot were created earlier.
Click “Test” on an active endpoint after the receiver and Signing secret are ready.
Maildroppa immediately sends one signed request using the saved endpoint URL and saved custom headers. Unsaved changes in an open editor are not part of the test.
The test payload uses the event type webhook.test and sets livemode to false:
{
"id": "evt_test_example",
"type": "webhook.test",
"schema_version": "1",
"created_at": "2026-07-16T10:30:00Z",
"livemode": false,
"data": {
"message": "This is a test webhook from Maildroppa."
}
}
The generated IDs and timestamp are different for every real test.
A test makes exactly one HTTP attempt. Test deliveries are not placed on the production retry schedule and cannot be replayed.
After the request finishes, the result panel shows:
The test also appears in Delivery history with a Test badge. Use the “Test” filter to show only test requests.
Production account events use a common JSON envelope:
{
"id": "evt_example",
"type": "subscriber.created",
"schema_version": "1",
"created_at": "2026-07-16T10:30:00Z",
"livemode": true,
"data": {}
}
The top-level properties mean:
id — The Event ID. It matches X-Maildroppa-Event-Id.type — The event key selected in the endpoint editor.schema_version — The payload schema version. Use it when deciding how to parse the event.created_at — The time the event payload was created, in UTC.livemode — true for production events and false for test events.data — The event-specific content.Route events by the exact type value. Ignore additional properties your integration does not need so compatible payload additions do not break the receiver.
Subscriber events contain the current subscriber representation inside data.subscriber:
{
"id": "evt_example",
"type": "subscriber.updated",
"schema_version": "1",
"created_at": "2026-07-16T10:30:00Z",
"livemode": true,
"data": {
"subscriber": {
"id": "7f49d0e9-77d6-4c24-8b90-12c9d53d82cc",
"email": "alex@example.com",
"first_name": "Alex",
"status": "active",
"registered_at": "2026-07-15T08:15:00Z",
"fields": [
{
"id": "b6594e58-0c4b-4138-9ad8-fc4747e076eb",
"personalization_tag_name": "company",
"value": "Example Ltd."
}
],
"tags": [
{
"id": "c69af5de-39d3-42a4-8f55-ddf86d10a51c",
"name": "Customers"
}
]
}
}
}
fields and tags are arrays. They can be empty. A subscriber property can also be null when no value exists, so your receiver should follow the payload schema instead of assuming every optional profile value is present.
Tag events contain both the subscriber and the tag that caused the event:
{
"id": "evt_example",
"type": "subscriber.tag_added",
"schema_version": "1",
"created_at": "2026-07-16T10:30:00Z",
"livemode": true,
"data": {
"subscriber": {
"id": "7f49d0e9-77d6-4c24-8b90-12c9d53d82cc",
"email": "alex@example.com",
"first_name": "Alex",
"status": "active",
"registered_at": "2026-07-15T08:15:00Z",
"fields": [],
"tags": []
},
"tag": {
"id": "c69af5de-39d3-42a4-8f55-ddf86d10a51c",
"name": "Customers"
}
}
}
For subscriber.tag_removed, data.tag still identifies the removed tag even though the subscriber's current tags array no longer contains it.
The Event ID and Delivery ID serve different purposes.
The Event ID identifies the business event. It appears in:
id property.X-Maildroppa-Event-Id request header.The same event can be sent to several subscribed endpoints. Those deliveries share the Event ID.
Retries and manual replays also retain the original Event ID. Store processed Event IDs and make the business action idempotent so a repeated request does not create duplicate contacts, repeat an irreversible action, or apply the same change twice.
The Delivery ID identifies one delivery record. It appears in:
X-Maildroppa-Delivery-Id request header.Each endpoint delivery has its own Delivery ID. A manual replay creates a new Delivery ID while preserving the original Event ID.
Use the Delivery ID for technical tracing and support. Use the Event ID for business-level deduplication.
Maildroppa classifies responses as follows:
2xx response marks the delivery as successful.408 Request Timeout, 429 Too Many Requests, and 5xx responses are temporary failures and can be retried.3xx responses are not followed and are treated as terminal failures.4xx responses are treated as terminal failures and are not retried.Return 200, 202, or 204 only when the event has been accepted safely. If processing takes time, store the event first and return a success response before doing the slower work asynchronously.
Do not return a redirect to another webhook URL. Configure the final URL in Maildroppa instead.
Production deliveries can make up to seven HTTP attempts.
After a retryable failure, Maildroppa schedules the next attempt with these delays:
If attempt 7 still receives a retryable failure, the delivery becomes Dead and no further automatic attempt is scheduled.
The schedule is measured from the individual failed attempts. Actual delivery time can be slightly later because deliveries are processed asynchronously and are also subject to system protection limits.
Fix a temporary receiver problem before the displayed “Next retry” time whenever possible. If the automatic attempts have ended, use Replay after the receiver is healthy again.
Delivery history belongs to the currently selected endpoint. The endpoint URL appears in the section header so you can confirm which history you are viewing.
Use these filters:
Click “Refresh” to retrieve the latest state. The history does not need to be left open while Maildroppa sends or retries a delivery.
The page shows the latest 50 matching deliveries for the selected filter.
Each row contains:
If no HTTP request was made, the HTTP column shows “No HTTP attempt”. This can happen when Maildroppa rejects the request before sending, for example because the Signing secret is missing or the saved destination can no longer be used safely.
When available, the row also shows an Error and a Response excerpt returned by the receiver. Do not return secrets or sensitive personal data in a webhook response body because part of that response can appear in the account's delivery log.
Pending means that the delivery is waiting for its first attempt or a scheduled retry. “Next retry” appears when another attempt has been scheduled.
Success means that the receiver returned a 2xx response. No further automatic attempt is required.
Failed means that the delivery ended with a non-retryable problem, was rejected before an HTTP attempt, or was stopped before it could be sent.
Dead means that all automatic attempts for a retryable problem were used without receiving a successful response.
Delivery records are retained for a limited time:
Keep your own integration logs when you need a longer audit history. Store Event IDs and Delivery IDs, but avoid storing secrets unnecessarily.
Click “Replay” when a completed production delivery should be attempted again.
Replay is available for production deliveries in Success, Failed, or Dead state. It is not available while a delivery is Pending, and test deliveries cannot be replayed.
A replay:
Replay does not rebuild the payload from the subscriber's current data. It re-sends the original event snapshot. This makes the replay auditable and prevents a historical event from silently changing meaning.
Only one replay of the same source delivery can be Pending at a time. Wait until that replay finishes before requesting another one.
Make sure the endpoint is Active before replaying. If the endpoint is inactive, the queued replay cannot be delivered successfully.
Because a receiver may have completed the business action even when Maildroppa did not receive its success response, replay can produce a duplicate request. Event ID deduplication protects the connected system from repeating the action.
Click “Edit” to change the URL, event selection, custom headers, or active status.
Before saving:
Remember that queued deliveries retain their existing URL and custom header snapshot. Test the new configuration for future deliveries rather than assuming it changes an older queued request.
Use the On/Off switch when you want to pause an integration without deleting its configuration and history.
When an endpoint is turned Off:
A request already in progress at the moment of deactivation can still finish. Check Delivery history after switching the endpoint Off if this distinction matters to your integration.
Events missed while the endpoint is inactive are not backfilled when you turn it On again.
Click “Delete” and confirm the warning when the endpoint should no longer exist.
Deleting removes the endpoint from the page, stops future event deliveries, and fails pending deliveries that were not already claimed for sending.
Delete is not a way to pause temporarily. Use the On/Off switch when you may need the configuration or its visible history again.
Before deletion, record any Event IDs or Delivery IDs you still need for your integration audit.
Check that:
https://.Test is available only for an Active endpoint. Turn the endpoint On or edit it and select “Active”, then save before testing.
Generate a Signing secret if the status is Missing. Also check whether the destination hostname is public and still resolves correctly.
A request can be rejected before sending when its secret, URL, custom headers, or destination safety check is invalid.
401 or 403Check the saved Custom header name and credential. Edit the endpoint and enter the value again if it has changed.
Also verify that the receiver is not confusing its own API credential with the Maildroppa signature. A Custom authorization header and X-Maildroppa-Signature serve different purposes and can be checked independently.
Maildroppa does not follow redirects. Replace the endpoint URL with the final public HTTPS URL and test again.
Confirm that the receiver:
X-Maildroppa-Timestamp value.<timestamp>.<raw request body>.v1=.This can happen after a network interruption, retry, or manual replay. It is normal for webhook delivery systems to provide at-least-once delivery rather than exactly-once delivery.
Use the Event ID as an idempotency key. Return a 2xx response when an already processed Event ID is received again and no additional action is needed.
Look at “Next retry” in the HTTP column. A retryable 408, 429, 5xx, or temporary network failure remains Pending until the next scheduled attempt.
Click “Refresh” after the retry time to load the latest state.
All automatic attempts were used. Fix the receiver first, make sure the endpoint is Active, send a Test webhook, and then use Replay on the production delivery.
Before relying on an endpoint in production, confirm all of the following:
2xx response is returned only for accepted events.With these safeguards in place, the Webhooks page provides both sides of a reliable integration: secure event delivery to your application and a clear operational history inside Maildroppa.
Helping founders and creators grow through easy, effective email marketing.