LostChurn Docs
API Reference

REST API Reference

Complete reference for all 50+ LostChurn REST API endpoints — payments, customers, recoveries, campaigns, analytics, AI scoring, webhooks, and more.

REST API Reference

Complete endpoint reference for the LostChurn REST API. All endpoints are served by the Cloudflare Worker at https://api.lostchurn.com.

For authentication details, see Authentication. For error handling and rate limits, see Errors & Rate Limits.


Status

Check API Connection

GET /api/v1/status

Returns connection status and merchant context. Works with or without authentication — returns additional merchant data when authenticated.

Scopes required: None (public), or any scope for enhanced response.

Example request:

curl https://api.lostchurn.com/api/v1/status \
  -H "Authorization: Bearer lc_live_your_api_key"

Example response:

{
  "data": {
    "connected": true,
    "merchant_id": "merch_abc123",
    "merchant_name": "Acme Inc.",
    "plan_tier": "revenue_recovery",
    "auth_strategy": "api_key"
  },
  "meta": {
    "timestamp": "2026-03-20T12:00:00Z"
  }
}

Payments

List Payments

GET /api/v1/payments

Returns a paginated list of failed payments with optional filters.

Scopes required: read

ParameterTypeDefaultDescription
statusstringFilter by status: pending, retrying, recovered, terminal, paused
decline_categorystringFilter: soft_retry, hard_customer, terminal, unknown
pspstringFilter by payment provider (e.g. stripe, braintree)
created_afterISO 8601Filter payments created after this date
created_beforeISO 8601Filter payments created before this date
pageinteger1Page number
per_pageinteger25Results per page (max 100)

Example request:

curl "https://api.lostchurn.com/api/v1/payments?status=pending&per_page=10" \
  -H "Authorization: Bearer lc_live_your_api_key"

Example response:

{
  "data": [
    {
      "id": "pe_abc123",
      "provider_payment_id": "pi_3abc123def456",
      "amount": 4999,
      "currency": "usd",
      "status": "pending",
      "decline_code": "insufficient_funds",
      "decline_category": "soft_retry",
      "psp": "stripe",
      "customer_email": "jane@example.com",
      "retry_count": 0,
      "max_retries": 4,
      "next_retry_at": "2026-03-22T14:00:00Z",
      "created_at": "2026-03-20T10:00:00Z",
      "updated_at": "2026-03-20T10:00:00Z"
    }
  ],
  "pagination": {
    "total": 42,
    "page": 1,
    "per_page": 10,
    "total_pages": 5
  },
  "meta": { "timestamp": "2026-03-20T12:00:00Z" }
}

Get a Payment

GET /api/v1/payments/:id

Returns full details for a single payment event.

Scopes required: read

Get Payment Timeline

GET /api/v1/payments/:id/timeline

Returns chronological timeline of recovery events for a payment, including retries and status changes.

Scopes required: read

Example response:

{
  "data": {
    "events": [
      {
        "type": "payment_failed",
        "timestamp": "2026-03-20T10:00:00Z",
        "detail": "Payment declined: insufficient_funds"
      },
      {
        "type": "retry",
        "timestamp": "2026-03-22T14:00:00Z",
        "detail": "Retry scheduled"
      }
    ]
  },
  "meta": { "timestamp": "2026-03-20T12:00:00Z" }
}

Retry a Payment

POST /api/v1/payments/:id/retry

Manually trigger a payment retry. The system checks retry eligibility before proceeding.

Scopes required: write

Retry rules:

  • Cannot retry payments already in recovered or terminal status
  • Cannot retry if the maximum retry count has been reached
  • Respects quiet hours and campaign-level retry logic

Example response (success):

{
  "data": {
    "payment_id": "pe_abc123",
    "status": "retry_initiated",
    "next_retry_at": "2026-03-22T14:00:00Z"
  }
}

Pause Recovery

POST /api/v1/payments/:id/pause

Pauses all automated recovery for a specific payment. The payment status changes to paused and no further retries or dunning emails are sent until resumed.

Scopes required: write

Example request:

curl -X POST https://api.lostchurn.com/api/v1/payments/pay_abc123/pause \
  -H "Authorization: Bearer lc_live_..."

Example response:

{
  "ok": true,
  "data": {
    "id": "pay_abc123",
    "status": "paused",
    "paused_at": "2026-03-21T10:30:00Z",
    "previous_status": "retrying"
  }
}

Resume Recovery

POST /api/v1/payments/:id/resume

Resumes automated recovery for a paused payment. The payment returns to its previous status and scheduled retries or campaign steps are re-activated.

Scopes required: write

Example request:

curl -X POST https://api.lostchurn.com/api/v1/payments/pay_abc123/resume \
  -H "Authorization: Bearer lc_live_..."

Example response:

{
  "ok": true,
  "data": {
    "id": "pay_abc123",
    "status": "retrying",
    "resumed_at": "2026-03-21T12:00:00Z",
    "next_retry_at": "2026-03-21T18:00:00Z"
  }
}

Customers

List Customers

GET /api/v1/customers

Returns a paginated list of customers.

Scopes required: read

ParameterTypeDefaultDescription
has_failed_paymentbooleanFilter to customers with active failed payments
searchstringSearch by email, name, or provider customer ID
created_afterISO 8601Filter customers created after this date
created_beforeISO 8601Filter customers created before this date
pageinteger1Page number
per_pageinteger25Results per page (max 100)

Example request:

curl "https://api.lostchurn.com/api/v1/customers?has_failed_payment=true&search=jane" \
  -H "Authorization: Bearer lc_live_your_api_key"

Example response:

{
  "data": [
    {
      "id": "cust_abc123",
      "provider_customer_id": "cus_stripe_abc123",
      "email": "jane@example.com",
      "name": "Jane Doe",
      "psp": "stripe",
      "total_payments": 12,
      "failed_payments": 2,
      "recovered_payments": 1,
      "lifetime_value_cents": 59988,
      "created_at": "2025-06-15T08:30:00Z"
    }
  ],
  "pagination": { "total": 1, "page": 1, "per_page": 25, "total_pages": 1 },
  "meta": { "timestamp": "2026-03-20T12:00:00Z" }
}

