API Reference
Complete reference for the LostChurn REST API v1 — payments, customers, recoveries, campaigns, analytics, webhooks, decline codes, email, AI, and more.
API v1 (Pre-release)
Complete endpoint reference for the LostChurn REST API v1.
Base URL: https://api.lostchurn.com/api/v1
This API is in pre-release. Endpoints, request/response shapes, and rate limits may change before general availability.
For key generation and rotation, see Authentication. For error codes and rate limits, see Errors & Rate Limits.
Authentication
All API requests require an API key passed via header:
Authorization: Bearer lc_live_your_api_keyOr alternatively:
X-API-Key: lc_live_your_api_keyResponse Format
Success:
{
"data": { ... },
"meta": {
"merchant_id": "m_abc123",
"timestamp": "2026-03-29T12:00:00Z"
}
}Paginated (offset):
{
"data": [ ... ],
"meta": { ... },
"pagination": {
"page": 1,
"per_page": 25,
"total": 142,
"total_pages": 6
}
}Paginated (cursor):
{
"data": [ ... ],
"meta": { ... },
"cursor": { "next": "eyJpZCI6..." }
}Error:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "amount_cents must be a positive integer"
}
}Rate Limits
| Type | Limit |
|---|---|
Read endpoints (GET) | 200 requests/minute per API key |
Write endpoints (POST, PUT, DELETE) | 50 requests/minute per API key |
Rate limit headers are included in every response: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.
Endpoint Summary
| # | Method | Path | Scope | Description |
|---|---|---|---|---|
| 1 | GET | /v1/status | Optional | API connection check |
| 2 | GET | /v1/payments | read | List payments |
| 3 | GET | /v1/payments/:id | read | Get payment |
| 4 | GET | /v1/payments/:id/timeline | read | Payment timeline |
| 5 | POST | /v1/payments/:id/retry | write | Retry payment |
| 6 | POST | /v1/payments/:id/pause | write | Pause recovery |
| 7 | POST | /v1/payments/:id/resume | write | Resume recovery |
| 8 | GET | /v1/customers | read | List customers |
| 9 | GET | /v1/customers/by-email/:email | read | Look up by email |
| 10 | GET | /v1/customers/:id | read | Get customer |
| 11 | GET | /v1/customers/:id/payments | read | Customer payments |
| 12 | GET | /v1/customers/:id/recoveries | read | Customer recoveries |
| 13 | POST | /v1/customers/:id/pause-all | write | Pause all recovery |
| 14 | POST | /v1/customers/:id/resume-all | write | Resume all recovery |
| 15 | DELETE | /v1/customers/:id | admin | GDPR erasure |
| 16 | GET | /v1/recoveries | read | List recoveries |
| 17 | GET | /v1/recoveries/:id | read | Get recovery |
| 18 | POST | /v1/recoveries/:id/dunning | write | Trigger dunning |
| 19 | GET | /v1/campaigns | read | List campaigns |
| 20 | GET | /v1/campaigns/:id | read | Get campaign |
| 21 | POST | /v1/campaigns | write | Create campaign |
| 22 | PUT | /v1/campaigns/:id | write | Update campaign |
| 23 | POST | /v1/campaigns/:id/activate | write | Activate campaign |
| 24 | POST | /v1/campaigns/:id/pause | write | Pause campaign |
| 25 | GET | /v1/campaigns/templates | read | List templates |
| 26 | POST | /v1/campaigns/from-template | write | Create from template |
| 27 | POST | /v1/campaigns/overlap | read | Check overlap |
| 28 | POST | /v1/campaigns/simulate | read | Simulate campaign |
| 29 | GET | /v1/subscriptions/:id | read | Subscription status |
| 30 | GET | /v1/subscriptions/:id/failed-invoices | read | Failed invoices |
| 31 | GET | /v1/invoices/:id | read | Invoice status |
| 32 | GET | /v1/invoices/:id/timeline | read | Invoice timeline |
| 33 | GET | /v1/analytics/recovery | analytics | Recovery metrics |
| 34 | GET | /v1/analytics/campaigns | analytics | Campaign metrics |
| 35 | GET | /v1/analytics/revenue | analytics | Revenue metrics |
| 36 | GET | /v1/analytics/at-risk | analytics | At-risk revenue |
| 37 | GET | /v1/analytics/decline-codes | analytics | Decline distribution |
| 38 | GET | /v1/analytics/recovery-breakdown | analytics | Recovery breakdown |
| 39 | GET | /v1/analytics/at-risk-customers | analytics | At-risk customers |
| 40 | POST | /v1/analytics/at-risk-customers/:id/enroll | write | Quick-enroll customer |
| 41 | GET | /v1/analytics/email-health | analytics | Email health |
| 42 | GET | /v1/analytics/email-engagement | analytics | Email engagement |
| 43 | GET | /v1/analytics/summary | analytics | Summary (alias) |
| 44 | GET | /v1/webhooks/endpoints | webhooks | List endpoints |
| 45 | POST | /v1/webhooks/endpoints | webhooks | Create endpoint |
| 46 | PUT | /v1/webhooks/endpoints/:id | webhooks | Update endpoint |
| 47 | DELETE | /v1/webhooks/endpoints/:id | webhooks | Delete endpoint |
| 48 | POST | /v1/webhooks/endpoints/:id/test | webhooks | Test endpoint |
| 49 | GET | /v1/webhooks/events | webhooks | Delivery log |
| 50 | GET | /v1/decline-codes | read | List decline codes |
| 51 | GET | /v1/decline-codes/categories | read | Decline categories |
| 52 | GET | /v1/decline-codes/:code | read | Get decline code |
| 53 | GET | /v1/settings/quiet-hours | read | Get quiet hours |
| 54 | POST | /v1/settings/quiet-hours | write | Set quiet hours |
| 55 | GET | /v1/settings/recovery-goal | read | Get recovery goal |
| 56 | POST | /v1/settings/recovery-goal | write | Set recovery goal |
| 57 | GET | /v1/templates/preview/:id | read | Preview template |
| 58 | POST | /v1/ingest/payment-event | write | Ingest event |
| 59 | GET | /v1/email/suppressions | email | List suppressions |
| 60 | DELETE | /v1/email/suppressions/:email | email | Remove suppression |
| 61 | GET | /v1/email/suppressions/stats | email | Suppression stats |
| 62 | POST | /v1/email/ab-test | write | Create A/B test |
| 63 | GET | /v1/email/ab-test/:campaign_id | read | Get A/B test |
| 64 | POST | /v1/email/ab-test/:campaign_id/evaluate | write | Evaluate A/B test |
| 65 | GET | /v1/experiments | read | List experiments |
| 66 | GET | /v1/experiments/:id | read | Get experiment |
| 67 | GET | /v1/experiments/:id/results | read | Experiment results |
| 68 | POST | /v1/experiments/:id/promote | write | Promote winner |
| 69 | POST | /v1/experiments/:id/stop | write | Stop experiment |
| 70 | GET | /v1/experiments/assign/:customer_id | read | Get assignment |
| 71 | GET | /v1/suggestions/recovery | read | Recovery suggestions |
| 72 | POST | /v1/suggestions/:id/apply | write | Apply suggestion |
| 73 | POST | /v1/suggestions/:id/dismiss | write | Dismiss suggestion |
| 74 | POST | /v1/win-back/:customerId | write | Win-back campaign |
| 75 | GET | /v1/cancel-flows | read | List cancel flows |
| 76 | POST | /v1/cancel-flows | write | Create cancel flow |
| 77 | PUT | /v1/cancel-flows/:id | write | Update cancel flow |
| 78 | DELETE | /v1/cancel-flows/:id | write | Delete cancel flow |
| 79 | POST | /v1/cancel-flows/:id/activate | write | Activate flow |
| 80 | POST | /v1/cancel-flows/:id/deactivate | write | Deactivate flow |
| 81 | POST | /v1/ai/generate | write | AI text generation |
| 82 | GET | /v1/ai/ping | None | AI health check |
| 83 | POST | /v1/scoring/retry | write | AI retry scoring |
| 84 | POST | /v1/vectors/embed-event | write | Embed event |
| 85 | POST | /v1/vectors/find-similar | read | Find similar |
| 86 | GET | /v1/vectors/recommend-strategy/:id | read | Recommend strategy |
| 87 | POST | /v1/integrations/shopify/register | admin | Register Shopify |
| 88 | GET | /v1/integrations/health | read | Integration health |
| 89 | GET | /v1/integrations/:id/health | read | Provider health |
| 90 | GET | /v1/integrations/:id/errors | read | Provider errors |
Status
Check API Connection
GET /v1/statusReturns API version, server time, and authentication status. No API key required, but if one is provided the response confirms it is valid.
Response:
{
"data": {
"status": "ok",
"version": "1.0.0",
"timestamp": "2026-03-29T12:00:00Z",
"authenticated": true,
"merchant_id": "m_abc123"
}
}Payments
List Payments
GET /v1/paymentsPaginated list of payment events for the authenticated merchant.
Scopes: read or read:payments
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number |
per_page | integer | 25 | Items per page (max 100) |
status | string | — | Filter: failed, recovered, terminal, pending |
decline_category | string | — | Filter: soft_retry, hard_customer, terminal, unknown |
created_after | date | — | YYYY-MM-DD |
created_before | date | — | YYYY-MM-DD |
Response:
{
"data": [
{
"id": "pe_abc123",
"external_id": "ch_1abc",
"amount_cents": 4999,
"currency": "usd",
"status": "failed",
"decline_code": "insufficient_funds",
"decline_category": "soft_retry",
"customer_id": "cust_xyz",
"customer_email": "jane@example.com",
"psp": "stripe",
"created_at": "2026-03-28T10:30:00Z"
}
],
"pagination": { "page": 1, "per_page": 25, "total": 142, "total_pages": 6 }
}Get a Payment
GET /v1/payments/:idReturns full details for a single payment event.
Scopes: read or read:payments
| Parameter | In | Description |
|---|---|---|
id | path | Payment ID or PSP charge ID |
Response:
{
"data": {
"id": "pe_abc123",
"external_id": "ch_1abc",
"amount_cents": 4999,
"currency": "usd",
"status": "failed",
"decline_code": "insufficient_funds",
"decline_category": "soft_retry",
"retry_count": 2,
"max_retries": 5,
"customer_id": "cust_xyz",
"customer_email": "jane@example.com",
"psp": "stripe",
"metadata": {},
"created_at": "2026-03-28T10:30:00Z",
"updated_at": "2026-03-29T08:00:00Z"
}
}Get Payment Timeline
GET /v1/payments/:id/timelineReturns a chronological timeline of retry attempts and status changes for a payment.
Scopes: read or read:payments
Response:
{
"data": {
"payment_id": "pe_abc123",
"events": [
{
"type": "payment_failed",
"timestamp": "2026-03-28T10:30:00Z",
"details": { "decline_code": "insufficient_funds" }
},
{
"type": "retry_scheduled",
"timestamp": "2026-03-28T14:00:00Z",
"details": { "retry_number": 1 }
},
{
"type": "retry_succeeded",
"timestamp": "2026-03-28T14:01:00Z",
"details": { "amount_cents": 4999 }
}
]
}
}Retry a Payment
POST /v1/payments/:id/retrySchedule a retry attempt for a failed payment. Returns 202 Accepted.
Scopes: write or write:payments
Response (202):
{
"data": {
"payment_id": "pe_abc123",
"retry_scheduled": true,
"retry_number": 3,
"scheduled_at": "2026-03-29T14:00:00Z"
}
}Pause Recovery
POST /v1/payments/:id/pausePause all recovery activity (retries and dunning emails) for a specific payment.
Scopes: write or write:payments
Response:
{
"data": {
"payment_id": "pe_abc123",
"status": "paused"
}
}Resume Recovery
POST /v1/payments/:id/resumeResume previously paused recovery for a payment.
Scopes: write or write:payments
Response:
{
"data": {
"payment_id": "pe_abc123",
"status": "active"
}
}Customers
List Customers
GET /v1/customersPaginated list of customers with optional search.
Scopes: read or read:customers
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number |
per_page | integer | 25 | Items per page (max 100) |
search | string | — | Search by name or email |
Response:
{
"data": [
{
"id": "cust_xyz",
"email": "jane@example.com",
"name": "Jane Doe",
"total_payments": 12,
"failed_payments": 2,
"recovered_payments": 1,
"total_revenue_cents": 59988,
"created_at": "2025-06-15T00:00:00Z"
}
],
"pagination": { "page": 1, "per_page": 25, "total": 1024 }
}Look Up Customer by Email
GET /v1/customers/by-email/:emailFind a customer by email address with recovery stats.
Scopes: read or read:customers
| Parameter | In | Description |
|---|---|---|
email | path | URL-encoded email address |
Response:
{
"data": {
"id": "cust_xyz",
"email": "jane@example.com",
"name": "Jane Doe",
"recovery_stats": {
"total_failed": 3,
"total_recovered": 2,
"recovery_rate": 0.667,
"total_recovered_cents": 9998
}
}
}Get a Customer
GET /v1/customers/:idGet customer by internal ID or Stripe customer ID (cus_*).
Scopes: read or read:customers
List Customer Payments
GET /v1/customers/:id/paymentsReturns all payment events for a specific customer.
Scopes: read or read:customers
List Customer Recoveries
GET /v1/customers/:id/recoveriesReturns all recovery records for a specific customer.
Scopes: read or read:customers
Pause All Recovery for a Customer
POST /v1/customers/:id/pause-allPauses recovery on all active payments for a customer.
Scopes: write or write:customers
Resume All Recovery for a Customer
POST /v1/customers/:id/resume-allResumes recovery on all paused payments for a customer.
Scopes: write or write:customers
Delete Customer Data (GDPR Erasure)
DELETE /v1/customers/:idPermanently erases all customer data per GDPR Article 17. This action is irreversible.
Scopes: admin or admin:customers
Response:
{
"data": {
"deleted": true,
"customer_id": "cust_xyz"
}
}Recoveries
List Recoveries
GET /v1/recoveriesPaginated list of recovery records.
Scopes: read
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number |
per_page | integer | 25 | Items per page (max 100) |
status | string | — | Filter: active, recovered, terminal, paused |
campaign_id | string | — | Filter by campaign |
Response:
{
"data": [
{
"id": "rec_abc123",
"payment_id": "pe_abc123",
"customer_id": "cust_xyz",
"campaign_id": "camp_def",
"status": "active",
"current_step": 2,
"total_steps": 5,
"amount_cents": 4999,
"currency": "usd",
"created_at": "2026-03-28T10:30:00Z"
}
],
"pagination": { "page": 1, "per_page": 25, "total": 87 }
}Get a Recovery
GET /v1/recoveries/:idReturns full details for a single recovery including campaign steps and timeline.
Scopes: read
Trigger Dunning Email
POST /v1/recoveries/:id/dunningManually trigger a dunning email for a recovery, bypassing the campaign schedule.
Scopes: write
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
template_id | string | No | Override the default template |
subject | string | No | Custom subject line |
Response:
{
"data": {
"sent": true,
"recovery_id": "rec_abc123",
"message_id": "msg_xyz"
}
}Campaigns
List Campaigns
GET /v1/campaignsPaginated list of recovery campaigns.
Scopes: read or read:campaigns
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number |
per_page | integer | 25 | Items per page (max 100) |
status | string | — | Filter: draft, active, paused, completed, archived |
trigger | string | — | Filter: payment_failed, card_expiring, card_expired, manual, pre_dunning, soft_decline, repeated_failure, high_value_churn, any_decline |
Get a Campaign
GET /v1/campaigns/:idReturns campaign details with all steps.
Scopes: read or read:campaigns
Create a Campaign
POST /v1/campaignsCreate a new recovery campaign.
Scopes: write or write:campaigns
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Campaign name (1-200 chars) |
trigger | string | No | Trigger type (default: payment_failed) |
steps | array | Yes | Array of campaign step objects (min 1) |
filters_json | string | No | JSON string of campaign filters |
Response (201):
{
"data": {
"id": "camp_new123",
"name": "Soft Decline Recovery",
"status": "draft",
"trigger": "payment_failed",
"steps": [ ... ],
"created_at": "2026-03-29T12:00:00Z"
}
}Update a Campaign
PUT /v1/campaigns/:idUpdate campaign name, trigger, or filters. Campaign must be in draft or paused status.
Scopes: write or write:campaigns
Activate a Campaign
POST /v1/campaigns/:id/activateActivate a draft or paused campaign so it begins processing enrollments.
Scopes: write or write:campaigns
Pause a Campaign
POST /v1/campaigns/:id/pausePause an active campaign. Existing enrollments are paused.
Scopes: write or write:campaigns
List Campaign Templates
GET /v1/campaigns/templatesReturns pre-built campaign templates that can be used as starting points.
Scopes: read or read:campaigns
Create Campaign from Template
POST /v1/campaigns/from-templateCreate a new campaign using a pre-built template.
Scopes: write or write:campaigns
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
template_id | string | Yes | Template ID from the templates list |
name | string | No | Override the template name |
Check Campaign Overlap
POST /v1/campaigns/overlapCheck whether a campaign's filters overlap with existing active campaigns.
Scopes: read or read:campaigns
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
trigger | string | Yes | Trigger type |
filters_json | string | No | JSON filter criteria |
exclude_campaign_id | string | No | Exclude a campaign from overlap check |
Simulate Campaign
POST /v1/campaigns/simulateSimulate a campaign against historical data to estimate impact before activating.
Scopes: read or read:campaigns
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
trigger | string | Yes | Trigger type |
filters_json | string | No | JSON filter criteria |
lookback_days | integer | No | Days of historical data to simulate (default: 30) |
Subscriptions & Invoices
Get Subscription Status
GET /v1/subscriptions/:idReturns the current status and metadata for a subscription.
Scopes: read
List Failed Invoices
GET /v1/subscriptions/:id/failed-invoicesReturns all failed invoices for a subscription.
Scopes: read
Get Invoice Status
GET /v1/invoices/:idReturns status and payment details for a single invoice.
Scopes: read
Get Invoice Timeline
GET /v1/invoices/:id/timelineReturns retry and status change history for an invoice.
Scopes: read
Analytics
Recovery Analytics
GET /v1/analytics/recoverySummary of failed, recovered, and terminal payments with decline category breakdown.
Scopes: analytics or read
| Parameter | Type | Default | Description |
|---|---|---|---|
start_date | date | 30 days ago | YYYY-MM-DD |
end_date | date | Today | YYYY-MM-DD |
group_by | string | day | hour, day, week, month |
psp | string | — | Filter by PSP provider |
decline_category | string | — | soft_retry, hard_customer, terminal, unknown |
currency | string | usd | ISO 4217 currency code |
Response:
{
"data": {
"summary": {
"total_failed": 150,
"total_recovered": 95,
"total_terminal": 30,
"recovery_rate": 0.633
},
"by_category": {
"soft_retry": { "count": 80, "recovered": 65, "rate": 0.812 },
"hard_customer": { "count": 45, "recovered": 20, "rate": 0.444 },
"terminal": { "count": 25, "recovered": 10, "rate": 0.400 }
},
"meta": { "start_date": "2026-02-27", "end_date": "2026-03-29", "group_by": "day" }
}
}Campaign Analytics
GET /v1/analytics/campaignsPer-campaign recovery rate and session counts. Uses cursor-based pagination.
Scopes: analytics or read
| Parameter | Type | Default | Description |
|---|---|---|---|
cursor | string | — | Pagination cursor |
limit | integer | 50 | Items per page (max 200) |
Revenue Analytics
GET /v1/analytics/revenueReturns revenue recovered and MRR impact for a date range.
Scopes: analytics or read
| Parameter | Type | Default | Description |
|---|---|---|---|
start_date | date | 30 days ago | YYYY-MM-DD |
end_date | date | Today | YYYY-MM-DD |
currency | string | usd | ISO 4217 code |
Response:
{
"data": {
"revenue_recovered": 475000,
"revenue_at_risk": 275000,
"payments_recovered": 95,
"payments_failed": 150,
"currency": "usd",
"period": { "start_date": "2026-02-27", "end_date": "2026-03-29" }
}
}At-Risk Revenue
GET /v1/analytics/at-riskReturns aggregate at-risk revenue across all active recoveries.
Scopes: analytics or read
Decline Code Distribution
GET /v1/analytics/decline-codesReturns decline code frequency distribution for a date range.
Scopes: analytics or read
| Parameter | Type | Default | Description |
|---|---|---|---|
start_date | date | 30 days ago | YYYY-MM-DD |
end_date | date | Today | YYYY-MM-DD |
psp | string | — | Filter by PSP |
Recovery Breakdown
GET /v1/analytics/recovery-breakdownDetailed recovery breakdown with time series data, segmented by decline category and PSP.
Scopes: analytics or read
| Parameter | Type | Default | Description |
|---|---|---|---|
start_date | date | 30 days ago | YYYY-MM-DD |
end_date | date | Today | YYYY-MM-DD |
group_by | string | day | hour, day, week, month |
segment_by | string | — | decline_category, psp, campaign |
At-Risk Customers
GET /v1/analytics/at-risk-customersList of customers at risk of churn, segmented by cohort.
Scopes: analytics or read
| Parameter | Type | Default | Description |
|---|---|---|---|
cohort | string | all | all, expiring_card, repeat_failure, high_value |
page | integer | 1 | Page number |
per_page | integer | 25 | Items per page (max 100) |
Quick-Enroll At-Risk Customer
POST /v1/analytics/at-risk-customers/:id/enrollEnroll an at-risk customer directly into a specific campaign.
Scopes: write
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
campaign_id | string | Yes | Target campaign ID |
Email Health
GET /v1/analytics/email-healthEmail deliverability health metrics including bounce rate, spam complaints, and domain reputation.
Scopes: analytics or email
| Parameter | Type | Default | Description |
|---|---|---|---|
start_date | date | 30 days ago | YYYY-MM-DD |
end_date | date | Today | YYYY-MM-DD |
group_by | string | day | hour, day, week, month |
Email Engagement
GET /v1/analytics/email-engagementEmail engagement metrics: open rate, click rate, and unsubscribe rate.
Scopes: analytics or email
| Parameter | Type | Default | Description |
|---|---|---|---|
start_date | date | 30 days ago | YYYY-MM-DD |
end_date | date | Today | YYYY-MM-DD |
campaign_id | string | — | Filter by campaign |
Analytics Summary
GET /v1/analytics/summaryAlias for /v1/analytics/recovery. Returns the same recovery summary response.
Scopes: analytics or read
Webhooks (Outbound)
List Webhook Endpoints
GET /v1/webhooks/endpointsReturns all registered webhook endpoints. Uses cursor-based pagination.
Scopes: webhooks or read
| Parameter | Type | Default | Description |
|---|---|---|---|
cursor | string | — | Pagination cursor |
limit | integer | 50 | Items per page (max 200) |
Create a Webhook Endpoint
POST /v1/webhooks/endpointsRegister a new webhook endpoint URL.
Scopes: webhooks
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
url | string (URI) | Yes | HTTPS URL to receive webhook events |
events | string[] | No | Event types to subscribe to (default: all events) |
description | string | No | Human-readable description |
Response (201):
{
"data": {
"id": "we_abc123",
"url": "https://example.com/webhooks",
"events": ["payment.recovered", "payment.failed"],
"signing_secret": "whsec_abc123...",
"created_at": "2026-03-29T12:00:00Z"
}
}Update a Webhook Endpoint
PUT /v1/webhooks/endpoints/:idUpdate an existing webhook endpoint URL, events, or description.
Scopes: webhooks
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
url | string (URI) | No | Updated HTTPS URL |
events | string[] | No | Updated event subscriptions |
description | string | No | Updated description |
enabled | boolean | No | Enable or disable the endpoint |
Delete a Webhook Endpoint
DELETE /v1/webhooks/endpoints/:idPermanently removes a webhook endpoint.
Scopes: webhooks
Test a Webhook Endpoint
POST /v1/webhooks/endpoints/:id/testSends a test event to the specified webhook endpoint and returns the delivery result.
Scopes: webhooks
Response:
{
"data": {
"success": true,
"status_code": 200,
"response_time_ms": 142,
"endpoint_id": "we_abc123"
}
}Webhook Delivery Log
GET /v1/webhooks/eventsReturns recent webhook delivery attempts with status and response codes.
Scopes: webhooks
| Parameter | Type | Default | Description |
|---|---|---|---|
cursor | string | — | Pagination cursor |
limit | integer | 50 | Items per page (max 200) |
endpoint_id | string | — | Filter by endpoint |
status | string | — | Filter: delivered, failed, pending |
Decline Codes
List Decline Codes
GET /v1/decline-codesPaginated list of 268 decline codes across 13 PSPs.
Scopes: read
| Parameter | Type | Default | Description |
|---|---|---|---|
psp | string | — | Filter by PSP: stripe, braintree, adyen, checkout_com, etc. |
category | string | — | soft_retry, hard_customer, terminal, unknown |
subcategory | string | — | Filter by subcategory |
cursor | string | — | Pagination cursor |
limit | integer | 50 | Items per page (max 200) |
Response:
{
"data": [
{
"code": "insufficient_funds",
"psp": "stripe",
"category": "soft_retry",
"subcategory": "balance",
"description": "The card has insufficient funds to complete the purchase.",
"recommended_action": "Retry in 24-48 hours",
"recovery_rate": 0.72
}
]
}List Decline Code Categories
GET /v1/decline-codes/categoriesReturns the 4 decline categories with subcategories and expected recovery rates.
Scopes: read
Response:
{
"data": [
{
"category": "soft_retry",
"description": "Temporary issues that are likely to resolve",
"expected_recovery_rate": 0.75,
"subcategories": ["balance", "limit", "processing_error"]
},
{
"category": "hard_customer",
"description": "Customer action required to resolve",
"expected_recovery_rate": 0.35,
"subcategories": ["expired", "stolen", "closed"]
}
]
}Get a Decline Code
GET /v1/decline-codes/:codeReturns details for a specific decline code including PSP-specific variations.
Scopes: read
| Parameter | In | Description |
|---|---|---|
code | path | Decline code string (e.g. insufficient_funds) |
Settings
Get Quiet Hours
GET /v1/settings/quiet-hoursReturns the merchant's quiet hours configuration. During quiet hours, no retry attempts or dunning messages are sent.
Scopes: read
Response:
{
"data": {
"start_hour": 22,
"end_hour": 8,
"timezone": "America/New_York",
"enabled": true
}
}Set Quiet Hours
POST /v1/settings/quiet-hoursConfigure quiet hours for the merchant.
Scopes: write
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
start_hour | integer | Yes | Hour to begin quiet period (0-23) |
end_hour | integer | Yes | Hour to end quiet period (0-23) |
timezone | string | Yes | IANA timezone (e.g. America/New_York) |
Get Recovery Goal
GET /v1/settings/recovery-goalReturns the merchant's recovery rate target and current progress.
Scopes: read
Set Recovery Goal
POST /v1/settings/recovery-goalSet a target recovery rate goal.
Scopes: write
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
target_rate | number | Yes | Target recovery rate (0.0-1.0) |
period | string | No | Goal period: monthly, quarterly, annual |
Templates
Preview Dunning Template
GET /v1/templates/preview/:idReturns a rendered preview of a dunning email template with sample data substituted into all placeholders.
Scopes: read
Response:
{
"data": {
"id": "tmpl_abc123",
"name": "Soft Decline - First Touch",
"subject": "Your payment of $49.99 could not be processed",
"html_preview": "<html>...</html>",
"text_preview": "Hi Jane Doe, your payment of $49.99...",
"placeholders": [
"{{customer_name}}",
"{{amount}}",
"{{currency}}",
"{{decline_reason}}",
"{{retry_date}}",
"{{update_payment_url}}"
]
}
}List Email Suppressions
GET /v1/email/suppressionsPaginated list of suppressed email addresses (hard bounces, spam complaints).
Scopes: email or read
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number |
per_page | integer | 25 | Items per page (max 100) |
search | string | — | Search by email address |
reason | string | — | Filter by suppression reason |
active_only | string | true | true or false |
Remove Email Suppression
DELETE /v1/email/suppressions/:emailLift a suppression to allow emails to the address again.
Scopes: email or write
| Parameter | In | Description |
|---|---|---|
email | path | Email address to unsuppress |
Email Suppression Stats
GET /v1/email/suppressions/statsReturns aggregate suppression statistics.
Scopes: email or read
Create Email A/B Test
POST /v1/email/ab-testCreate a new A/B test for email subject lines or templates within a campaign.
Scopes: write
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
campaign_id | string | Yes | Campaign to run the test on |
variants | array | Yes | Array of variant objects with name, subject, and template_id |
traffic_split | number | No | Percentage of traffic for the test (default: 0.5) |
Get Email A/B Test
GET /v1/email/ab-test/:campaign_idReturns A/B test configuration and current results for a campaign.
Scopes: read
Evaluate Email A/B Test
POST /v1/email/ab-test/:campaign_id/evaluateEvaluate the A/B test results and optionally promote the winning variant.
Scopes: write
Experiments
List Experiments
GET /v1/experimentsReturns all recovery experiments (retry timing, email cadence, etc.).
Scopes: read
Get Experiment
GET /v1/experiments/:idReturns experiment configuration and status.
Scopes: read
Get Experiment Results
GET /v1/experiments/:id/resultsReturns statistical results for an experiment including confidence intervals.
Scopes: read
Promote Experiment Winner
POST /v1/experiments/:id/promotePromote the winning variant to be the default for all future recoveries.
Scopes: write
Stop Experiment
POST /v1/experiments/:id/stopStop a running experiment early.
Scopes: write
Get Customer Assignment
GET /v1/experiments/assign/:customer_idReturns which experiment variant a customer is assigned to.
Scopes: read
AI Suggestions
Get Recovery Suggestions
GET /v1/suggestions/recoveryReturns AI-powered recovery strategy suggestions based on recent payment patterns.
Scopes: read
Apply a Suggestion
POST /v1/suggestions/:id/applyApply an AI suggestion (e.g. adjust retry timing, change campaign trigger).
Scopes: write
Dismiss a Suggestion
POST /v1/suggestions/:id/dismissDismiss a suggestion so it no longer appears.
Scopes: write
Win-Back
Trigger Win-Back Campaign
POST /v1/win-back/:customerIdInitiate a win-back campaign for a churned customer.
Scopes: write
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
campaign_id | string | No | Specific win-back campaign (uses default if omitted) |
offer_type | string | No | discount, pause, downgrade, custom |
offer_value | string | No | Offer details (e.g. 20%, 1_month_free) |
Cancel Flows
List Cancel Flows
GET /v1/cancel-flowsReturns all cancel flows with steps and session statistics.
Scopes: read or read:cancel-flows
Create a Cancel Flow
POST /v1/cancel-flowsCreate a new cancel flow (starts as an inactive draft).
Scopes: write or write:cancel-flows
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Flow name (1-200 chars) |
steps | array | No | Array of step objects |
Each step object:
| Field | Type | Description |
|---|---|---|
step_type | string | survey, offer, confirm, or custom |
title | string | Step title |
body | string | Step body text |
options | array | Array of { value, label } objects |
button_label | string | CTA button text |
Update a Cancel Flow
PUT /v1/cancel-flows/:idReplace all steps for a cancel flow.
Scopes: write or write:cancel-flows
Delete a Cancel Flow
DELETE /v1/cancel-flows/:idDelete an inactive cancel flow.
Scopes: write or write:cancel-flows
Activate a Cancel Flow
POST /v1/cancel-flows/:id/activateActivate a cancel flow. Deactivates all other flows (only one can be active).
Scopes: write or write:cancel-flows
Deactivate a Cancel Flow
POST /v1/cancel-flows/:id/deactivateDeactivate the currently active cancel flow.
Scopes: write or write:cancel-flows
AI & Vectors
AI Text Generation
POST /v1/ai/generateGenerate AI-powered text (dunning emails, retry explanations, customer communications).
Scopes: write
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
prompt_template | string | Yes | Template: retry_explanation, dunning_email, win_back, report_summary |
context | object | Yes | Template variables (payment details, customer info, etc.) |
max_tokens | integer | No | Maximum output tokens (default: 500) |
Response:
{
"data": {
"text": "Hi Jane, we noticed your payment of $49.99 was declined...",
"model": "qwen3-30b",
"tokens_used": 142,
"cost_usd": 0.0003
}
}AI Health Check
GET /v1/ai/pingReturns AI service availability. No authentication required.
AI Retry Scoring
POST /v1/scoring/retryScore a failed payment to determine optimal retry timing and likelihood of success.
Scopes: write
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
payment_id | string | Yes | Payment to score |
decline_code | string | Yes | Current decline code |
amount_cents | integer | Yes | Payment amount |
currency | string | Yes | ISO 4217 code |
retry_count | integer | Yes | Number of previous retries |
Response:
{
"data": {
"score": 0.73,
"recommended_delay_hours": 24,
"confidence": 0.85,
"reasoning": "Soft decline with 72% historical recovery rate for this code"
}
}Embed Recovery Event
POST /v1/vectors/embed-eventStore a recovery event as a vector embedding for similarity search.
Scopes: write or write:vectors
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Recovery event ID |
decline_code | string | Yes | Decline code |
amount_cents | integer | Yes | Amount |
currency | string | Yes | Currency |
customer_segment | string | Yes | Customer segment |
recovery_outcome | string | Yes | Outcome: recovered, terminal |
Find Similar Recoveries
POST /v1/vectors/find-similarQuery the vector index for similar past recoveries to inform strategy.
Scopes: read or read:vectors
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
decline_code | string | Yes | Decline code to match |
amount_cents | integer | Yes | Amount |
currency | string | Yes | Currency |
top_k | integer | No | Number of results (default: 5) |
Recommend Recovery Strategy
GET /v1/vectors/recommend-strategy/:idReturns an AI-recommended recovery strategy based on similar past recoveries.
Scopes: read or read:vectors
| Parameter | In | Description |
|---|---|---|
id | path | Payment ID to get recommendations for |
Integrations
Register Shopify Store
POST /v1/integrations/shopify/registerCreates or updates a merchant's Shopify store association during app installation.
Scopes: admin
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
shop_domain | string | Yes | Shopify domain (e.g. mystore.myshopify.com) |
Integration Health Overview
GET /v1/integrations/healthReturns health status for all configured integrations.
Scopes: read
Provider Health
GET /v1/integrations/:id/healthReturns detailed health status for a specific integration provider.
Scopes: read
Provider Errors
GET /v1/integrations/:id/errorsReturns recent error log for a specific integration provider.
Scopes: read
Ingest
Ingest Payment Event
POST /v1/ingest/payment-eventGeneric payment event ingestion for PSPs without native webhook support (BigCommerce, WooCommerce, custom).
Scopes: write or admin
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
event_type | string | Yes | payment_failed, payment_succeeded, subscription_cancelled, payment_method_updated, charge_refunded |
amount_cents | integer | Yes | Amount in smallest currency unit |
currency | string | Yes | ISO 4217 code (e.g. usd, eur) |
customer_email | string | Yes | Customer email address |
decline_code | string | No | PSP-specific decline code |
metadata | object | No | Arbitrary key-value metadata |
Supported currencies: usd, eur, gbp, cad, aud, jpy, chf, nzd, sek, nok, dkk, pln, czk, huf, ron, bgn, hrk, brl, mxn, inr
Response:
{
"data": {
"event_id": "pe_new123",
"status": "processed",
"recovery_initiated": true
}
}