Bill switch & cancellation webhooks inform you when a user has attempted a bill switch or cancellation. You must also register for account.added webhooks to correlate information provided about the merchant the user switched/cancelled payment info for.
bill_switch.added
A bill_switch job completed. Pinwheel sends this event to your webhook endpoint when the merchant attempts to update your customer's payment method. The event is delivered whether the attempt ultimately succeeds or fails. Check the outcome field in the payload to determine if the payment migration was successful or failed.
Payload Schema
| Payload Param | Type | Description |
|---|---|---|
account_id | string | UUID of the account connected by the end user. |
end_user_id | string | The user identifier you provided when initializing Link for this user (if provided). |
outcome | string | The outcome of the job, either success, error, or pending. If pending you will receive another webhook with outcome as success or error within 24 hours. |
error_code (optional) | string | On error, a string describing the error. |
error_type (optional) | string | On error, a high level classification of the error. |
timestamp | string | ISO 8601 timestamp of job completion. |
name | string | Name of the job, which is bill_switch. |
link_token_id | string | UUID of the Link token used to initialize Link. You should use account_id as the main identifier. |
params (optional) | object | Parameters of the job, if applicable. Contains payment method information when available. |
params.is_integrated_switch | boolean | Whether this is an integrated switch flow (true) or guided flow (false). |
params.type (optional) | string | The type of payment method switch, such as card for card-based payments. Only present for integrated flows. |
params.payment (optional) | object | Payment method details. See Payment Schema below for object structure. May be absent for guided flows if card details are unavailable. |
params.frequency (optional) | string | The billing frequency for the payment, such as monthly, weekly, or annually. |
params.next_payment_date (optional) | string | ISO 8601 timestamp of the next scheduled payment date. |
params.next_payment_amount_cents (optional) | number | The amount of the next payment in cents. |
id | string | Deprecated. UUID of the job. You should use account_id as the main identifier. |
Payment Schema
| Parameter | Type | Description |
|---|---|---|
card_name (optional) | string | Name on the card for card-based payments. |
last_four_card_number (optional) | string | Last four digits of the card number for card-based payment |
Sample Webhook Event - Integrated Flow (Card Payment)
{
"event_id": "4a939000-b43f-489d-ab32-4a0b1b9ba7a2",
"event": "bill_switch.added",
"payload": {
"id": "c4ccfd24-5e5c-4b22-8191-6f1384fc8db1",
"name": "bill_switch",
"timestamp": "2025-01-03T12:30:00+00:00",
"outcome": "success",
"link_token_id": "3b35ba10-48cf-4a6a-b038-1572e8e93e98",
"params": {
"is_integrated_switch": true,
"type": "card",
"payment": {
"card_name": "CARD NAME",
"last_four_card_number": "4242"
},
"frequency": "monthly",
"next_payment_date": "2025-09-26T12:00:00+00:00",
"next_payment_amount_cents": 1234
},
"account_id": "792f2d1f-abcd-42b7-ae45-01dd80ceae28",
"end_user_id": "my_user_12345"
}
}
Sample Webhook Event - Guided Flow (With Payment Details)
{
"event_id": "7b212456-c89e-4f1a-bc54-8e9f3b4c7d21",
"event": "bill_switch.added",
"payload": {
"id": "d5eef035-7f6d-5c33-9202-7g2495gd9ec2",
"name": "bill_switch",
"timestamp": "2025-01-03T12:30:00+00:00",
"outcome": "success",
"link_token_id": "3b35ba10-48cf-4a6a-b038-1572e8e93e98",
"params": {
"is_integrated_switch": false,
"payment": {
"card_name": "CARD NAME",
"last_four_card_number": "4242"
},
"frequency": "monthly",
"next_payment_date": "2025-09-26T12:00:00+00:00",
"next_payment_amount_cents": 1234
},
"account_id": "792f2d1f-abcd-42b7-ae45-01dd80ceae28",
"end_user_id": "my_user_12345"
}
}
Sample Webhook Event - Guided Flow (Without Payment Details)
{
"event_id": "8c323567-d90f-5g2b-cd65-9f0g4c5d8e32",
"event": "bill_switch.added",
"payload": {
"id": "e6ffg146-8g7e-6d44-0313-8h3506he0fd3",
"name": "bill_switch",
"timestamp": "2025-01-03T12:30:00+00:00",
"outcome": "success",
"link_token_id": "3b35ba10-48cf-4a6a-b038-1572e8e93e98",
"params": {
"is_integrated_switch": false,
"frequency": "monthly",
"next_payment_date": "2025-09-26T12:00:00+00:00",
"next_payment_amount_cents": 1234
},
"account_id": "792f2d1f-abcd-42b7-ae45-01dd80ceae28",
"end_user_id": "my_user_12345"
}
}
Sample Webhook Event - Failed Payment Migration
{
"event_id": "5a141122-4235-4fa1-bd76-0628573880b0",
"event": "bill_switch.added",
"payload": {
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"name": "bill_switch",
"timestamp": "2025-01-03T12:30:00+00:00",
"outcome": "error",
"error_code": "platformError",
"error_type": "platformError",
"link_token_id": "4787acbc-11cf-4db3-998c-5ea7c4feebcd",
"account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
"end_user_id": "my_user_12345"
}
}
bill_switch.cancelled
A bill_cancellation job completed. Pinwheel sends this event to your webhook endpoint when the merchant attempts to cancel a stored payment method or a recurring payment for your customer. The event is delivered whether the attempt ultimately succeeds or fails. Check the outcome field in the payload to determine if the payment cancellation was successful or failed.
Payload Schema
| Payload Param | Type | Description |
|---|---|---|
account_id | string | UUID of the account connected by the end user. |
end_user_id | string | The user identifier you provided when initializing Link for this user (if provided). |
outcome | string | The outcome of the job, either success, error, or pending. If pending you will receive another webhook with outcome as success or error within 24 hours. |
error_code (optional) | string | On error, a string describing the error. |
error_type (optional) | string | On error, a high level classification of the error. |
timestamp | string | ISO 8601 timestamp of job completion. |
name | string | Name of the job, which is bill_cancellation. |
link_token_id | string | UUID of the Link token used to initialize Link. You should use account_id as the main identifier. |
params (optional) | object | Parameters of the job, if applicable. |
params.is_integrated_cancellation | boolean | Whether this is an integrated cancellation flow (true) or guided flow (false). |
id | string | Deprecated. UUID of the job. You should use account_id as the main identifier. |
Sample Webhook Event - Integrated Flow (Successful Cancellation)
{
"event_id": "689fcb7c-4378-4516-a489-3efd16f83d6d",
"event": "bill_switch.cancelled",
"payload": {
"id": "828a62b9-07ed-40aa-9c43-71c2df0f1fee",
"name": "bill_cancellation",
"timestamp": "2023-06-15T14:30:00+00:00",
"outcome": "success",
"link_token_id": "3b35ba10-48cf-4a6a-b038-1572e8e93e98",
"params": {
"is_integrated_cancellation": true
},
"account_id": "792f2d1f-abcd-42b7-ae45-01dd80ceae28",
"end_user_id": "my_user_12345"
}
}
Sample Webhook Event - Guided Flow (Successful Cancellation)
{
"event_id": "9d434678-e01g-6h3c-de76-0g1h5e6f9g43",
"event": "bill_switch.cancelled",
"payload": {
"id": "939b73c0-18fe-51bb-0d54-82d3eg1g2gff",
"name": "bill_cancellation",
"timestamp": "2023-06-15T14:30:00+00:00",
"outcome": "success",
"link_token_id": "3b35ba10-48cf-4a6a-b038-1572e8e93e98",
"params": {
"is_integrated_cancellation": false
},
"account_id": "792f2d1f-abcd-42b7-ae45-01dd80ceae28",
"end_user_id": "my_user_12345"
}
}
Sample Webhook Event - Failed Cancellation
{
"event_id": "5a141122-4235-4fa1-bd76-0628573880b0",
"event": "bill_switch.cancelled",
"payload": {
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"name": "bill_cancellation",
"timestamp": "2023-06-15T14:30:00+00:00",
"outcome": "error",
"error_code": "systemError",
"error_type": "systemError",
"link_token_id": "4787acbc-11cf-4db3-998c-5ea7c4feebcd",
"account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
"end_user_id": "my_user_12345"
}
}