Skip to main content

Managing Webhooks

Use webhooks to receive near real-time notifications when account events happen in ValueMapper.

Prerequisites

Before creating webhooks, make sure you have:

  • Completed authentication
  • A public HTTPS endpoint that can accept POST requests
note

Webhook URLs must use https://. Non-HTTPS URLs are rejected.

Supported Events

When creating a webhook, subscribe to one or more WebhookEventType values:

  • CONTACT_CREATED
  • CONTACT_DELETED
  • REDEMPTION_CODE_CREATED
  • REDEMPTION_CODE_REDEEMED
  • WALLET_CREDIT_ADDED
  • WALLET_CREDIT_SPENT
  • WALLET_CREDIT_REMOVED
  • WALLET_CREDIT_CONVERTED

Event Payloads

Every delivery shares the same top-level envelope:

{
"id": "evt_3f2504e0-4f89-11d3-9a0c-0305e82c3301",
"type": "contact.created",
"timestamp": "2025-04-16T21:33:00.000Z",
"account_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"data": { ... }
}
FieldTypeDescription
idstringUnique event ID prefixed with evt_
typestringEvent type string (see below)
timestampstringISO 8601 UTC timestamp of the event
account_uuidstringUUID of the account that generated the event
dataobjectEvent-specific payload (see examples below)

contact.created

Fired when a new contact is created.

{
"id": "evt_3f2504e0-4f89-11d3-9a0c-0305e82c3301",
"type": "contact.created",
"timestamp": "2025-04-16T21:33:00.000Z",
"account_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"data": {
"contact": {
"uuid": "c1d2e3f4-0000-0000-0000-000000000001",
"email": "jane@example.com",
"name": "Jane Smith",
"phone": "+15550001234"
}
}
}

contact.deleted

Fired when a contact is deleted.

{
"id": "evt_3f2504e0-4f89-11d3-9a0c-0305e82c3302",
"type": "contact.deleted",
"timestamp": "2025-04-16T21:34:00.000Z",
"account_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"data": {
"contact": {
"uuid": "c1d2e3f4-0000-0000-0000-000000000001",
"email": "jane@example.com",
"name": "Jane Smith",
"phone": "+15550001234"
}
}
}

redemption_code.created

Fired when a redemption code is issued. recipientEmail and recipientPhone are null when no recipient was specified.

{
"id": "evt_3f2504e0-4f89-11d3-9a0c-0305e82c3303",
"type": "redemption_code.created",
"timestamp": "2025-04-16T21:35:00.000Z",
"account_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"data": {
"redemptionCode": {
"uuid": "r1d2e3f4-0000-0000-0000-000000000001",
"code": "SUMMER20",
"redeemed": false,
"externalId": "shopify-price-rule-123",
"recipientEmail": "jane@example.com",
"recipientPhone": null
}
}
}

redemption_code.redeemed

Fired when a redemption code is marked as redeemed.

{
"id": "evt_3f2504e0-4f89-11d3-9a0c-0305e82c3304",
"type": "redemption_code.redeemed",
"timestamp": "2025-04-16T21:36:00.000Z",
"account_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"data": {
"redemptionCode": {
"uuid": "r1d2e3f4-0000-0000-0000-000000000001",
"code": "SUMMER20",
"redeemed": true,
"redeemedAt": "2025-04-16T21:36:00.000Z",
"externalId": "shopify-price-rule-123",
"recipientEmail": "jane@example.com",
"recipientPhone": null
}
}
}

wallet.credit_added

Fired when credit is added to a wallet.

{
"id": "evt_3f2504e0-4f89-11d3-9a0c-0305e82c3305",
"type": "wallet.credit_added",
"timestamp": "2025-04-16T21:37:00.000Z",
"account_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"data": {
"wallet": {
"uuid": "w1d2e3f4-0000-0000-0000-000000000001"
},
"creditEntry": {
"uuid": "ce1d2e3f-0000-0000-0000-000000000001",
"action": "ADD",
"creditType": "CREDIT",
"amount": 10.00
}
}
}

wallet.credit_spent

Fired when credit is redeemed/spent from a wallet.

{
"id": "evt_3f2504e0-4f89-11d3-9a0c-0305e82c3306",
"type": "wallet.credit_spent",
"timestamp": "2025-04-16T21:38:00.000Z",
"account_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"data": {
"wallet": {
"uuid": "w1d2e3f4-0000-0000-0000-000000000001"
},
"creditEntry": {
"uuid": "ce1d2e3f-0000-0000-0000-000000000002",
"action": "SPEND",
"creditType": "CREDIT",
"amount": 5.00
}
}
}

