eventData varies by event type.
Webhook envelope
Every delivery uses this envelope structure:Envelope structure and field reference
Envelope structure and field reference
| Field | Type | Description |
|---|---|---|
| eventId | string | Unique per delivery — use for idempotency / deduplication |
| webhookId | string | The subscription ID that triggered this delivery |
| eventType | string | Dot-notation event name (e.g. campaign.created) |
| orgId | string | Organization ID the event belongs to |
| userId | string | User ID who triggered the action |
| eventData | object | Event-specific payload — schema is fixed per eventType |
| resourceId | object | Primary resource: resource (campaign | recipient) and resourceId |
Supported event types
| # | Event Type | Resource | Description |
|---|---|---|---|
| 1 | campaign.created | campaign | A new campaign was created |
| 2 | campaign.updated | campaign | Campaign fields were modified |
| 3 | campaign.status_changed | campaign | Campaign status transitioned |
| 4 | campaign.deleted | campaign | Campaign was deleted |
| 5 | campaign.recipients_added | campaign | Recipients were added to a campaign |
| 6 | recipient.created | recipient | A new recipient was added |
| 7 | recipient.status_changed | recipient | Recipient status transitioned |
| 8 | recipient.email_sent | recipient | An email was sent to a recipient |
| 9 | recipient.feedback_submitted | recipient | Recipient submitted feedback |
Campaign events
Schema and examples for campaign lifecycle events.
Recipient events
Schema and examples for recipient and delivery events.
Campaign events
campaign.created
campaign.created
Fired when a new campaign is created.
Example:
eventData schema:| Field | Type | Required | Description |
|---|---|---|---|
| campaignId | string | yes | Campaign ID |
| name | string | yes | Campaign name |
| description | string | no | Campaign description |
| status | string | yes | e.g. draft, preparing, live, completed |
| createdBy | string | yes | User ID of creator |
| createdAt | string (ISO 8601) | no | Creation timestamp |
| goal | object | no | { goalId, name } |
| motion | object | no | { motionId, name } |
| budget | object | no | { totalAmount, currency } |
| target_recipient_count | number | yes | Target/expected recipient count |
| recipient_in_camp | number | yes | Actual count |
| recipient_details | array | yes | [{ fname, lname, email }] |
campaign.updated
campaign.updated
Fired when one or more campaign fields are modified.
Example:
eventData schema:| Field | Type | Required | Description |
|---|---|---|---|
| campaignId | string | yes | Campaign ID |
| name | string | no | Current name |
| description | string | no | Current description |
| status | string | yes | Current status |
| lastUpdatedBy | string | no | User ID who performed update |
| updatedAt | string (ISO 8601) | no | Update timestamp |
| goal | object | no | { goalId, name } |
| motion | object | no | { motionId, name } |
| budget | object | no | { totalAmount, currency } |
| fieldChanges | array | yes | [{ field, previousValue, newValue }] |
campaign.status_changed
campaign.status_changed
Fired when a campaign transitions from one status to another.
Example:
eventData schema:| Field | Type | Required | Description |
|---|---|---|---|
| campaignId | string | yes | Campaign ID |
| name | string | yes | Campaign name |
| previousStatus | string | yes | Status before change |
| currentStatus | string | yes | Status after change |
| statusChangedBy | string | yes | User ID who changed status |
| statusChangedAt | string (ISO 8601) | yes | When status changed |
campaign.deleted
campaign.deleted
Fired when a campaign is deleted.
Example:
eventData schema:| Field | Type | Required | Description |
|---|---|---|---|
| campaignId | string | yes | Campaign ID |
| name | string | no | Campaign name at delete time |
| status | string | yes | Status at delete time |
| deletedBy | string | no | User ID who deleted |
| deletedAt | string (ISO 8601) | yes | When deleted |
campaign.recipients_added
campaign.recipients_added
Fired when recipients are added to a campaign (manually, bulk upload, or booth QR).
Example:
eventData schema:| Field | Type | Required | Description |
|---|---|---|---|
| campaignId | string | yes | Campaign ID |
| campaignName | string | no | Campaign name |
| campaignStatus | string | yes | Current campaign status |
| recipientsAdded.count | number | yes | Number of recipients added |
| recipientsAdded.recipientIds | string[] | no | IDs of added recipients |
| recipientsAdded.recipient_details | array | no | [{ fname, lname, email }] |
| recipientsAdded.addedBy | string | no | User ID who added |
| recipientsAdded.addedAt | string (ISO 8601) | yes | When recipients were added |
Recipient events
recipient.created
recipient.created
Fired when a new recipient is added to a campaign.
eventData schema:| Field | Type | Required | Description |
|---|---|---|---|
| recipientId | string | yes | Recipient ID |
| campaignId | string | yes | Campaign ID |
| contactDetails | object | yes | { firstName, lastName, email } |
| sourceType | string | yes | How added: manual, bulk, booth, etc. |
| status | string | yes | Initial status (e.g. draft) |
| gift | object | no | Gift data: gifts[], giftBudget, giftExpirationDate, giftMode, selectedCatalogId |
| createdAt | string (ISO 8601) | yes | When the recipient was created |
eventData.gift.gifts[] (each item): id, name, description, imageUrl, price, currency, budgetExample (single gift):recipient.status_changed
recipient.status_changed
Fired when a recipient’s status transitions (e.g.
Example (status →
draft → invite_sent → address_confirmed → in_transit → delivered).eventData schema:| Field | Type | Required | Description |
|---|---|---|---|
| recipientId | string | yes | Recipient ID |
| campaignId | string | yes | Campaign ID |
| previousStatus | string | yes | Status before change |
| currentStatus | string | yes | Status after change |
| statusChangedAt | string (ISO 8601) | yes | When status changed |
| contactDetails | object | no | { firstName, lastName, email } |
| shipmentInfo | object | no | Shipment details (no status field) |
| carrierDetails | object | no | When currentStatus is in_transit: { name, trackingId, trackingUrl } |
in_transit):recipient.email_sent
recipient.email_sent
Fired when any email is sent to a recipient (invite, confirmation, reminder, etc.).
Example:
eventData schema:| Field | Type | Required | Description |
|---|---|---|---|
| recipientId | string | yes | Recipient ID |
| campaignId | string | yes | Campaign ID |
| contactDetails | object | yes | { firstName, lastName, email } |
| emailType | string | yes | e.g. invite_sent, address_confirmed, reminder |
| sentAt | string (ISO 8601) | yes | When email was sent |
recipient.feedback_submitted
recipient.feedback_submitted
Fired when a recipient submits feedback (rating, text, video, or audio).
Example (rating + text):
eventData schema:| Field | Type | Required | Description |
|---|---|---|---|
| recipientId | string | yes | Recipient ID |
| campaignId | string | yes | Campaign ID |
| contactDetails | object | yes | { firstName, lastName, email } |
| feedback.rating | object | no | { value: "like" | "dislike", submittedAt } |
| feedback.message | object | no | { type: "video" | "audio" | "text", url?, text?, submittedAt } |
| submittedAt | string (ISO 8601) | yes | When feedback was submitted |
Important notes
- All timestamps are ISO 8601 in UTC.
carrierDetailsappears onrecipient.status_changedonly whencurrentStatusisin_transit.feedback.rating.valueis"like"or"dislike".feedback.message.typeis"video","audio", or"text".
Need help? Visit the support portal or contact DelightLoop support.