Get a Customer

GET /api/v1/customers/:id

Returns customer profile with recovery statistics.

Scopes required: read

List Customer Payments

GET /api/v1/customers/:id/payments

Returns a paginated list of a customer's failed payments.

Scopes required: read

ParameterTypeDefaultDescription
statusstringFilter by payment status
pageinteger1Page number
per_pageinteger25Results per page (max 100)

List Customer Recoveries

GET /api/v1/customers/:id/recoveries

Returns recovery states for all of a customer's failed payments.

Scopes required: read

Delete Customer Data (GDPR Erasure)

DELETE /api/v1/customers/:id

Permanently deletes all data for a customer in compliance with GDPR Article 17 (Right to Erasure). This action is irreversible.

Scopes required: admin

Example response:

{
  "data": {
    "deleted": true,
    "customer_id": "cust_abc123",
    "records_deleted": 15
  }
}

Recoveries

List Recoveries

GET /api/v1/recoveries

Returns a paginated list of recovery states with details on retry status, next retry time, and outcome.

Scopes required: read

ParameterTypeDefaultDescription
statusstringFilter: pending, retrying, recovered, terminal, paused
pageinteger1Page number
per_pageinteger25Results per page (max 100)

Example request:

curl "https://api.lostchurn.com/api/v1/recoveries?status=retrying" \
  -H "Authorization: Bearer lc_live_your_api_key"

Example response:

{
  "data": [
    {
      "id": "rec_abc123",
      "payment_event_id": "pe_abc123",
      "status": "retrying",
      "retry_count": 2,
      "max_retries": 4,
      "next_retry_at": "2026-03-22T14:00:00Z",
      "recovered_at": null,
      "psp_payment_id": "pi_3abc123def456",
      "amount": 4999,
      "currency": "usd",
      "decline_code": "insufficient_funds",
      "decline_category": "soft_retry",
      "psp": "stripe",
      "created_at": "2026-03-20T10:00:00Z",
      "updated_at": "2026-03-21T10:00:00Z"
    }
  ],
  "pagination": { "total": 8, "page": 1, "per_page": 25, "total_pages": 1 },
  "meta": { "timestamp": "2026-03-20T12:00:00Z" }
}

Get a Recovery

GET /api/v1/recoveries/:id

Returns full details for a single recovery state, including state history and decline subcategory.

Scopes required: read

Example response:

{
  "data": {
    "id": "rec_abc123",
    "payment_event_id": "pe_abc123",
    "status": "retrying",
    "retry_count": 2,
    "max_retries": 4,
    "next_retry_at": "2026-03-22T14:00:00Z",
    "recovered_at": null,
    "customer_id": "cus_stripe_abc123",
    "subscription_id": "sub_abc123",
    "decline_subcategory": "Balance",
    "state_history": [
      { "status": "pending", "at": "2026-03-20T10:00:00Z", "reason": "Payment failed" },
      { "status": "retrying", "at": "2026-03-20T10:05:00Z", "reason": "Retry scheduled" }
    ],
    "psp_payment_id": "pi_3abc123def456",
    "amount": 4999,
    "currency": "usd",
    "decline_code": "insufficient_funds",
    "decline_category": "soft_retry",
    "psp": "stripe",
    "created_at": "2026-03-20T10:00:00Z",
    "updated_at": "2026-03-21T10:00:00Z"
  },
  "meta": { "timestamp": "2026-03-20T12:00:00Z" }
}

Trigger Dunning Email

POST /api/v1/recoveries/:id/dunning

Manually triggers a dunning email for a recovery. Cannot be called for payments that are already recovered or terminal.

Scopes required: write

Example response:

{
  "data": {
    "recovery_id": "rec_abc123",
    "payment_event_id": "pe_abc123",
    "status": "dunning_triggered"
  },
  "meta": { "merchant_id": "merch_abc123", "timestamp": "2026-03-20T12:00:00Z" }
}
Status CodeMeaning
202Dunning email queued for delivery
404Recovery not found
409Payment already recovered or terminal

Campaigns

List Campaigns

GET /api/v1/campaigns

Returns all campaigns for the authenticated merchant.

Scopes required: read

ParameterTypeDefaultDescription
statusstringFilter: draft, active, paused, archived
pageinteger1Page number
per_pageinteger25Results per page (max 100)

Get a Campaign

GET /api/v1/campaigns/:id

Returns full campaign details including steps, trigger configuration, and performance metrics.

Scopes required: read

Create a Campaign

POST /api/v1/campaigns

Creates a new recovery campaign in draft status.

Scopes required: write

Request body:

FieldTypeRequiredDescription
namestringYesCampaign display name
trigger_typestringYesOne of: payment_failed, payment_failed_soft, payment_failed_hard, subscription_past_due, card_expiring
stepsarrayYesArray of campaign step objects (see below)
delay_hoursnumberNoHours to wait before first step (default: 0)
max_attemptsnumberNoMaximum retry attempts (default: 4)
stop_on_recoverybooleanNoStop campaign when payment recovers (default: true)
stop_on_card_updatebooleanNoStop when customer updates card (default: true)
start_hournumberNoEarliest hour to send (0-23, default: 9)
end_hournumberNoLatest hour to send (0-23, default: 21)

Example request:

curl -X POST https://api.lostchurn.com/api/v1/campaigns \
  -H "Authorization: Bearer lc_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Soft Decline Recovery",
    "trigger_type": "payment_failed_soft",
    "steps": [
      { "action": "retry", "delay_hours": 6 },
      { "action": "email", "delay_hours": 24, "template_id": "tmpl_abc123" },
      { "action": "retry", "delay_hours": 48 }
    ],
    "max_attempts": 4,
    "stop_on_recovery": true
  }'

Update a Campaign

PUT /api/v1/campaigns/:id