wallet.credit_removed

Fired when credit is administratively removed from a wallet.

{
"id": "evt_3f2504e0-4f89-11d3-9a0c-0305e82c3307",
"type": "wallet.credit_removed",
"timestamp": "2025-04-16T21:39:00.000Z",
"account_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"data": {
"wallet": {
"uuid": "w1d2e3f4-0000-0000-0000-000000000001"
},
"creditEntry": {
"uuid": "ce1d2e3f-0000-0000-0000-000000000003",
"action": "REMOVE",
"creditType": "CREDIT",
"amount": 2.50
}
}
}

wallet.credit_converted

Fired when points or another credit type are converted to a different credit type.

{
"id": "evt_3f2504e0-4f89-11d3-9a0c-0305e82c3308",
"type": "wallet.credit_converted",
"timestamp": "2025-04-16T21:40:00.000Z",
"account_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"data": {
"wallet": {
"uuid": "w1d2e3f4-0000-0000-0000-000000000001"
},
"conversion": {
"from": "POINTS",
"to": "CREDIT",
"amount": 100,
"conversionRate": 0.01
},
"creditEntry": {
"uuid": "ce1d2e3f-0000-0000-0000-000000000004",
"action": "ADD",
"creditType": "CREDIT",
"amount": 1.00
}
}
}

Create a Webhook

Use the createWebhook mutation:

mutation CreateWebhook($webhook: CreateWebhookInput!) {
createWebhook(webhook: $webhook) {
success
webhook {
uuid
url
events
enabled
description
createdAt
}
secret
errors
}
}

Variables:

{
"webhook": {
"url": "https://example.com/webhooks/valuemapper",
"events": ["CONTACT_CREATED", "WALLET_CREDIT_ADDED"],
"description": "CRM + wallet sync"
}
}
warning

Save secret immediately. It is returned in plaintext when creating or rotating a webhook secret, and should be stored securely by your system.

List Webhooks

Fetch configured webhooks for your account:

query GetWebhooks {
account {
webhooks {
uuid
url
events
enabled
description
createdAt
updatedAt
}
}
}

Check Webhook Deliveries

Use account.webhookDeliveries to inspect recent delivery attempts for a webhook.

query GetWebhookDeliveries(
$webhookUuid: String!
$limit: Int
$eventType: WebhookEventType
$success: Boolean
) {
account {
webhookDeliveries(
webhookUuid: $webhookUuid
limit: $limit
eventType: $eventType
success: $success
) {
uuid
eventType
statusCode
errorMessage
durationMs
success
attempts
createdAt
}
}
}

Common filters:

  • limit (default 30, max 100)
  • eventType (optional)
  • success (true for successful deliveries, false for failures)

Check Delivery Health

Use account.webhookErrorRate for aggregate delivery health over a rolling window:

query GetWebhookErrorRate($webhookUuid: String!, $windowHours: Int) {
account {
webhookErrorRate(webhookUuid: $webhookUuid, windowHours: $windowHours) {
totalDeliveries
successCount
failureCount
successRate
failureRate
statusCodeBreakdown {
statusCode
count
label
}
}
}
}

windowHours defaults to 24 (max 720).

Delivery Headers and Signature Verification

Each webhook delivery includes:

  • X-Webhook-Id: webhook UUID
  • X-Webhook-Event: event identifier (for example contact.created)
  • X-Webhook-Timestamp: ISO timestamp
  • X-Webhook-Signature: HMAC-SHA256 signature

To verify authenticity, compute:

HMAC-SHA256(secret, timestamp + "." + rawBody)

Then compare it against X-Webhook-Signature.

Update, Disable, or Delete a Webhook

  • updateWebhook updates URL, events, description, and enabled status.
  • rotateWebhookSecret generates a new signing secret.
  • deleteWebhook permanently removes the webhook.

Example update mutation:

mutation UpdateWebhook($webhook: UpdateWebhookInput!) {
updateWebhook(webhook: $webhook) {
success
webhook {
uuid
url
events
enabled
description
updatedAt
}
errors
}
}

Variables:

{
"webhook": {
"webhookUuid": "YOUR_WEBHOOK_UUID",
"enabled": false
}
}

Troubleshooting

  • Webhook URL must be a valid HTTPS URL.: Update the endpoint to HTTPS.
  • At least one webhook event must be selected.: Provide at least one event in events.
  • No deliveries returned: Confirm the webhookUuid belongs to the authenticated account.