Reference
Webhook events
The 11 webhook event types, with their payloads, generated from the OpenAPI document.
11 event types. Each delivery is a Standard Webhooks request with three headers, webhook-id, webhook-timestamp, webhook-signature, and a JSON body of the shape below. Delivered to your endpoint under Standard Webhooks: verify webhook-signature (HMAC-SHA256 over webhook-id, webhook-timestamp and the body with your whsec_ secret) and treat webhook-id as the idempotency key. Any 2xx acknowledges; anything else is retried over 24 hours with backoff.
Every payload carries id (also the webhook-id header, your idempotency key), type, timestamp, api_version and data. Ignore members you do not know: they may appear in a later MyDataHub-Version.
GET /v1/events replays the last 30 days, oldest first, in the same shape. See Webhooks for signing, retries and verification code.
The example payloads are illustrative. Each is checked against its schema when this page is generated.
Event types
| Event | Fires when |
|---|---|
order.ready | Records are available. |
order.failed | Processing failed; credits are refunded. |
audience.refreshed | A saved audience was recounted, with the diff. |
credits.low | The balance crossed the configured threshold. |
credits.topped_up | A top-up settled. |
warranty.replacement_issued | A bounced or job-changed record was replaced, or re-credited. |
suppression.created | An objection reached a record your organisation holds. Suppress it before any send. |
push.completed | A CRM push finished. |
push.partial | A CRM push partly finished; retry the failed records. |
push.failed | A CRM push failed. |
connection.expired | A CRM token failed; reconnect in the app. |
order.ready
Records are available.
Payload: OrderReadyEvent.
| Member | Type | Always present | Description |
|---|---|---|---|
id | string | yes | Also sent as the webhook-id header; your idempotency key. |
type | order.ready | yes | |
timestamp | string (date-time) | yes | |
api_version | string | yes | A dated MyDataHub-Version, such as 2027-01-15. |
data | object | yes | |
data.order_id | string | yes | Format: an order id: ord_ followed by a 26 character ULID in upper case Crockford base32, such as ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E. |
data.records | integer (0 or more) | yes | |
data.records_url | string (uri-reference) | yes | A path on https://mydatahub.emailmovers.com starting /v1/. Resolve it against the origin (RFC 3986), not by appending it to the server URL. |
data.receipt_url | string (uri-reference) | yes | A path on https://mydatahub.emailmovers.com starting /v1/. Resolve it against the origin (RFC 3986), not by appending it to the server URL. |
{
"id": "evt_01JB4NB7T1Y5W8ZAK8Q2V7XN3M",
"type": "order.ready",
"timestamp": "2026-09-26T10:16:04Z",
"api_version": "2027-01-15",
"data": {
"order_id": "ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E",
"records": 5000,
"records_url": "/v1/orders/ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E/records",
"receipt_url": "/v1/orders/ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E/receipt"
}
}order.failed
Processing failed; credits are refunded.
Payload: OrderFailedEvent.
| Member | Type | Always present | Description |
|---|---|---|---|
id | string | yes | Also sent as the webhook-id header; your idempotency key. |
type | order.failed | yes | |
timestamp | string (date-time) | yes | |
api_version | string | yes | A dated MyDataHub-Version, such as 2027-01-15. |
data | object | yes | |
data.order_id | string | yes | Format: an order id: ord_ followed by a 26 character ULID in upper case Crockford base32, such as ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E. |
data.reason | string | yes | |
data.credits_refunded | number (0 or more) | yes | Credits, to one decimal place: whole at 1 credit a record, fractional only where a rule is (0.1 company-only, 1.8 outright, both proposed). |
{
"id": "evt_01JB4NB7T1Y5W8ZAK8Q2V7XN3M",
"type": "order.failed",
"timestamp": "2026-09-26T10:16:04Z",
"api_version": "2027-01-15",
"data": {
"order_id": "ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E",
"reason": "The audience could not be run.",
"credits_refunded": 300
}
}audience.refreshed
A saved audience was recounted, with the diff.
Payload: AudienceRefreshedEvent.
| Member | Type | Always present | Description |
|---|---|---|---|
id | string | yes | Also sent as the webhook-id header; your idempotency key. |
type | audience.refreshed | yes | |
timestamp | string (date-time) | yes | |
api_version | string | yes | A dated MyDataHub-Version, such as 2027-01-15. |
data | AudienceRefresh | yes | A saved audience recounted on the current dataset version, with the difference. |
data.audience_id | string | yes | Format: an audience id: aud_ followed by a 26 character ULID in upper case Crockford base32, such as aud_01JB4H2K9V6XN3M9R6T1Y5W8ZA. |
data.previous | AudienceCountSummary or null | yes | |
data.current | AudienceCountSummary | yes | The headline numbers of one count of an audience. |
data.diff | object | yes |
{
"id": "evt_01JB4NB7T1Y5W8ZAK8Q2V7XN3M",
"type": "audience.refreshed",
"timestamp": "2026-09-26T10:16:04Z",
"api_version": "2027-01-15",
"data": {
"audience_id": "aud_01JB4H2K9V6XN3M9R6T1Y5W8ZA",
"previous": {
"count_id": "cnt_7K2PQ4MAXN3R6TBY5WDZ",
"dataset_version": "2026-W39",
"contacts": 12840,
"companies": 3115,
"emailable": 12310,
"counted_at": "2026-09-26T10:14:00Z"
},
"current": {
"count_id": "cnt_Q3N5X2M7K4P6R2T4V4W6",
"dataset_version": "2026-W40",
"contacts": 13054,
"companies": 3160,
"emailable": 12520,
"counted_at": "2026-10-05T06:00:00Z"
},
"diff": {
"contacts": 214,
"companies": 45,
"emailable": 210,
"new_records": 231,
"removed_records": 17
}
}
}credits.low
The balance crossed the configured threshold.
Payload: CreditsLowEvent.
| Member | Type | Always present | Description |
|---|---|---|---|
id | string | yes | Also sent as the webhook-id header; your idempotency key. |
type | credits.low | yes | |
timestamp | string (date-time) | yes | |
api_version | string | yes | A dated MyDataHub-Version, such as 2027-01-15. |
data | object | yes | |
data.balance | number | yes | |
data.threshold | integer (0 or more) | yes | |
data.top_up_url | string (uri) | yes |
{
"id": "evt_01JB4NB7T1Y5W8ZAK8Q2V7XN3M",
"type": "credits.low",
"timestamp": "2026-09-26T10:16:04Z",
"api_version": "2027-01-15",
"data": {
"balance": 180,
"threshold": 200,
"top_up_url": "https://mydatahub.emailmovers.com/billing/top-up"
}
}credits.topped_up
A top-up settled.
Payload: CreditsToppedUpEvent.
| Member | Type | Always present | Description |
|---|---|---|---|
id | string | yes | Also sent as the webhook-id header; your idempotency key. |
type | credits.topped_up | yes | |
timestamp | string (date-time) | yes | |
api_version | string | yes | A dated MyDataHub-Version, such as 2027-01-15. |
data | object | yes | |
data.credits_added | integer (0 or more) | yes | |
data.balance | number | yes | |
data.source | enum: credit_pack, top_up, plan, refund, adjustment | yes | credit_pack for credit packs bought by card, top_up for credits bought at the per-contact scale (with or without credit packs), plan for a plan's credits, refund or adjustment. |
data.amount_gbp_ex_vat | number (0 or more) or null | yes |
{
"id": "evt_01JB4NB7T1Y5W8ZAK8Q2V7XN3M",
"type": "credits.topped_up",
"timestamp": "2026-09-26T10:16:04Z",
"api_version": "2027-01-15",
"data": {
"credits_added": 40000,
"balance": 41200,
"source": "credit_pack",
"amount_gbp_ex_vat": 1249
}
}warranty.replacement_issued
A bounced or job-changed record was replaced, or re-credited.
Payload: WarrantyReplacementEvent.
| Member | Type | Always present | Description |
|---|---|---|---|
id | string | yes | Also sent as the webhook-id header; your idempotency key. |
type | warranty.replacement_issued | yes | |
timestamp | string (date-time) | yes | |
api_version | string | yes | A dated MyDataHub-Version, such as 2027-01-15. |
data | object | yes | |
data.order_id | string | yes | Format: an order id: ord_ followed by a 26 character ULID in upper case Crockford base32, such as ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E. |
data.retired_record_id | string | yes | Format: a contact id: contact_ followed by a 26 character ULID in upper case Crockford base32, such as contact_01JA9X2V7XN3M9R6T1Y5W8ZAK8. |
data.replacement_record_id | string or null | yes | |
data.reason | enum: hard_bounce, job_change | yes | |
data.credits_refunded | number (0 or more) | yes | Credits, to one decimal place: whole at 1 credit a record, fractional only where a rule is (0.1 company-only, 1.8 outright, both proposed). |
{
"id": "evt_01JB4NB7T1Y5W8ZAK8Q2V7XN3M",
"type": "warranty.replacement_issued",
"timestamp": "2026-09-26T10:16:04Z",
"api_version": "2027-01-15",
"data": {
"order_id": "ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E",
"retired_record_id": "contact_01JA9X2V7XN3M9R6T1Y5W8ZAK8",
"replacement_record_id": null,
"reason": "hard_bounce",
"credits_refunded": 1
}
}suppression.created
An objection reached a record your organisation holds. Suppress it before any send.
Payload: SuppressionCreatedEvent.
| Member | Type | Always present | Description |
|---|---|---|---|
id | string | yes | Also sent as the webhook-id header; your idempotency key. |
type | suppression.created | yes | |
timestamp | string (date-time) | yes | |
api_version | string | yes | A dated MyDataHub-Version, such as 2027-01-15. |
data | SuppressionNotice | yes | A record you hold that is now suppressed, as the suppression.created webhook carries it. |
data.record_id | string | yes | Format: a contact id: contact_ followed by a 26 character ULID in upper case Crockford base32, such as contact_01JA9X2V7XN3M9R6T1Y5W8ZAK8. |
data.reason | enum: none, objected_to_emailmovers, objected_to_licensee, deceased, left_company | yes | |
data.scope | enum: licensee, emailmovers | yes | |
data.suppressed_at | string (date-time) | yes |
{
"id": "evt_01JB4NB7T1Y5W8ZAK8Q2V7XN3M",
"type": "suppression.created",
"timestamp": "2026-09-26T10:16:04Z",
"api_version": "2027-01-15",
"data": {
"record_id": "contact_01JA9X2V7XN3M9R6T1Y5W8ZAK8",
"reason": "objected_to_emailmovers",
"scope": "emailmovers",
"suppressed_at": "2026-10-01T08:30:00Z"
}
}push.completed
A CRM push finished.
Payload: PushCompletedEvent.
| Member | Type | Always present | Description |
|---|---|---|---|
id | string | yes | Also sent as the webhook-id header; your idempotency key. |
type | push.completed | yes | |
timestamp | string (date-time) | yes | |
api_version | string | yes | A dated MyDataHub-Version, such as 2027-01-15. |
data | Push | yes | A CRM push or its dry run, such as 4,102 to create and 0 already in your HubSpot. |
data.id | string | yes | Format: a CRM push id: psh_ followed by a 26 character ULID in upper case Crockford base32, such as psh_01JB4NC3W2X6Y7Z8A1B2C3D4E5. |
data.order_id | string | yes | Format: an order id: ord_ followed by a 26 character ULID in upper case Crockford base32, such as ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E. |
data.connection_id | string | yes | Format: a CRM connection id: conn_ followed by a 26 character ULID in upper case Crockford base32, such as conn_01JB3Y2X6Y7Z8A1B2C3D4E5F6G. |
data.dry_run | boolean | yes | |
data.status | enum: queued, running, completed, partial, failed | yes | |
data.summary | object | yes | |
data.property_group | array of enum: mydatahub_record_id, licence_expires_at, lawful_basis, article14_status, tps_ctps_screened_at, subscriber_class, suppression_status, compliance_receipt_url | yes | The MyDataHub property group written on every record (CrmPropertyGroup). |
data.sample | CrmPropertyGroup or null | yes | On a dry run: the property group the first record would carry. |
data.errors | array of object | yes | |
data.created_at | string (date-time) | yes | |
data.completed_at | string (date-time) or null | yes |
{
"id": "evt_01JB4NB7T1Y5W8ZAK8Q2V7XN3M",
"type": "push.completed",
"timestamp": "2026-09-26T10:16:04Z",
"api_version": "2027-01-15",
"data": {
"id": "psh_01JB4NC3W2X6Y7Z8A1B2C3D4E5",
"order_id": "ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E",
"connection_id": "conn_01JB3Y2X6Y7Z8A1B2C3D4E5F6G",
"dry_run": false,
"status": "completed",
"summary": {
"to_create": 4102,
"to_update": 0,
"already_present": 0,
"skipped": 0,
"failed": 0
},
"property_group": [
"mydatahub_record_id",
"licence_expires_at",
"lawful_basis",
"article14_status",
"tps_ctps_screened_at",
"subscriber_class",
"suppression_status",
"compliance_receipt_url"
],
"sample": {
"mydatahub_record_id": "contact_01JA9X2V7XN3M9R6T1Y5W8ZAK8",
"licence_expires_at": "2027-09-26",
"lawful_basis": "legitimate_interests_art6_1_f",
"article14_status": "notified",
"tps_ctps_screened_at": "2026-09-12",
"subscriber_class": "ltd",
"suppression_status": "none",
"compliance_receipt_url": "https://mydatahub.emailmovers.com/receipts/rcpt_01JB4NA2Q5W8ZAK8Q2V7XN3M9R"
},
"errors": [],
"created_at": "2026-09-26T10:20:00Z",
"completed_at": "2026-09-26T10:20:03Z"
}
}push.partial
A CRM push partly finished; retry the failed records.
Payload: PushPartialEvent.
| Member | Type | Always present | Description |
|---|---|---|---|
id | string | yes | Also sent as the webhook-id header; your idempotency key. |
type | push.partial | yes | |
timestamp | string (date-time) | yes | |
api_version | string | yes | A dated MyDataHub-Version, such as 2027-01-15. |
data | Push | yes | A CRM push or its dry run, such as 4,102 to create and 0 already in your HubSpot. |
data.id | string | yes | Format: a CRM push id: psh_ followed by a 26 character ULID in upper case Crockford base32, such as psh_01JB4NC3W2X6Y7Z8A1B2C3D4E5. |
data.order_id | string | yes | Format: an order id: ord_ followed by a 26 character ULID in upper case Crockford base32, such as ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E. |
data.connection_id | string | yes | Format: a CRM connection id: conn_ followed by a 26 character ULID in upper case Crockford base32, such as conn_01JB3Y2X6Y7Z8A1B2C3D4E5F6G. |
data.dry_run | boolean | yes | |
data.status | enum: queued, running, completed, partial, failed | yes | |
data.summary | object | yes | |
data.property_group | array of enum: mydatahub_record_id, licence_expires_at, lawful_basis, article14_status, tps_ctps_screened_at, subscriber_class, suppression_status, compliance_receipt_url | yes | The MyDataHub property group written on every record (CrmPropertyGroup). |
data.sample | CrmPropertyGroup or null | yes | On a dry run: the property group the first record would carry. |
data.errors | array of object | yes | |
data.created_at | string (date-time) | yes | |
data.completed_at | string (date-time) or null | yes |
{
"id": "evt_01JB4NB7T1Y5W8ZAK8Q2V7XN3M",
"type": "push.partial",
"timestamp": "2026-09-26T10:16:04Z",
"api_version": "2027-01-15",
"data": {
"id": "psh_01JB4NC3W2X6Y7Z8A1B2C3D4E5",
"order_id": "ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E",
"connection_id": "conn_01JB3Y2X6Y7Z8A1B2C3D4E5F6G",
"dry_run": false,
"status": "partial",
"summary": {
"to_create": 4090,
"to_update": 0,
"already_present": 0,
"skipped": 0,
"failed": 12
},
"property_group": [
"mydatahub_record_id",
"licence_expires_at",
"lawful_basis",
"article14_status",
"tps_ctps_screened_at",
"subscriber_class",
"suppression_status",
"compliance_receipt_url"
],
"sample": {
"mydatahub_record_id": "contact_01JA9X2V7XN3M9R6T1Y5W8ZAK8",
"licence_expires_at": "2027-09-26",
"lawful_basis": "legitimate_interests_art6_1_f",
"article14_status": "notified",
"tps_ctps_screened_at": "2026-09-12",
"subscriber_class": "ltd",
"suppression_status": "none",
"compliance_receipt_url": "https://mydatahub.emailmovers.com/receipts/rcpt_01JB4NA2Q5W8ZAK8Q2V7XN3M9R"
},
"errors": [],
"created_at": "2026-09-26T10:20:00Z",
"completed_at": "2026-09-26T10:20:03Z"
}
}push.failed
A CRM push failed.
Payload: PushFailedEvent.
| Member | Type | Always present | Description |
|---|---|---|---|
id | string | yes | Also sent as the webhook-id header; your idempotency key. |
type | push.failed | yes | |
timestamp | string (date-time) | yes | |
api_version | string | yes | A dated MyDataHub-Version, such as 2027-01-15. |
data | Push | yes | A CRM push or its dry run, such as 4,102 to create and 0 already in your HubSpot. |
data.id | string | yes | Format: a CRM push id: psh_ followed by a 26 character ULID in upper case Crockford base32, such as psh_01JB4NC3W2X6Y7Z8A1B2C3D4E5. |
data.order_id | string | yes | Format: an order id: ord_ followed by a 26 character ULID in upper case Crockford base32, such as ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E. |
data.connection_id | string | yes | Format: a CRM connection id: conn_ followed by a 26 character ULID in upper case Crockford base32, such as conn_01JB3Y2X6Y7Z8A1B2C3D4E5F6G. |
data.dry_run | boolean | yes | |
data.status | enum: queued, running, completed, partial, failed | yes | |
data.summary | object | yes | |
data.property_group | array of enum: mydatahub_record_id, licence_expires_at, lawful_basis, article14_status, tps_ctps_screened_at, subscriber_class, suppression_status, compliance_receipt_url | yes | The MyDataHub property group written on every record (CrmPropertyGroup). |
data.sample | CrmPropertyGroup or null | yes | On a dry run: the property group the first record would carry. |
data.errors | array of object | yes | |
data.created_at | string (date-time) | yes | |
data.completed_at | string (date-time) or null | yes |
{
"id": "evt_01JB4NB7T1Y5W8ZAK8Q2V7XN3M",
"type": "push.failed",
"timestamp": "2026-09-26T10:16:04Z",
"api_version": "2027-01-15",
"data": {
"id": "psh_01JB4NC3W2X6Y7Z8A1B2C3D4E5",
"order_id": "ord_01JB4N9S3W2X6Y7Z8A1B2C3D4E",
"connection_id": "conn_01JB3Y2X6Y7Z8A1B2C3D4E5F6G",
"dry_run": false,
"status": "failed",
"summary": {
"to_create": 0,
"to_update": 0,
"already_present": 0,
"skipped": 0,
"failed": 4102
},
"property_group": [
"mydatahub_record_id",
"licence_expires_at",
"lawful_basis",
"article14_status",
"tps_ctps_screened_at",
"subscriber_class",
"suppression_status",
"compliance_receipt_url"
],
"sample": {
"mydatahub_record_id": "contact_01JA9X2V7XN3M9R6T1Y5W8ZAK8",
"licence_expires_at": "2027-09-26",
"lawful_basis": "legitimate_interests_art6_1_f",
"article14_status": "notified",
"tps_ctps_screened_at": "2026-09-12",
"subscriber_class": "ltd",
"suppression_status": "none",
"compliance_receipt_url": "https://mydatahub.emailmovers.com/receipts/rcpt_01JB4NA2Q5W8ZAK8Q2V7XN3M9R"
},
"errors": [],
"created_at": "2026-09-26T10:20:00Z",
"completed_at": "2026-09-26T10:20:03Z"
}
}connection.expired
A CRM token failed; reconnect in the app.
Payload: ConnectionExpiredEvent.
| Member | Type | Always present | Description |
|---|---|---|---|
id | string | yes | Also sent as the webhook-id header; your idempotency key. |
type | connection.expired | yes | |
timestamp | string (date-time) | yes | |
api_version | string | yes | A dated MyDataHub-Version, such as 2027-01-15. |
data | object | yes | |
data.connection_id | string | yes | Format: a CRM connection id: conn_ followed by a 26 character ULID in upper case Crockford base32, such as conn_01JB3Y2X6Y7Z8A1B2C3D4E5F6G. |
data.provider | string | yes | |
data.reconnect_url | string (uri) | yes |
{
"id": "evt_01JB4NB7T1Y5W8ZAK8Q2V7XN3M",
"type": "connection.expired",
"timestamp": "2026-09-26T10:16:04Z",
"api_version": "2027-01-15",
"data": {
"connection_id": "conn_01JB3Y2X6Y7Z8A1B2C3D4E5F6G",
"provider": "hubspot",
"reconnect_url": "https://mydatahub.emailmovers.com/api-keys"
}
}