Updates a campaign. Only draft and paused campaigns can be updated.

Scopes required: write

Activate a Campaign

POST /api/v1/campaigns/:id/activate

Activates a draft or paused campaign. New matching payments will be enrolled.

Scopes required: write

Pause a Campaign

POST /api/v1/campaigns/:id/pause

Pauses an active campaign. In-progress enrollments continue but no new enrollments are created.

Scopes required: write

Archive a Campaign

POST /api/v1/campaigns/:id/archive

Archives a campaign permanently. Cannot be undone.

Scopes required: write


Subscriptions

Get Subscription Recovery Status

GET /api/v1/subscriptions/:id

Returns recovery status for a specific subscription, including failed invoice count, at-risk revenue, and recovery rate.

Scopes required: read

Example request:

curl https://api.lostchurn.com/api/v1/subscriptions/sub_abc123 \
  -H "Authorization: Bearer lc_live_your_api_key"

Example response:

{
  "data": {
    "subscription_id": "sub_abc123",
    "status": "at_risk",
    "failed_invoice_count": 2,
    "total_at_risk": 9998,
    "recovered_amount": 4999,
    "recovery_rate": 0.5
  },
  "meta": { "timestamp": "2026-03-20T12:00:00Z" }
}
StatusMeaning
at_riskHas active failed invoices
recoveredAll failed invoices recovered
unknownNo failure data available

List Failed Invoices for a Subscription

GET /api/v1/subscriptions/:id/failed-invoices

Returns a paginated list of failed invoices for a subscription.

Scopes required: read

ParameterTypeDefaultDescription
pageinteger1Page number
per_pageinteger25Results per page (max 100)

Example response:

{
  "data": [
    {
      "invoice_id": "in_abc123",
      "amount": 4999,
      "currency": "usd",
      "decline_code": "insufficient_funds",
      "decline_category": "soft_retry",
      "status": "retrying",
      "created_at": "2026-03-20T10:00:00Z"
    }
  ],
  "pagination": { "total": 2, "page": 1, "per_page": 25, "total_pages": 1 }
}

Invoices

Get Invoice Recovery Status

GET /api/v1/invoices/:id

Returns recovery status for a specific invoice, including retry count, decline details, and next retry time.

Scopes required: read

Example request:

curl https://api.lostchurn.com/api/v1/invoices/in_abc123 \
  -H "Authorization: Bearer lc_live_your_api_key"

Example response:

{
  "data": {
    "invoice_id": "in_abc123",
    "payment_event_id": "pe_abc123",
    "amount": 4999,
    "currency": "usd",
    "status": "retrying",
    "decline_code": "insufficient_funds",
    "decline_category": "soft_retry",
    "decline_subcategory": "Balance",
    "psp": "stripe",
    "retry_count": 2,
    "max_retries": 4,
    "next_retry_at": "2026-03-22T14:00:00Z",
    "recovered_at": null,
    "created_at": "2026-03-20T10:00:00Z",
    "updated_at": "2026-03-21T10:00:00Z"
  },
  "meta": { "timestamp": "2026-03-20T12:00:00Z" }
}

Get Invoice Recovery Timeline

GET /api/v1/invoices/:id/timeline

Returns a chronological timeline of all recovery events for an invoice, including retries and status transitions.

Scopes required: read

Example response:

{
  "data": {
    "invoice_id": "in_abc123",
    "payment_event_id": "pe_abc123",
    "events": [
      {
        "timestamp": "2026-03-20T10:00:00Z",
        "type": "status_change",
        "detail": "Status changed to pending: Payment failed"
      },
      {
        "timestamp": "2026-03-21T14:00:00Z",
        "type": "retry",
        "detail": "Retry succeeded: Payment recovered"
      }
    ]
  },
  "meta": { "timestamp": "2026-03-20T12:00:00Z" }
}

Analytics

Recovery Analytics

GET /api/v1/analytics/recovery

Returns recovery performance metrics for a date range, broken down by decline category.

Scopes required: read or analytics

ParameterTypeDefaultDescription
start_dateYYYY-MM-DD30 days agoStart of date range
end_dateYYYY-MM-DDTodayEnd of date range
group_bystringdayGroup by: hour, day, week, month
pspstringFilter by payment provider
decline_categorystringFilter by decline category

Example response:

{
  "data": {
    "summary": {
      "total_failed": 150,
      "total_recovered": 95,
      "total_terminal": 30,
      "total_pending": 25,
      "recovery_rate": 0.633,
      "total_failed_amount": 750000,
      "total_recovered_amount": 475000,
      "total_terminal_amount": 150000,
      "currency": "usd"
    },
    "by_category": [
      {
        "category": "soft_retry",
        "failures": 80,
        "recovered": 65,
        "recovery_rate": 0.813,
        "recovered_amount": 325000
      },
      {
        "category": "hard_customer",
        "failures": 50,
        "recovered": 25,
        "recovery_rate": 0.5,
        "recovered_amount": 125000
      }
    ],
    "period": { "start_date": "2026-02-18", "end_date": "2026-03-20", "group_by": "day" }
  }
}

Campaign Analytics

GET /api/v1/analytics/campaigns

Returns performance metrics for all campaigns.

Scopes required: read or analytics

Example response:

{
  "data": [
    {
      "id": "cmp_abc123",
      "name": "Soft Decline Recovery",
      "status": "active",
      "trigger": "payment_failed_soft",
      "sessions_count": 120,
      "recovered_count": 78,
      "recovery_rate": 0.65
    }
  ]
}

Revenue Analytics

GET /api/v1/analytics/revenue

Returns revenue recovered and MRR impact for a date range.

Scopes required: read or analytics

ParameterTypeDefaultDescription
start_dateYYYY-MM-DD30 days agoStart of date range
end_dateYYYY-MM-DDTodayEnd of date range

Example response:

{
  "data": {
    "revenue_recovered": 475000,
    "revenue_at_risk": 275000,
    "payments_recovered": 95,
    "payments_failed": 150,
    "currency": "usd",
    "period": { "start_date": "2026-02-18", "end_date": "2026-03-20" }
  }
}

At-Risk Revenue

GET /api/v1/analytics/at-risk

Returns the total revenue currently at risk (sum of all pending/retrying failed payments).

Scopes required: read or analytics

Example response:

{
  "data": {
    "at_risk_cents": 275000,
    "at_risk_count": 55
  }
}

Decline Code Distribution

GET /api/v1/analytics/decline-codes

Returns decline code distribution and recovery rates for a date range.

Scopes required: read or analytics

ParameterTypeDefaultDescription
start_dateYYYY-MM-DD30 days agoStart of date range
end_dateYYYY-MM-DDTodayEnd of date range

Example response:

{
  "data": {
    "decline_codes": [
      {
        "decline_code": "insufficient_funds",
        "category": "soft_retry",
        "subcategory": "Balance",
        "occurrences": 45,
        "recovered": 35,
        "recovery_rate": 0.778,
        "total_amount": 225000
      }
    ],
    "period": { "start_date": "2026-02-18", "end_date": "2026-03-20" }
  }
}

Analytics Summary (Alias)

GET /api/v1/analytics/summary

Redirects (307) to /api/v1/analytics/recovery. Used by the BigCommerce integration.


Decline Codes

List Decline Codes

GET /api/v1/decline-codes

Returns all known decline codes with their category, subcategory, and recommended recovery strategy.

Scopes required: read

Get Decline Code

GET /api/v1/decline-codes/:code

Returns details for a specific decline code.

Scopes required: read

List Decline Code Categories

GET /api/v1/decline-codes/categories

Returns the decline code category taxonomy.

Scopes required: read


Webhooks (Outbound)

List Webhook Endpoints

GET /api/v1/webhooks/endpoints

Returns all registered webhook endpoints for the authenticated merchant.

Scopes required: webhooks or read

Create Webhook Endpoint

POST /api/v1/webhooks/endpoints

Registers a new HTTPS endpoint to receive webhook events.

Scopes required: webhooks or admin

Request body:

FieldTypeRequiredDescription
urlstring (URL)YesHTTPS URL to receive events
eventsstring[]NoEvent types to subscribe to (default: all)
descriptionstringNoHuman-readable label

Example request:

curl -X POST https://api.lostchurn.com/api/v1/webhooks/endpoints \
  -H "Authorization: Bearer lc_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-server.com/webhooks/lostchurn",
    "events": ["recovery.succeeded", "recovery.failed"],
    "description": "Production recovery events"
  }'

Update Webhook Endpoint

PUT /api/v1/webhooks/endpoints/:id

Updates URL and/or subscribed events for a webhook endpoint.

Scopes required: webhooks or admin

Delete Webhook Endpoint

DELETE /api/v1/webhooks/endpoints/:id

Removes a webhook endpoint.

Scopes required: webhooks or admin

List Webhook Events

GET /api/v1/webhooks/events

Returns a paginated log of recent webhook deliveries.

Scopes required: webhooks or read

Test Webhook Endpoint

POST /api/v1/webhooks/endpoints/:id/test

Sends a test event to the specified webhook endpoint.

Scopes required: webhooks or admin


Settings

Get Quiet Hours

GET /api/v1/settings/quiet-hours

Returns the merchant's quiet hours configuration. During quiet hours, no retry attempts or dunning messages are sent.

Scopes required: read

Example response:

{
  "data": {
    "start_hour": 22,
    "end_hour": 8,
    "timezone": "America/New_York",
    "enabled": true
  }
}

Set Quiet Hours

POST /api/v1/settings/quiet-hours

Configures quiet hours for the merchant.

Scopes required: write

Request body:

FieldTypeRequiredDescription
start_hourintegerYesHour to begin quiet period (0-23)
end_hourintegerYesHour to end quiet period (0-23)
timezonestringYesIANA timezone (e.g. America/New_York, Europe/London)

Example request:

curl -X POST https://api.lostchurn.com/api/v1/settings/quiet-hours \
  -H "Authorization: Bearer lc_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "start_hour": 22,
    "end_hour": 8,
    "timezone": "America/New_York"
  }'

Templates

Preview Dunning Template

GET /api/v1/templates/preview/:id

Returns a rendered preview of a dunning email template with sample data substituted into all placeholders.

Scopes required: read

Example response:

{
  "data": {
    "id": "tmpl_abc123",
    "name": "Soft Decline - First Touch",
    "subject": "Your payment of $49.99 could not be processed",
    "html_preview": "<html>...(rendered HTML with sample data)...</html>",
    "text_preview": "Hi Jane Doe, your payment of $49.99...",
    "placeholders": [
      "{{customer_name}}",
      "{{customer_email}}",
      "{{amount}}",
      "{{amount_cents}}",
      "{{currency}}",
      "{{decline_code}}",
      "{{decline_reason}}",
      "{{retry_date}}",
      "{{merchant_name}}",
      "{{update_payment_url}}",
      "{{support_email}}",
      "{{subscription_name}}",
      "{{invoice_id}}"
    ]
  }
}

Integrations

Register Shopify Store

POST /api/v1/integrations/shopify/register

Creates or updates a merchant's Shopify store association. Used during Shopify app installation.

Scopes required: admin

Request body:

FieldTypeRequiredDescription
shop_domainstringYesShopify store domain (e.g. mystore.myshopify.com)

Example request:

curl -X POST https://api.lostchurn.com/api/v1/integrations/shopify/register \
  -H "Authorization: Bearer lc_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "shop_domain": "mystore.myshopify.com" }'

Ingest Payment Event

POST /api/v1/ingest/payment-event

Generic payment event ingestion endpoint. Used by BigCommerce, WooCommerce, and other integrations that do not have native webhook support.

Scopes required: write or admin

Request body:

FieldTypeRequiredDescription
event_typestringYesOne of: payment_failed, payment_succeeded, subscription_cancelled, payment_method_updated, charge_refunded
amount_centsintegerYesAmount in smallest currency unit (e.g. cents)
currencystringYesISO 4217 currency code (lowercase): usd, eur, gbp, etc.
customer_emailstringYesCustomer email address
decline_codestringNoPSP-specific decline code
metadataobjectNoArbitrary 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

Example request:

curl -X POST https://api.lostchurn.com/api/v1/ingest/payment-event \
  -H "Authorization: Bearer lc_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "event_type": "payment_failed",
    "amount_cents": 2999,
    "currency": "usd",
    "customer_email": "jane@example.com",
    "decline_code": "insufficient_funds",
    "metadata": { "order_id": "ORD-12345" }
  }'

AI Generation

Generate AI Text

POST /api/v1/ai/generate

Unified AI text generation endpoint powered by Cloudflare Workers AI (Qwen3 30B). Used for email personalization, decline explanations, campaign copy, and more.

Scopes required: write

Rate limit: 100 calls/minute per merchant (separate from API rate limit).

Request body:

FieldTypeRequiredDescription
use_casestringYesSee use cases below
system_promptstringYesSystem prompt for the AI model
user_promptstringYesUser prompt with context
max_tokensintegerNoMax output tokens (50-4096, default: 500)
temperaturenumberNoSampling temperature (0-2, default: 0.7)
languagestringNoTarget language for output

Valid use cases:

Use CaseDescriptionCacheable
email_personalizationPersonalized dunning email contentNo
sms_personalizationSMS message personalizationNo
whatsapp_personalizationWhatsApp message personalizationNo
decline_explanationHuman-readable decline code explanationYes (1 hour)
retry_scoringAI-assisted retry scoringYes (1 hour)
campaign_copyCampaign email/SMS copy generationNo
weekly_digestWeekly recovery digest summaryNo
multi_language_dunningMulti-language dunning contentNo

Example request:

curl -X POST https://api.lostchurn.com/api/v1/ai/generate \
  -H "Authorization: Bearer lc_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "use_case": "decline_explanation",
    "system_prompt": "Explain payment decline codes in plain English for customer support agents.",
    "user_prompt": "Explain the decline code: insufficient_funds",
    "max_tokens": 200,
    "temperature": 0.3
  }'

Example response:

{
  "text": "The \"insufficient_funds\" decline means the customer's card did not have enough available balance...",
  "model": "@cf/qwen/qwen3-30b-a3b-fp8",
  "tokens_used": 85,
  "cached": false,
  "latency_ms": 342
}

AI Health Check

GET /api/v1/ai/ping

Tests whether the Workers AI binding is responsive. No authentication required.

Example response:

{
  "status": "ok",
  "model": "@cf/qwen/qwen3-30b-a3b-fp8",
  "response": "OK",
  "latency_ms": 150
}

AI Retry Scoring

Score Payment Retry

POST /api/v1/scoring/retry

Scores a payment retry attempt using AI, predicting the probability of success and recommending optimal delay. Supports three model tiers.

Scopes required: write

Request body:

FieldTypeRequiredDescription
decline_codestringYesPSP decline code (e.g. insufficient_funds)
amount_centsintegerYesPayment amount in smallest currency unit
decline_categorystringNoCategory: SoftRetry, HardCustomer, Terminal, Unknown
attempt_numberintegerNoCurrent attempt number (default: 1)
hour_of_dayintegerNoHour of retry (0-23, default: 12)
day_of_weekintegerNoDay of week (0=Sun, 6=Sat)
currencystringNoISO 4217 code (default: usd)
card_brandstringNoCard brand (e.g. visa, mastercard)
card_last4stringNoLast 4 digits of card
is_debitbooleanNoWhether card is debit
customer_lifetime_value_centsintegerNoCustomer LTV in cents
previous_successful_paymentsintegerNoCount of past successful payments
subscription_monthsintegerNoMonths customer has been subscribed
days_since_failureintegerNoDays since the original failure
payday_proximity_daysintegerNoDays until customer's likely payday
success_rate_90dnumberNo90-day success rate (0-1)
anomaly_scorenumberNoAnomaly score (0-1)
modelstringNoModel to use: rules, enhanced (default), lgbm

Model tiers:

ModelSourceDescription
rulesWorkerSimple rule-based scoring using decline code heuristics
enhancedWorkers AIAI-powered scoring with Workers AI (falls back to rules on failure)
lgbmKV LookupPre-computed LightGBM scores from training pipeline (falls back to enhanced)

Example request:

curl -X POST https://api.lostchurn.com/api/v1/scoring/retry \
  -H "Authorization: Bearer lc_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "decline_code": "insufficient_funds",
    "amount_cents": 4999,
    "attempt_number": 2,
    "hour_of_day": 14,
    "card_brand": "visa",
    "customer_lifetime_value_cents": 59988,
    "model": "enhanced"
  }'

Example response:

{
  "score": 0.62,
  "delay_hours": 48,
  "model_version": "workers-ai-granite-4.0-h-micro",
  "confidence": 0.7,
  "source": "workers_ai",
  "reasoning": "Insufficient funds with a loyal customer (high LTV). Afternoon retry on attempt 2 has a moderate probability of success.",
  "factors": [
    { "name": "decline_code", "impact": "positive", "weight": 0.7 },
    { "name": "customer_ltv", "impact": "positive", "weight": 0.15 },
    { "name": "attempt_number", "impact": "negative", "weight": 0.15 }
  ]
}

Vector search endpoints use Cloudflare Vectorize to find similar past recovery events and recommend optimal strategies.

Embed Recovery Event

POST /api/v1/vectors/embed-event

Embeds a recovery event into the vector index for future similarity searches.

Scopes required: write

Request body:

FieldTypeRequiredDescription
idstringYesUnique event identifier
decline_codestringYesPSP decline code
amount_centsintegerYesPayment amount in cents
currencystringYes3-letter ISO currency code
customer_segmentstringYesCustomer segment (e.g. high_value, new, at_risk)
recovery_strategystringYesStrategy used (e.g. retry_only, email_then_retry)
outcomestringYesOutcome: recovered, failed, pending

Example request:

curl -X POST https://api.lostchurn.com/api/v1/vectors/embed-event \
  -H "Authorization: Bearer lc_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "rec_abc123",
    "decline_code": "insufficient_funds",
    "amount_cents": 4999,
    "currency": "usd",
    "customer_segment": "high_value",
    "recovery_strategy": "email_then_retry",
    "outcome": "recovered"
  }'

Example response:

{
  "data": {
    "embedded": true,
    "id": "rec_abc123",
    "merchant_id": "merch_abc123"
  }
}

Find Similar Recoveries

POST /api/v1/vectors/find-similar

Finds similar past recovery events based on decline context. Returns results ranked by cosine similarity.

Scopes required: read

Request body:

FieldTypeRequiredDescription
decline_codestringYesPSP decline code
amount_centsintegerYesPayment amount in cents
currencystringYes3-letter currency code
customer_segmentstringYesCustomer segment
top_kintegerNoNumber of results to return (1-50, default: 10)

Example response:

{
  "data": {
    "count": 3,
    "matches": [
      {
        "id": "rec_xyz789",
        "score": 0.95,
        "metadata": {
          "outcome": "recovered",
          "strategy": "email_then_retry",
          "decline_code": "insufficient_funds"
        }
      }
    ]
  }
}

Recommend Recovery Strategy

GET /api/v1/vectors/recommend-strategy/:payment_id

Given a payment event ID, finds the best recovery strategy based on similar past outcomes. Automatically looks up payment context from SpacetimeDB.

Scopes required: read

Example response:

{
  "data": {
    "payment_id": "pe_abc123",
    "recommended_strategy": "email_then_retry",
    "confidence": 0.87,
    "similar_outcomes": {
      "recovered": 12,
      "failed": 3,
      "total": 15
    }
  }
}

Cancel Sessions

Cancel flow endpoints manage the lifecycle of subscription cancellation interception sessions. These run on the edge worker at https://edge.lostchurn.com.

Start a Session

POST /api/cancel-session/start

Creates a new cancel session with a unique token. Returns session state and first step configuration.

Request body:

FieldTypeRequiredDescription
merchant_idstringYesMerchant identifier
customer_idstringYesCustomer identifier
subscription_idstringNoSubscription being cancelled

Get Session State

GET /api/cancel-session/:token

Returns the current session state and step configuration.

Advance Session

POST /api/cancel-session/:token/advance

Advances the session to the next step (e.g. from survey to offer).

Request body:

FieldTypeRequiredDescription
responseobjectNoCustomer's response to the current step
selected_reasonstringNoSelected cancellation reason (survey step)

Complete Session

POST /api/cancel-session/:token/complete

Completes the session with a final outcome.

Request body:

FieldTypeRequiredDescription
outcomestringYesOne of: cancelled, saved_discount, saved_pause, saved_other, abandoned
reasonstringNoCancellation reason
feedbackstringNoFree-text feedback

Widget

Initialize Widget

POST /api/widget/init

Initializes the embeddable recovery widget. Validates the HMAC token, looks up the customer's failed payments, and returns payment info with merchant branding.

Authentication: HMAC signature (not API key).

Rate limit: 30 requests/minute per IP.

Request body:

FieldTypeRequiredDescription
merchant_idstringYesMerchant identifier
customer_idstringYesCustomer identifier
timestampintegerYesUnix timestamp (must be within 5 minutes)
signaturestringYesHMAC-SHA256 signature

Example response:

{
  "has_failed_payment": true,
  "amount_cents": 4999,
  "currency": "usd",
  "update_url": "https://billing.example.com/update-payment",
  "branding": {
    "logo_url": "https://cdn.example.com/logo.png",
    "primary_color": "#4F46E5",
    "merchant_name": "Acme Inc."
  }
}

Get Widget Branding

GET /api/widget/branding/:merchant_id

Returns merchant branding configuration for the widget. Public endpoint, cached for 5 minutes.

Authentication: None (public endpoint).


Inbound PSP Webhooks

LostChurn accepts webhooks from 13 payment service providers. Each PSP has a dedicated endpoint with provider-specific signature verification.

PSPEndpointSignature Method
StripePOST /stripe/:merchant_idHMAC-SHA256 (Stripe-Signature header)
Stripe InvoicePOST /stripe/:merchant_id/invoiceHMAC-SHA256
BraintreePOST /braintree/:merchant_idBraintree signature verification
PaddlePOST /paddle/:merchant_idPaddle webhook signature
RecurlyPOST /recurly/:merchant_idRecurly HMAC
ChargebeePOST /chargebee/:merchant_idBasic auth credentials
ShopifyPOST /shopify/:merchant_idHMAC-SHA256 (X-Shopify-Hmac-Sha256)
AdyenPOST /adyen/:merchant_idHMAC-SHA256 (HmacSignature)
Checkout.comPOST /checkoutcom/:merchant_idHMAC-SHA256
Authorize.NetPOST /authorizenet/:merchant_idSignature key verification
PayPalPOST /paypal/:merchant_idPayPal webhook ID verification
GoCardlessPOST /gocardless/:merchant_idGoCardless webhook signature
NuveiPOST /nuvei/:merchant_idChecksum verification
WorldpayPOST /worldpay/:merchant_idMAC verification

Configure your PSP to send webhooks to https://webhooks.lostchurn.com/{psp}/{your_merchant_id}. Each PSP's signing secret is configured in Settings > Integrations in the dashboard.


Delivery Webhooks

Twilio SMS/WhatsApp Status

POST /twilio/status

Receives delivery status callbacks from Twilio for SMS and WhatsApp messages. Updates communication_log delivery status in SpacetimeDB.

Twilio Email Status

POST /twilio/email/status

Receives delivery status callbacks for Twilio SendGrid emails. Note: Email delivery has been migrated to Resend. This endpoint is retained for backwards compatibility with legacy SendGrid configurations. New integrations should use the Resend Email Webhook below.

Resend Email Webhook

POST /resend/webhook

Receives email delivery events from Resend (via Svix). Tracks opens, clicks, bounces, and complaints.


Custom Hostname (White-Label)

Provision Custom Hostname

POST /api/custom-hostname/provision

Creates a Cloudflare Custom Hostname for white-label domain support. The merchant must create a CNAME record pointing to custom.lostchurn.com.

Scopes required: admin

Request body:

FieldTypeRequiredDescription
hostnamestringYesCustom domain (e.g. billing.yourdomain.com)

Verify Custom Hostname

POST /api/custom-hostname/verify

Checks DNS CNAME configuration and updates verification status.

Scopes required: admin

Get Custom Hostname Status

GET /api/custom-hostname/status/:id

Returns current verification status for a custom hostname.

Scopes required: read

Delete Custom Hostname

DELETE /api/custom-hostname/:id

Removes a custom hostname and cleans up KV cache.

Scopes required: admin

Get Merchant Branding

GET /api/custom-hostname/branding/:merchant_id

Returns branding configuration for a merchant's white-label setup. Used by customer-facing pages.

Authentication: None (public, cached).


Email Domain

Auto-Provision Subdomain

POST /api/email-domain/auto-provision

Automatically provisions a LostChurn subdomain for email sending (e.g. acme.mail.lostchurn.com). Handles DNS records and Resend domain setup.

Scopes required: admin

Custom Domain Setup

POST /api/email-domain/custom-setup

Initiates guided custom domain setup for email sending. Returns required DNS records for the merchant to configure.

Scopes required: admin

Verify Domain DNS

POST /api/email-domain/verify

Triggers DNS verification for a pending email domain.

Scopes required: admin

Get Domain Status

GET /api/email-domain/status/:id

Returns domain verification status and DNS diagnostics.

Scopes required: read

Deactivate Domain

DELETE /api/email-domain/:id

Deactivates an email domain and cleans up DNS records.

Scopes required: admin


CRM Integrations

HubSpot OAuth Callback

POST /hubspot/oauth/callback

Handles HubSpot OAuth token exchange during app installation.

HubSpot CRM Sync

POST /hubspot/sync

Syncs recovery data to HubSpot as contacts and timeline events.

Salesforce OAuth Callback

POST /salesforce/oauth/callback

Handles Salesforce OAuth token exchange during connected app installation.

Salesforce CRM Sync

POST /salesforce/sync

Syncs recovery data to Salesforce as Recovery__c custom objects and platform events.

Zapier Subscribe

POST /zapier/subscribe

Registers a Zapier REST Hook subscription for real-time event delivery.

Zapier Unsubscribe

DELETE /zapier/subscribe

Removes a Zapier REST Hook subscription.

Zapier Polling Fallback

GET /zapier/poll/:eventType

Returns the last 50 events of a given type. Used by Zapier as a polling fallback when REST Hooks are unavailable.

Zapier Sample Data

GET /zapier/sample/:eventType

Returns sample event data for Zapier trigger configuration.


Internal Endpoints

These endpoints are used internally by the dashboard and are not part of the public API.

Webhook Payload Retrieval

GET /internal/webhook/:webhook_log_id

Retrieves a stored webhook payload from R2 by log ID.

Authentication: Internal (service binding or CRON_SECRET).

GDPR Webhook Erasure

DELETE /internal/webhook-cleanup/:id

Deletes webhook payloads from R2 for GDPR compliance.

Data Export Upload

POST /internal/exports/upload

Uploads a data export file to R2.

Data Export Download

GET /internal/exports/:merchantId/:jobId

Retrieves a data export file from R2.

Cache Invalidation

POST /api/internal/cache/invalidate

Purges a KV cache entry. Requires CRON_SECRET.

LightGBM Lookup Update

POST /api/internal/scoring/update-lookup

Seeds or updates the LightGBM KV lookup table with pre-computed retry scores from the training pipeline.

Authentication: CRON_SECRET.


WebSocket Proxy

These endpoints support the HttpOnly WebSocket proxy for secure SpacetimeDB connections.

Create WS Session

POST /ws/auth/session

Creates a WebSocket session. Validates Clerk JWT and sets an HttpOnly session cookie.

Refresh WS Session

POST /ws/auth/refresh

Refreshes an existing WebSocket session cookie.

Revoke WS Session

POST /ws/auth/revoke

Revokes a WebSocket session and clears the HttpOnly cookie.

Get WebSocket Token

POST /ws/v1/identity/websocket-token

Proxies a WebSocket token request to SpacetimeDB. Requires valid session cookie.

WebSocket Upgrade

GET /ws/v1/database/:name/subscribe

Upgrades the connection to a WebSocket and proxies to SpacetimeDB. Requires valid session cookie.


Health

Health Check

GET /health

Returns a simple health check response. No authentication required.

Example response:

{ "status": "ok" }

Cron Triggers

The worker runs scheduled tasks via Cloudflare Cron Triggers:

ScheduleTasks
Every minuteFlush Slack notification queue, execute pending retries, dispatch queued messages (SMS/WhatsApp/Voice)
Hourly (0 *)Advance campaign steps, analytics rollup
Daily (0 8)Card expiry checks, pre-dunning notifications, pending domain provisioning, domain warmup, R2 retention cleanup, billing metering

Endpoint Summary

#MethodPathAuthDescription
1GET/api/v1/statusOptionalAPI connection check
2GET/api/v1/paymentsreadList payments
3GET/api/v1/payments/:idreadGet payment
4GET/api/v1/payments/:id/timelinereadPayment timeline
5POST/api/v1/payments/:id/retrywriteRetry payment
6POST/api/v1/payments/:id/pausewritePause recovery
7POST/api/v1/payments/:id/resumewriteResume recovery
8GET/api/v1/customersreadList customers
9GET/api/v1/customers/:idreadGet customer
10GET/api/v1/customers/:id/paymentsreadCustomer payments
11GET/api/v1/customers/:id/recoveriesreadCustomer recoveries
12DELETE/api/v1/customers/:idadminGDPR erasure
13GET/api/v1/recoveriesreadList recoveries
14GET/api/v1/recoveries/:idreadGet recovery
15POST/api/v1/recoveries/:id/dunningwriteTrigger dunning
16GET/api/v1/campaignsreadList campaigns
17GET/api/v1/campaigns/:idreadGet campaign
18POST/api/v1/campaignswriteCreate campaign
19PUT/api/v1/campaigns/:idwriteUpdate campaign
20POST/api/v1/campaigns/:id/activatewriteActivate campaign
21POST/api/v1/campaigns/:id/pausewritePause campaign
22POST/api/v1/campaigns/:id/archivewriteArchive campaign
23GET/api/v1/subscriptions/:idreadSubscription status
24GET/api/v1/subscriptions/:id/failed-invoicesreadFailed invoices
25GET/api/v1/invoices/:idreadInvoice status
26GET/api/v1/invoices/:id/timelinereadInvoice timeline
27GET/api/v1/analytics/recoveryread/analyticsRecovery metrics
28GET/api/v1/analytics/campaignsread/analyticsCampaign metrics
29GET/api/v1/analytics/revenueread/analyticsRevenue metrics
30GET/api/v1/analytics/at-riskread/analyticsAt-risk revenue
31GET/api/v1/analytics/decline-codesread/analyticsDecline distribution
32GET/api/v1/analytics/summaryAlias for recovery
33GET/api/v1/decline-codesreadList decline codes
34GET/api/v1/decline-codes/:codereadGet decline code
35GET/api/v1/decline-codes/categoriesreadDecline categories
36GET/api/v1/webhooks/endpointswebhooksList endpoints
37POST/api/v1/webhooks/endpointswebhooksCreate endpoint
38PUT/api/v1/webhooks/endpoints/:idwebhooksUpdate endpoint
39DELETE/api/v1/webhooks/endpoints/:idwebhooksDelete endpoint
40GET/api/v1/webhooks/eventswebhooksDelivery log
41POST/api/v1/webhooks/endpoints/:id/testwebhooksTest endpoint
42GET/api/v1/settings/quiet-hoursreadGet quiet hours
43POST/api/v1/settings/quiet-hourswriteSet quiet hours
44GET/api/v1/templates/preview/:idreadPreview template
45POST/api/v1/integrations/shopify/registeradminRegister Shopify
46POST/api/v1/ingest/payment-eventwriteIngest event
47POST/api/v1/ai/generatewriteAI text generation
48GET/api/v1/ai/pingNoneAI health check
49POST/api/v1/scoring/retrywriteAI retry scoring
50POST/api/v1/vectors/embed-eventwriteEmbed event
51POST/api/v1/vectors/find-similarreadFind similar
52GET/api/v1/vectors/recommend-strategy/:idreadRecommend strategy
53POST/api/cancel-session/startTokenStart cancel session
54GET/api/cancel-session/:tokenTokenGet session state
55POST/api/cancel-session/:token/advanceTokenAdvance session
56POST/api/cancel-session/:token/completeTokenComplete session
57POST/api/widget/initHMACWidget init
58GET/api/widget/branding/:idNoneWidget branding
59GET/healthNoneHealth check

On this page

REST API ReferenceStatusCheck API ConnectionPaymentsList PaymentsGet a PaymentGet Payment TimelineRetry a PaymentPause RecoveryResume RecoveryCustomersList CustomersGet a CustomerList Customer PaymentsList Customer RecoveriesDelete Customer Data (GDPR Erasure)RecoveriesList RecoveriesGet a RecoveryTrigger Dunning EmailCampaignsList CampaignsGet a CampaignCreate a CampaignUpdate a CampaignActivate a CampaignPause a CampaignArchive a CampaignSubscriptionsGet Subscription Recovery StatusList Failed Invoices for a SubscriptionInvoicesGet Invoice Recovery StatusGet Invoice Recovery TimelineAnalyticsRecovery AnalyticsCampaign AnalyticsRevenue AnalyticsAt-Risk RevenueDecline Code DistributionAnalytics Summary (Alias)Decline CodesList Decline CodesGet Decline CodeList Decline Code CategoriesWebhooks (Outbound)List Webhook EndpointsCreate Webhook EndpointUpdate Webhook EndpointDelete Webhook EndpointList Webhook EventsTest Webhook EndpointSettingsGet Quiet HoursSet Quiet HoursTemplatesPreview Dunning TemplateIntegrationsRegister Shopify StoreIngest Payment EventAI GenerationGenerate AI TextAI Health CheckAI Retry ScoringScore Payment RetryVector SearchEmbed Recovery EventFind Similar RecoveriesRecommend Recovery StrategyCancel SessionsStart a SessionGet Session StateAdvance SessionComplete SessionWidgetInitialize WidgetGet Widget BrandingInbound PSP WebhooksDelivery WebhooksTwilio SMS/WhatsApp StatusTwilio Email StatusResend Email WebhookCustom Hostname (White-Label)Provision Custom HostnameVerify Custom HostnameGet Custom Hostname StatusDelete Custom HostnameGet Merchant BrandingEmail DomainAuto-Provision SubdomainCustom Domain SetupVerify Domain DNSGet Domain StatusDeactivate DomainCRM IntegrationsHubSpot OAuth CallbackHubSpot CRM SyncSalesforce OAuth CallbackSalesforce CRM SyncZapier SubscribeZapier UnsubscribeZapier Polling FallbackZapier Sample DataInternal EndpointsWebhook Payload RetrievalGDPR Webhook ErasureData Export UploadData Export DownloadCache InvalidationLightGBM Lookup UpdateWebSocket ProxyCreate WS SessionRefresh WS SessionRevoke WS SessionGet WebSocket TokenWebSocket UpgradeHealthHealth CheckCron TriggersEndpoint Summary