API REFERENCE v1

DATA

Integrations

The Billing connection object

Billing tools, payment providers, app stores and help desks connected to NoChurn.

ATTRIBUTES

Show 10 more attributesHide 10 attributes
  • available boolean

    The provider's adapter is live on this NoChurn version.

  • webhook_url string | null

    Paste it in the provider's webhook settings (not for Stripe).

  • backfill object
    Show child attributesHide child attributes
    • status enum
      • pending
      • running
      • done
      • failed
    • progress object

      Real counts imported so far, by object (customer, subscription, invoice, payment_method).

    • started_at string | null date-time
    • finished_at string | null date-time
    • error object | null

      Why the import stopped and what to do; null unless it failed.

      Show child attributesHide child attributes
  • False until the provider's webhook secret is pasted (Recurly, Paddle, GoCardless, Razorpay): webhooks are refused until then. Always true for Stripe, for providers that sign webhooks with the API keys (Braintree) and for providers without a webhook secret (Mollie).

  • settings object

    What the account declares for this connection (stores only; {} otherwise).

    Show child attributesHide child attributes
    • refund_review object

      Store refund reviews: NoChurn answers only if customer_consented is true (your app collects the consent); sample_content_provided is sent unless a free trial is seen on the purchase.

      Show child attributesHide child attributes
    • push_audience string

      Google Play: the audience of the Pub/Sub push OIDC token. Set, pushes without a valid Google-signed token are refused.

    • Google Play: the service account that signs the push OIDC token.

  • internal_id object | null

    Where NoChurn reads your app's id for a customer (your user id, stored as external_id) in this tool; null for a tool that carries none (stores, universal webhook). Nothing found: the email decides.

    Show child attributesHide child attributes
    • field string | null

      The field this connection names (PATCH internal_id_field); null = defaults.

    • defaults array of strings

      Read in this order when field is null; user_id is the account's external_id_metadata_key.

    • fields array of strings

      The shapes a field may take for this tool (<name> = one key).

  • last_event_at string | null date-time
  • error string | null
  • created_at string date-time
  • webhook_setup object | null

    Only in the response that creates the connection: webhook credentials to paste in the provider (e.g. Chargebee Basic auth). Shown once.

Schema: BillingConnection

THE BILLING CONNECTION OBJECT
{
  "object": "billing_connection",
  "id": "bcn_WLPj135TCf4cf9uS",
  "provider": "chargebee",
  "livemode": false,
  "status": "active",
  "external_account_id": "acme-test",
  "business_name": "acme-test",
  "capabilities": {
    "retries": "provider",
    "card_update": "provider_portal",
    "offers": ["coupon", "pause"],
    "cancel_via_api": true,
    "disputes": "provider_handles",
    "fraud_warnings": false,
    "webhooks": true,
    "backfill": true
  },
  "available": true,
  "webhook_url": "https://api.nochurn.sh/webhooks/chargebee/-QEPYRNIzgjDa6SdZxc02GO3oW9oHifu",
  "backfill": {
    "status": "pending",
    "progress": {},
    "started_at": null,
    "finished_at": null,
    "error": null
  },
  "webhook_secret_set": true,
  "settings": {},
  "internal_id": {
    "field": null,
    "defaults": ["metadata.user_id", "cf_user_id"],
    "fields": ["metadata.<name>", "cf_<name>", "id"]
  },
  "last_event_at": null,
  "error": null,
  "created_at": "2026-11-04T10:00:00Z",
  "webhook_setup": {
    "basic_auth_username": "nochurn",
    "basic_auth_password": "EXAMPLE00000000000000000",
    "api_version": "v2"
  }
}

Connect a provider with API keys

Providers arrive milestone by milestone: until then, provider_not_available.

  • Secret key (nc_test_… or nc_live_…). Restricted keys need write access.
  • AI apps (OAuth): not available.

BODY PARAMETERS

  • provider enum REQUIRED
    • stripe
    • chargebee
    • recurly
    • maxio
    • zuora
    • paddle
    • lemon_squeezy
    • polar
    • braintree
    • mollie
    • gocardless
    • razorpay
    • app_store
    • google_play
    • custom
  • credentials object

    The fields listed by GET /v1/billing_providers (e.g. site, api_key, region, webhook_secret; App Store: private_key, key_id, issuer_id, bundle_id; Google Play: service_account_json, package_name).

  • settings object

    Stores only: refund_review { customer_consented, sample_content_provided } (booleans); Google Play: push_audience, push_service_account_email ("" clears).

    Show child parametersHide child parameters

RETURNS

ERRORS

POST/v1/billing_connections
curl https://api.nochurn.sh/v1/billing_connections \
  -H "Authorization: Bearer nc_test_…" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "chargebee",
    "credentials": {
      "site": "acme-test",
      "api_key": "test_x"
    }
  }'
const res = await fetch("https://api.nochurn.sh/v1/billing_connections", {
  method: "POST",
  headers: {
    Authorization: "Bearer nc_test_…",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "provider": "chargebee",
    "credentials": {
      "site": "acme-test",
      "api_key": "test_x"
    }
  }),
});
const billingConnection = await res.json();
import requests

res = requests.post(
    "https://api.nochurn.sh/v1/billing_connections",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
    json={
      "provider": "chargebee",
      "credentials": {
        "site": "acme-test",
        "api_key": "test_x"
      }
    },
)
billing_connection = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/billing_connections")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer nc_test_…"
req["Content-Type"] = "application/json"
req.body = {
  "provider" => "chargebee",
  "credentials" => {
    "site" => "acme-test",
    "api_key" => "test_x"
  }
}.to_json

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
billing_connection = JSON.parse(res.body)
RESPONSE 201
{
  "object": "billing_connection",
  "id": "bcn_WLPj135TCf4cf9uS",
  "provider": "chargebee",
  "livemode": false,
  "status": "active",
  "external_account_id": "acme-test",
  "business_name": "acme-test",
  "capabilities": {
    "retries": "provider",
    "card_update": "provider_portal",
    "offers": ["coupon", "pause"],
    "cancel_via_api": true,
    "disputes": "provider_handles",
    "fraud_warnings": false,
    "webhooks": true,
    "backfill": true
  },
  "available": true,
  "webhook_url": "https://api.nochurn.sh/webhooks/chargebee/-QEPYRNIzgjDa6SdZxc02GO3oW9oHifu",
  "backfill": {
    "status": "pending",
    "progress": {},
    "started_at": null,
    "finished_at": null,
    "error": null
  },
  "webhook_secret_set": true,
  "settings": {},
  "internal_id": {
    "field": null,
    "defaults": ["metadata.user_id", "cf_user_id"],
    "fields": ["metadata.<name>", "cf_<name>", "id"]
  },
  "last_event_at": null,
  "error": null,
  "created_at": "2026-11-04T10:00:00Z",
  "webhook_setup": {
    "basic_auth_username": "nochurn",
    "basic_auth_password": "EXAMPLE00000000000000000",
    "api_version": "v2"
  }
}

A billing connection

  • Secret key (nc_test_… or nc_live_…). Restricted keys need read access.
  • AI apps (OAuth): read scope.

PATH PARAMETERS

  • id string REQUIRED

RETURNS

GET/v1/billing_connections/{id}
curl https://api.nochurn.sh/v1/billing_connections/scn_4XXipZYv1tnXU99X \
  -H "Authorization: Bearer nc_test_…"
const res = await fetch("https://api.nochurn.sh/v1/billing_connections/scn_4XXipZYv1tnXU99X", {
  headers: {
    Authorization: "Bearer nc_test_…",
  },
});
const billingConnection = await res.json();
import requests

res = requests.get(
    "https://api.nochurn.sh/v1/billing_connections/scn_4XXipZYv1tnXU99X",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
)
billing_connection = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/billing_connections/scn_4XXipZYv1tnXU99X")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer nc_test_…"

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
billing_connection = JSON.parse(res.body)
RESPONSE 200
{
  "object": "billing_connection",
  "id": "scn_4XXipZYv1tnXU99X",
  "provider": "stripe",
  "livemode": false,
  "status": "active",
  "external_account_id": "acct_test1",
  "business_name": null,
  "capabilities": {
    "retries": "nochurn",
    "card_update": "hosted_page",
    "offers": ["coupon", "pause", "downgrade"],
    "cancel_via_api": true,
    "disputes": "evidence_api",
    "fraud_warnings": true,
    "webhooks": true,
    "backfill": true
  },
  "available": true,
  "webhook_url": null,
  "backfill": {
    "status": "done",
    "progress": {},
    "started_at": null,
    "finished_at": null,
    "error": null
  },
  "webhook_secret_set": true,
  "settings": {},
  "internal_id": {
    "field": null,
    "defaults": ["metadata.user_id"],
    "fields": ["metadata.<name>"]
  },
  "last_event_at": null,
  "error": null,
  "created_at": "2026-11-04T10:00:00Z"
}

Change capabilities, the Stripe retry mode or where your user id is read

  • Secret key (nc_test_… or nc_live_…). Restricted keys need write access.
  • AI apps (OAuth): not available.

PATH PARAMETERS

  • id string REQUIRED

BODY PARAMETERS

RETURNS

PATCH/v1/billing_connections/{id}
curl https://api.nochurn.sh/v1/billing_connections/scn_qHHubuDxvBUkk4ZN \
  -X PATCH \
  -H "Authorization: Bearer nc_test_…" \
  -H "Content-Type: application/json" \
  -d '{
    "smart_retries_mode": "stripe"
  }'
const res = await fetch("https://api.nochurn.sh/v1/billing_connections/scn_qHHubuDxvBUkk4ZN", {
  method: "PATCH",
  headers: {
    Authorization: "Bearer nc_test_…",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "smart_retries_mode": "stripe"
  }),
});
const billingConnection = await res.json();
import requests

res = requests.patch(
    "https://api.nochurn.sh/v1/billing_connections/scn_qHHubuDxvBUkk4ZN",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
    json={
      "smart_retries_mode": "stripe"
    },
)
billing_connection = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/billing_connections/scn_qHHubuDxvBUkk4ZN")
req = Net::HTTP::Patch.new(uri)
req["Authorization"] = "Bearer nc_test_…"
req["Content-Type"] = "application/json"
req.body = {
  "smart_retries_mode" => "stripe"
}.to_json

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
billing_connection = JSON.parse(res.body)
RESPONSE 200
{
  "object": "billing_connection",
  "id": "scn_qHHubuDxvBUkk4ZN",
  "provider": "stripe",
  "livemode": false,
  "status": "active",
  "external_account_id": "acct_test1",
  "business_name": null,
  "capabilities": {
    "retries": "provider",
    "card_update": "hosted_page",
    "offers": ["coupon", "pause", "downgrade"],
    "cancel_via_api": true,
    "disputes": "evidence_api",
    "fraud_warnings": true,
    "webhooks": true,
    "backfill": true
  },
  "available": true,
  "webhook_url": null,
  "backfill": {
    "status": "done",
    "progress": {},
    "started_at": null,
    "finished_at": null,
    "error": null
  },
  "webhook_secret_set": true,
  "settings": {},
  "internal_id": {
    "field": null,
    "defaults": ["metadata.user_id"],
    "fields": ["metadata.<name>"]
  },
  "last_event_at": null,
  "error": null,
  "created_at": "2026-11-04T10:00:00Z"
}

Disconnect (credentials erased; synced data stays)

  • Secret key (nc_test_… or nc_live_…). Restricted keys need write access.
  • AI apps (OAuth): not available.

PATH PARAMETERS

  • id string REQUIRED

RETURNS

DELETE/v1/billing_connections/{id}
curl https://api.nochurn.sh/v1/billing_connections/bcn_G5sqaQTvcqqq3YGa \
  -X DELETE \
  -H "Authorization: Bearer nc_test_…"
const res = await fetch("https://api.nochurn.sh/v1/billing_connections/bcn_G5sqaQTvcqqq3YGa", {
  method: "DELETE",
  headers: {
    Authorization: "Bearer nc_test_…",
  },
});
const billingConnection = await res.json();
import requests

res = requests.delete(
    "https://api.nochurn.sh/v1/billing_connections/bcn_G5sqaQTvcqqq3YGa",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
)
billing_connection = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/billing_connections/bcn_G5sqaQTvcqqq3YGa")
req = Net::HTTP::Delete.new(uri)
req["Authorization"] = "Bearer nc_test_…"

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
billing_connection = JSON.parse(res.body)
RESPONSE 200
{
  "object": "billing_connection",
  "id": "bcn_G5sqaQTvcqqq3YGa",
  "provider": "chargebee",
  "livemode": false,
  "status": "revoked",
  "external_account_id": "acme-test",
  "business_name": null,
  "capabilities": {
    "retries": "provider",
    "card_update": "provider_portal",
    "offers": ["coupon", "pause"],
    "cancel_via_api": true,
    "disputes": "provider_handles",
    "fraud_warnings": false,
    "webhooks": true,
    "backfill": true
  },
  "available": true,
  "webhook_url": null,
  "backfill": {
    "status": "done",
    "progress": {},
    "started_at": null,
    "finished_at": null,
    "error": null
  },
  "webhook_secret_set": false,
  "settings": {},
  "internal_id": {
    "field": null,
    "defaults": ["metadata.user_id", "cf_user_id"],
    "fields": ["metadata.<name>", "cf_<name>", "id"]
  },
  "last_event_at": null,
  "error": null,
  "created_at": "2026-11-04T10:00:00Z"
}

Connected billing providers

Every provider with its capability matrix (what NoChurn can do with it). Stripe keeps /v1/stripe_connections.

  • Secret key (nc_test_… or nc_live_…). Restricted keys need read access.
  • AI apps (OAuth): read scope.

RETURNS

GET/v1/billing_connections
curl https://api.nochurn.sh/v1/billing_connections \
  -H "Authorization: Bearer nc_test_…"
const res = await fetch("https://api.nochurn.sh/v1/billing_connections", {
  headers: {
    Authorization: "Bearer nc_test_…",
  },
});
const page = await res.json();
import requests

res = requests.get(
    "https://api.nochurn.sh/v1/billing_connections",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
)
page = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/billing_connections")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer nc_test_…"

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
page = JSON.parse(res.body)
RESPONSE 200
{
  "object": "list",
  "data": [
    {
      "object": "billing_connection",
      "id": "scn_LVV5Gkx9djjhXDGN",
      "provider": "stripe",
      "livemode": false,
      "status": "active",
      "external_account_id": "acct_test1",
      "business_name": null,
      "capabilities": {
        "retries": "nochurn",
        "card_update": "hosted_page",
        "offers": ["coupon", "pause", "downgrade"],
        "cancel_via_api": true,
        "disputes": "evidence_api",
        "fraud_warnings": true,
        "webhooks": true,
        "backfill": true
      },
      "available": true,
      "webhook_url": null,
      "backfill": {
        "status": "done",
        "progress": {},
        "started_at": null,
        "finished_at": null,
        "error": null
      },
      "webhook_secret_set": true,
      "settings": {},
      "internal_id": {
        "field": null,
        "defaults": ["metadata.user_id"],
        "fields": ["metadata.<name>"]
      },
      "last_event_at": null,
      "error": null,
      "created_at": "2026-11-04T10:00:00Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Import again (12 months)

  • Secret key (nc_test_… or nc_live_…). Restricted keys need write access.
  • AI apps (OAuth): not available.

PATH PARAMETERS

  • id string REQUIRED

RETURNS

POST/v1/billing_connections/{id}/backfill
curl https://api.nochurn.sh/v1/billing_connections/scn_LVV5Gkx9djjhXDGN/backfill \
  -X POST \
  -H "Authorization: Bearer nc_test_…"
const res = await fetch("https://api.nochurn.sh/v1/billing_connections/scn_LVV5Gkx9djjhXDGN/backfill", {
  method: "POST",
  headers: {
    Authorization: "Bearer nc_test_…",
  },
});
const billingConnection = await res.json();
import requests

res = requests.post(
    "https://api.nochurn.sh/v1/billing_connections/scn_LVV5Gkx9djjhXDGN/backfill",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
)
billing_connection = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/billing_connections/scn_LVV5Gkx9djjhXDGN/backfill")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer nc_test_…"

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
billing_connection = JSON.parse(res.body)
RESPONSE 202
{
  "object": "billing_connection",
  "id": "bcn_bd2nxUWHSGoShYqJ",
  "provider": "chargebee",
  "livemode": false,
  "status": "active",
  "external_account_id": "acme-test",
  "business_name": null,
  "capabilities": {
    "retries": "provider",
    "card_update": "provider_portal",
    "offers": ["coupon", "pause"],
    "cancel_via_api": true,
    "disputes": "provider_handles",
    "fraud_warnings": false,
    "webhooks": true,
    "backfill": true
  },
  "available": true,
  "webhook_url": "https://api.nochurn.sh/webhooks/chargebee/tok_cb2",
  "backfill": {
    "status": "pending",
    "progress": {},
    "started_at": null,
    "finished_at": null,
    "error": null
  },
  "webhook_secret_set": false,
  "settings": {},
  "internal_id": {
    "field": null,
    "defaults": ["metadata.user_id", "cf_user_id"],
    "fields": ["metadata.<name>", "cf_<name>", "id"]
  },
  "last_event_at": null,
  "error": null,
  "created_at": "2026-11-04T10:00:00Z"
}

Billing providers (supported and coming)

  • Secret key (nc_test_… or nc_live_…). Restricted keys need read access.
  • AI apps (OAuth): read scope.

RETURNS

GET/v1/billing_providers
curl https://api.nochurn.sh/v1/billing_providers \
  -H "Authorization: Bearer nc_test_…"
const res = await fetch("https://api.nochurn.sh/v1/billing_providers", {
  headers: {
    Authorization: "Bearer nc_test_…",
  },
});
const page = await res.json();
import requests

res = requests.get(
    "https://api.nochurn.sh/v1/billing_providers",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
)
page = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/billing_providers")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer nc_test_…"

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
page = JSON.parse(res.body)
RESPONSE 200
{
  "object": "list",
  "data": [
    {
      "object": "billing_provider",
      "provider": "stripe",
      "family": "billing",
      "available": true,
      "connect": "oauth",
      "credentials": [],
      "capabilities": {
        "retries": "provider",
        "card_update": "hosted_page",
        "offers": ["coupon", "pause", "downgrade"],
        "cancel_via_api": true,
        "disputes": "evidence_api",
        "fraud_warnings": true,
        "webhooks": true,
        "backfill": true
      },
      "locked": [],
      "webhook_secret": "none",
      "hint": null,
      "docs_url": "https://nochurn.sh/docs/integrations/stripe/"
    },
    {
      "object": "billing_provider",
      "provider": "chargebee",
      "family": "billing",
      "available": true,
      "connect": "credentials",
      "credentials": [
        {
          "name": "site",
          "secret": false,
          "hint": "The part before .chargebee.com (test site: <name>-test)"
        },
        {
          "name": "api_key",
          "secret": true,
          "hint": "Settings › Configure Chargebee › API keys (full access)"
        }
      ],
      "capabilities": {
        "retries": "provider",
        "card_update": "provider_portal",
        "offers": ["coupon", "pause"],
        "cancel_via_api": true,
        "disputes": "provider_handles",
        "fraud_warnings": false,
        "webhooks": true,
        "backfill": true
      },
      "locked": [],
      "webhook_secret": "generated",
      "hint": null,
      "docs_url": "https://nochurn.sh/docs/integrations/chargebee/"
    },
    {
      "object": "billing_provider",
      "provider": "recurly",
      "family": "billing",
      "available": true,
      "connect": "credentials",
      "credentials": [
        {
          "name": "api_key",
          "secret": true,
          "hint": "Integrations › API credentials (private key)"
        },
        {
          "name": "region",
          "secret": false,
          "hint": "us or eu",
          "options": ["us", "eu"]
        }
      ],
      "capabilities": {
        "retries": "provider",
        "card_update": "provider_portal",
        "offers": ["coupon", "pause"],
        "cancel_via_api": true,
        "disputes": "provider_handles",
        "fraud_warnings": false,
        "webhooks": true,
        "backfill": true
      },
      "locked": [],
      "webhook_secret": "pasted",
      "hint": null,
      "docs_url": "https://nochurn.sh/docs/integrations/recurly/"
    },
    {
      "object": "billing_provider",
      "provider": "maxio",
      "family": "billing",
      "available": true,
      "connect": "credentials",
      "credentials": [
        {
          "name": "subdomain",
          "secret": false,
          "hint": "The part before .chargify.com, or the full address of an EU site (acme.ebilling.maxio.com). A site in test mode in Test mode"
        },
        {
          "name": "api_key",
          "secret": true,
          "hint": "Config › Integrations › API keys"
        },
        {
          "name": "site_shared_key",
          "secret": true,
          "hint": "Config › Settings › Site shared key: signs the webhooks"
        }
      ],
      "capabilities": {
        "retries": "provider",
        "card_update": "provider_portal",
        "offers": ["coupon"],
        "cancel_via_api": true,
        "disputes": "provider_handles",
        "fraud_warnings": false,
        "webhooks": true,
        "backfill": true
      },
      "locked": [],
      "webhook_secret": "none",
      "hint": null,
      "docs_url": "https://nochurn.sh/docs/integrations/maxio/"
    },
    {
      "object": "billing_provider",
      "provider": "zuora",
      "family": "billing",
      "available": true,
      "connect": "credentials",
      "credentials": [
        {
          "name": "environment",
          "secret": false,
          "hint": "Where your tenant lives (sandbox or test in Test mode)",
          "options": [
            "sandbox",
            "test",
            "na_sandbox",
            "eu_sandbox",
            "eu_test",
            "ap_test",
            "production",
            "na_production",
            "eu_production",
            "ap_production"
          ]
        },
        {
          "name": "client_id",
          "secret": false,
          "hint": "Settings › Administration › Manage users › OAuth client (API user with read and subscription rights)"
        },
        {
          "name": "client_secret",
          "secret": true,
          "hint": "Shown once when the OAuth client is created"
        }
      ],
      "capabilities": {
        "retries": "provider",
        "card_update": "none",
        "offers": ["pause"],
        "cancel_via_api": true,
        "disputes": "provider_handles",
        "fraud_warnings": false,
        "webhooks": false,
        "backfill": true
      },
      "locked": ["card_update"],
      "webhook_secret": "none",
      "hint": "NoChurn reads your Zuora tenant every 10 minutes (accounts, subscriptions, invoices, payments): no callout to configure. Retries and the payment page stay with Zuora.",
      "docs_url": "https://nochurn.sh/docs/integrations/zuora/"
    },
    {
      "object": "billing_provider",
      "provider": "paddle",
      "family": "merchant_of_record",
      "available": true,
      "connect": "credentials",
      "credentials": [
        {
          "name": "api_key",
          "secret": true,
          "hint": "Developer tools › Authentication (sandbox key in Test mode), with the Customer portal session permission (card update links)"
        }
      ],
      "capabilities": {
        "retries": "provider",
        "card_update": "provider_portal",
        "offers": ["coupon", "pause"],
        "cancel_via_api": true,
        "disputes": "provider_handles",
        "fraud_warnings": false,
        "webhooks": true,
        "backfill": true
      },
      "locked": ["retries", "disputes"],
      "webhook_secret": "pasted",
      "hint": null,
      "docs_url": "https://nochurn.sh/docs/integrations/paddle/"
    },
    {
      "object": "billing_provider",
      "provider": "lemon_squeezy",
      "family": "merchant_of_record",
      "available": true,
      "connect": "credentials",
      "credentials": [
        {
          "name": "api_key",
          "secret": true,
          "hint": "Settings › API (a test mode key in Test mode)"
        },
        {
          "name": "store_id",
          "secret": false,
          "hint": "Settings › Stores: the store's number"
        }
      ],
      "capabilities": {
        "retries": "provider",
        "card_update": "provider_portal",
        "offers": ["pause"],
        "cancel_via_api": true,
        "disputes": "provider_handles",
        "fraud_warnings": false,
        "webhooks": true,
        "backfill": true
      },
      "locked": ["retries", "disputes"],
      "webhook_secret": "pasted",
      "hint": null,
      "docs_url": "https://nochurn.sh/docs/integrations/lemon-squeezy/"
    },
    {
      "object": "billing_provider",
      "provider": "polar",
      "family": "merchant_of_record",
      "available": true,
      "connect": "credentials",
      "credentials": [
        {
          "name": "access_token",
          "secret": true,
          "hint": "Settings › Developers › Organization access token (a sandbox.polar.sh token in Test mode)"
        }
      ],
      "capabilities": {
        "retries": "provider",
        "card_update": "provider_portal",
        "offers": ["coupon", "pause"],
        "cancel_via_api": true,
        "disputes": "provider_handles",
        "fraud_warnings": false,
        "webhooks": true,
        "backfill": true
      },
      "locked": ["retries", "disputes"],
      "webhook_secret": "pasted",
      "hint": "Create a webhook endpoint in Polar › Settings › Webhooks with webhook_url, format Raw and API version 2026-10 (the version NoChurn reads), then paste its secret (whsec_…) here.",
      "docs_url": "https://nochurn.sh/docs/integrations/polar/"
    },
    {
      "object": "billing_provider",
      "provider": "braintree",
      "family": "payments",
      "available": true,
      "connect": "credentials",
      "credentials": [
        {
          "name": "merchant_id",
          "secret": false,
          "hint": "Settings › Business (sandbox account in Test mode)"
        },
        {
          "name": "public_key",
          "secret": false,
          "hint": "Settings › API › API keys"
        },
        {
          "name": "private_key",
          "secret": true,
          "hint": "Settings › API › API keys (View)"
        }
      ],
      "capabilities": {
        "retries": "provider",
        "card_update": "none",
        "offers": ["coupon"],
        "cancel_via_api": true,
        "disputes": "evidence_api",
        "fraud_warnings": false,
        "webhooks": true,
        "backfill": true
      },
      "locked": ["card_update"],
      "webhook_secret": "none",
      "hint": null,
      "docs_url": "https://nochurn.sh/docs/integrations/braintree/"
    },
    {
      "object": "billing_provider",
      "provider": "mollie",
      "family": "payments",
      "available": true,
      "connect": "credentials",
      "credentials": [
        {
          "name": "api_key",
          "secret": true,
          "hint": "Developers › API keys (test_… in Test mode, live_… in Live mode)"
        }
      ],
      "capabilities": {
        "retries": "nochurn",
        "card_update": "hosted_page",
        "offers": [],
        "cancel_via_api": true,
        "disputes": "none",
        "fraud_warnings": false,
        "webhooks": true,
        "backfill": true
      },
      "locked": ["disputes"],
      "webhook_secret": "none",
      "hint": null,
      "docs_url": "https://nochurn.sh/docs/integrations/mollie/"
    },
    {
      "object": "billing_provider",
      "provider": "gocardless",
      "family": "payments",
      "available": true,
      "connect": "credentials",
      "credentials": [
        {
          "name": "access_token",
          "secret": true,
          "hint": "Developers › Create › Access token, read-write (sandbox token in Test mode)"
        }
      ],
      "capabilities": {
        "retries": "nochurn",
        "card_update": "hosted_page",
        "offers": ["pause"],
        "cancel_via_api": true,
        "disputes": "none",
        "fraud_warnings": false,
        "webhooks": true,
        "backfill": true
      },
      "locked": ["disputes"],
      "webhook_secret": "pasted",
      "hint": null,
      "docs_url": "https://nochurn.sh/docs/integrations/gocardless/"
    },
    {
      "object": "billing_provider",
      "provider": "razorpay",
      "family": "payments",
      "available": true,
      "connect": "credentials",
      "credentials": [
        {
          "name": "key_id",
          "secret": false,
          "hint": "Account & Settings › API keys (rzp_test_… in Test mode)"
        },
        {
          "name": "key_secret",
          "secret": true,
          "hint": "Shown once when the key is generated"
        }
      ],
      "capabilities": {
        "retries": "provider",
        "card_update": "provider_portal",
        "offers": ["pause"],
        "cancel_via_api": true,
        "disputes": "evidence_api",
        "fraud_warnings": false,
        "webhooks": true,
        "backfill": true
      },
      "locked": ["retries", "offers"],
      "webhook_secret": "pasted",
      "hint": null,
      "docs_url": "https://nochurn.sh/docs/integrations/razorpay/"
    },
    {
      "object": "billing_provider",
      "provider": "app_store",
      "family": "stores",
      "available": true,
      "connect": "credentials",
      "credentials": [
        {
          "name": "private_key",
          "secret": true,
          "hint": "The .p8 file of an In-App Purchase key (App Store Connect › Users and Access › Integrations › In-App Purchase), pasted whole"
        },
        {
          "name": "key_id",
          "secret": false,
          "hint": "The key's ID, next to it in App Store Connect"
        },
        {
          "name": "issuer_id",
          "secret": false,
          "hint": "Issuer ID, at the top of the same page"
        },
        {
          "name": "bundle_id",
          "secret": false,
          "hint": "Your app's bundle ID (e.g. com.acme.app)"
        }
      ],
      "capabilities": {
        "retries": "none",
        "card_update": "none",
        "offers": [],
        "cancel_via_api": false,
        "disputes": "refund_review",
        "fraud_warnings": false,
        "webhooks": true,
        "backfill": true
      },
      "locked": ["retries", "card_update", "disputes"],
      "webhook_secret": "none",
      "hint": "Apple shares no email: customers are linked only when your app sets an appAccountToken at purchase and sends it to NoChurn (as the external_id, or the app_account_token attribute of the customer). Without it, events stay unlinked. Paste webhook_url as the App Store Server Notifications V2 URL (sandbox URL in Test mode).",
      "docs_url": "https://nochurn.sh/docs/integrations/app-store/"
    },
    {
      "object": "billing_provider",
      "provider": "google_play",
      "family": "stores",
      "available": true,
      "connect": "credentials",
      "credentials": [
        {
          "name": "service_account_json",
          "secret": true,
          "hint": "JSON key of a Google Cloud service account invited in Play Console › Users and permissions (view financial data, manage orders and subscriptions)"
        },
        {
          "name": "package_name",
          "secret": false,
          "hint": "Your app's package name (e.g. com.acme.app)"
        }
      ],
      "capabilities": {
        "retries": "none",
        "card_update": "none",
        "offers": [],
        "cancel_via_api": true,
        "disputes": "refund_review",
        "fraud_warnings": false,
        "webhooks": true,
        "backfill": true
      },
      "locked": ["retries", "card_update", "disputes"],
      "webhook_secret": "none",
      "hint": "Customers are linked only when your app sets obfuscatedAccountId at purchase and sends it to NoChurn (as the external_id, or the obfuscated_account_id attribute of the customer). Without it, events stay unlinked. Create a Pub/Sub push subscription to webhook_url on the topic of your real-time developer notifications. Test mode applies license testers' purchases only.",
      "docs_url": "https://nochurn.sh/docs/integrations/google-play/"
    },
    {
      "object": "billing_provider",
      "provider": "custom",
      "family": "custom",
      "available": true,
      "connect": "credentials",
      "credentials": [
        {
          "name": "name",
          "secret": false,
          "hint": "The name of your billing system, as shown in NoChurn"
        },
        {
          "name": "signature_mode",
          "secret": false,
          "hint": "How your billing system signs its webhooks",
          "options": ["hmac_sha256", "header_secret"]
        },
        {
          "name": "signature_header",
          "secret": false,
          "hint": "The header carrying the signature or the secret (e.g. X-Signature)"
        },
        {
          "name": "signature_encoding",
          "secret": false,
          "hint": "HMAC only: how the signature is written",
          "options": ["hex", "base64"]
        }
      ],
      "capabilities": {
        "retries": "none",
        "card_update": "none",
        "offers": [],
        "cancel_via_api": false,
        "disputes": "none",
        "fraud_warnings": false,
        "webhooks": true,
        "backfill": false
      },
      "locked": [
        "retries",
        "card_update",
        "offers",
        "cancel_via_api",
        "disputes",
        "fraud_warnings",
        "webhooks",
        "backfill"
      ],
      "webhook_secret": "pasted",
      "hint": null,
      "docs_url": "https://nochurn.sh/docs/integrations/custom/"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Mapping of a custom billing connection, tested on its sample

  • Secret key (nc_test_… or nc_live_…). Restricted keys need read access.
  • AI apps (OAuth): read scope.

PATH PARAMETERS

RETURNS

GET/v1/billing_connections/{billing_connection_id}/mapping
curl https://api.nochurn.sh/v1/billing_connections/scn_LVV5Gkx9djjhXDGN/mapping \
  -H "Authorization: Bearer nc_test_…"
const res = await fetch("https://api.nochurn.sh/v1/billing_connections/scn_LVV5Gkx9djjhXDGN/mapping", {
  headers: {
    Authorization: "Bearer nc_test_…",
  },
});
const billingMapping = await res.json();
import requests

res = requests.get(
    "https://api.nochurn.sh/v1/billing_connections/scn_LVV5Gkx9djjhXDGN/mapping",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
)
billing_mapping = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/billing_connections/scn_LVV5Gkx9djjhXDGN/mapping")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer nc_test_…"

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
billing_mapping = JSON.parse(res.body)
RESPONSE 200
{
  "object": "billing_mapping",
  "billing_connection": "bcn_pEFhqdfNzf8kNZu4",
  "active": false,
  "activated_at": null,
  "rules": [],
  "types": [
    "customer.upserted",
    "subscription.created",
    "subscription.updated",
    "subscription.paused",
    "subscription.resumed",
    "subscription.canceled",
    "subscription.renewed",
    "invoice.paid",
    "invoice.payment_failed",
    "invoice.uncollectible",
    "invoice.updated"
  ],
  "fields": {
    "customer": ["id", "email", "name", "country", "locale", "external_id"],
    "subscription": [
      "id",
      "status",
      "plan",
      "amount_cents",
      "currency",
      "interval",
      "interval_count",
      "current_period_end",
      "cancel_at_period_end",
      "started_at",
      "canceled_at",
      "ended_at"
    ],
    "invoice": [
      "id",
      "subscription_id",
      "status",
      "amount_due_cents",
      "amount_paid_cents",
      "amount_remaining_cents",
      "currency",
      "attempt_count",
      "decline_code",
      "failure_code",
      "next_attempt_at",
      "hosted_invoice_url"
    ]
  },
  "transforms": [
    "units_to_cents",
    "unix_seconds",
    "unix_millis",
    "lowercase",
    "boolean",
    "string"
  ],
  "sample": [
    {
      "id": "bws_UdGw7Rgf3vMuJkXV",
      "received_at": "2026-11-04T10:00:00Z",
      "payload": {
        "id": "wh_1",
        "data": {
          "email": "ana@example.test",
          "amount": "49.90",
          "invoice": "inv_wh_1",
          "currency": "eur",
          "customer": "c_1"
        },
        "type": "invoice.failed"
      },
      "result": {
        "status": "ignored",
        "rule": null,
        "type": null,
        "event_id": null,
        "data": null,
        "errors": []
      }
    }
  ],
  "summary": {
    "total": 1,
    "events": 0,
    "errors": 0,
    "ignored": 1
  }
}

Save the mapping rules (tested on the sample)

  • Secret key (nc_test_… or nc_live_…). Restricted keys need write access.
  • AI apps (OAuth): not available.

PATH PARAMETERS

BODY PARAMETERS

  • rules array of objects REQUIRED

RETURNS

ERRORS

PUT/v1/billing_connections/{billing_connection_id}/mapping
curl https://api.nochurn.sh/v1/billing_connections/scn_LVV5Gkx9djjhXDGN/mapping \
  -X PUT \
  -H "Authorization: Bearer nc_test_…" \
  -H "Content-Type: application/json" \
  -d '{
    "rules": [
      {
        "when": {
          "path": "$.type",
          "equals": "invoice.failed"
        },
        "type": "invoice.payment_failed",
        "event_id": "$.id",
        "fields": {
          "customer.id": "$.data.customer",
          "customer.email": "$.data.email",
          "invoice.id": "$.data.invoice",
          "invoice.amount_due_cents": {
            "path": "$.data.amount",
            "transform": "units_to_cents"
          },
          "invoice.currency": "$.data.currency"
        }
      }
    ]
  }'
const res = await fetch("https://api.nochurn.sh/v1/billing_connections/scn_LVV5Gkx9djjhXDGN/mapping", {
  method: "PUT",
  headers: {
    Authorization: "Bearer nc_test_…",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "rules": [
      {
        "when": {
          "path": "$.type",
          "equals": "invoice.failed"
        },
        "type": "invoice.payment_failed",
        "event_id": "$.id",
        "fields": {
          "customer.id": "$.data.customer",
          "customer.email": "$.data.email",
          "invoice.id": "$.data.invoice",
          "invoice.amount_due_cents": {
            "path": "$.data.amount",
            "transform": "units_to_cents"
          },
          "invoice.currency": "$.data.currency"
        }
      }
    ]
  }),
});
const billingMapping = await res.json();
import requests

res = requests.put(
    "https://api.nochurn.sh/v1/billing_connections/scn_LVV5Gkx9djjhXDGN/mapping",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
    json={
      "rules": [
        {
          "when": {
            "path": "$.type",
            "equals": "invoice.failed"
          },
          "type": "invoice.payment_failed",
          "event_id": "$.id",
          "fields": {
            "customer.id": "$.data.customer",
            "customer.email": "$.data.email",
            "invoice.id": "$.data.invoice",
            "invoice.amount_due_cents": {
              "path": "$.data.amount",
              "transform": "units_to_cents"
            },
            "invoice.currency": "$.data.currency"
          }
        }
      ]
    },
)
billing_mapping = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/billing_connections/scn_LVV5Gkx9djjhXDGN/mapping")
req = Net::HTTP::Put.new(uri)
req["Authorization"] = "Bearer nc_test_…"
req["Content-Type"] = "application/json"
req.body = {
  "rules" => [
    {
      "when" => {
        "path" => "$.type",
        "equals" => "invoice.failed"
      },
      "type" => "invoice.payment_failed",
      "event_id" => "$.id",
      "fields" => {
        "customer.id" => "$.data.customer",
        "customer.email" => "$.data.email",
        "invoice.id" => "$.data.invoice",
        "invoice.amount_due_cents" => {
          "path" => "$.data.amount",
          "transform" => "units_to_cents"
        },
        "invoice.currency" => "$.data.currency"
      }
    }
  ]
}.to_json

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
billing_mapping = JSON.parse(res.body)
RESPONSE 200
{
  "object": "billing_mapping",
  "billing_connection": "bcn_mVxfYN2KgqTevEbE",
  "active": false,
  "activated_at": null,
  "rules": [
    {
      "when": {
        "path": "$.type",
        "equals": "invoice.failed"
      },
      "type": "invoice.payment_failed",
      "event_id": "$.id",
      "fields": {
        "customer.id": "$.data.customer",
        "customer.email": "$.data.email",
        "invoice.id": "$.data.invoice",
        "invoice.amount_due_cents": {
          "path": "$.data.amount",
          "transform": "units_to_cents"
        },
        "invoice.currency": "$.data.currency"
      }
    }
  ],
  "types": [
    "customer.upserted",
    "subscription.created",
    "subscription.updated",
    "subscription.paused",
    "subscription.resumed",
    "subscription.canceled",
    "subscription.renewed",
    "invoice.paid",
    "invoice.payment_failed",
    "invoice.uncollectible",
    "invoice.updated"
  ],
  "fields": {
    "customer": ["id", "email", "name", "country", "locale", "external_id"],
    "subscription": [
      "id",
      "status",
      "plan",
      "amount_cents",
      "currency",
      "interval",
      "interval_count",
      "current_period_end",
      "cancel_at_period_end",
      "started_at",
      "canceled_at",
      "ended_at"
    ],
    "invoice": [
      "id",
      "subscription_id",
      "status",
      "amount_due_cents",
      "amount_paid_cents",
      "amount_remaining_cents",
      "currency",
      "attempt_count",
      "decline_code",
      "failure_code",
      "next_attempt_at",
      "hosted_invoice_url"
    ]
  },
  "transforms": [
    "units_to_cents",
    "unix_seconds",
    "unix_millis",
    "lowercase",
    "boolean",
    "string"
  ],
  "sample": [
    {
      "id": "bws_rcEbEUxNJYg4jyS4",
      "received_at": "2026-11-04T10:00:00Z",
      "payload": {
        "id": "wh_1",
        "data": {
          "email": "ana@example.test",
          "amount": "49.90",
          "invoice": "inv_wh_1",
          "currency": "eur",
          "customer": "c_1"
        },
        "type": "invoice.failed"
      },
      "result": {
        "status": "event",
        "rule": 0,
        "type": "invoice.payment_failed",
        "event_id": "wh_1",
        "data": {
          "invoice": {
            "currency": "eur",
            "id": "inv_wh_1",
            "amount_due_cents": 4990
          },
          "customer": {
            "id": "c_1",
            "email": "ana@example.test"
          }
        },
        "errors": []
      }
    }
  ],
  "summary": {
    "total": 1,
    "events": 1,
    "errors": 0,
    "ignored": 0
  }
}

Turn the mapping on (the sample must pass)

  • Secret key (nc_test_… or nc_live_…). Restricted keys need write access.
  • AI apps (OAuth): not available.

PATH PARAMETERS

RETURNS

ERRORS

  • 409 conflict the sample does not pass yet
POST/v1/billing_connections/{billing_connection_id}/mapping/activate
curl https://api.nochurn.sh/v1/billing_connections/scn_LVV5Gkx9djjhXDGN/mapping/activate \
  -X POST \
  -H "Authorization: Bearer nc_test_…"
const res = await fetch("https://api.nochurn.sh/v1/billing_connections/scn_LVV5Gkx9djjhXDGN/mapping/activate", {
  method: "POST",
  headers: {
    Authorization: "Bearer nc_test_…",
  },
});
const billingMapping = await res.json();
import requests

res = requests.post(
    "https://api.nochurn.sh/v1/billing_connections/scn_LVV5Gkx9djjhXDGN/mapping/activate",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
)
billing_mapping = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/billing_connections/scn_LVV5Gkx9djjhXDGN/mapping/activate")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer nc_test_…"

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
billing_mapping = JSON.parse(res.body)
RESPONSE 200
{
  "object": "billing_mapping",
  "billing_connection": "bcn_7ihcvkgpzms1J5ee",
  "active": true,
  "activated_at": "2026-11-04T10:00:00Z",
  "rules": [
    {
      "type": "invoice.payment_failed",
      "when": {
        "path": "$.type",
        "equals": "invoice.failed"
      },
      "fields": {
        "invoice.id": "$.data.invoice",
        "customer.id": "$.data.customer",
        "customer.email": "$.data.email",
        "invoice.currency": "$.data.currency",
        "invoice.amount_due_cents": {
          "path": "$.data.amount",
          "transform": "units_to_cents"
        }
      },
      "event_id": "$.id"
    }
  ],
  "types": [
    "customer.upserted",
    "subscription.created",
    "subscription.updated",
    "subscription.paused",
    "subscription.resumed",
    "subscription.canceled",
    "subscription.renewed",
    "invoice.paid",
    "invoice.payment_failed",
    "invoice.uncollectible",
    "invoice.updated"
  ],
  "fields": {
    "customer": ["id", "email", "name", "country", "locale", "external_id"],
    "subscription": [
      "id",
      "status",
      "plan",
      "amount_cents",
      "currency",
      "interval",
      "interval_count",
      "current_period_end",
      "cancel_at_period_end",
      "started_at",
      "canceled_at",
      "ended_at"
    ],
    "invoice": [
      "id",
      "subscription_id",
      "status",
      "amount_due_cents",
      "amount_paid_cents",
      "amount_remaining_cents",
      "currency",
      "attempt_count",
      "decline_code",
      "failure_code",
      "next_attempt_at",
      "hosted_invoice_url"
    ]
  },
  "transforms": [
    "units_to_cents",
    "unix_seconds",
    "unix_millis",
    "lowercase",
    "boolean",
    "string"
  ],
  "sample": [
    {
      "id": "bws_VCjNWusA1bhGbbGR",
      "received_at": "2026-11-04T10:00:00Z",
      "payload": {
        "id": "wh_1",
        "data": {
          "email": "ana@example.test",
          "amount": "49.90",
          "invoice": "inv_wh_1",
          "currency": "eur",
          "customer": "c_1"
        },
        "type": "invoice.failed"
      },
      "result": {
        "status": "event",
        "rule": 0,
        "type": "invoice.payment_failed",
        "event_id": "wh_1",
        "data": {
          "invoice": {
            "currency": "eur",
            "id": "inv_wh_1",
            "amount_due_cents": 4990
          },
          "customer": {
            "id": "c_1",
            "email": "ana@example.test"
          }
        },
        "errors": []
      }
    }
  ],
  "summary": {
    "total": 1,
    "events": 1,
    "errors": 0,
    "ignored": 0
  }
}

Turn the mapping off (webhooks are only kept as a sample)

  • Secret key (nc_test_… or nc_live_…). Restricted keys need write access.
  • AI apps (OAuth): not available.

PATH PARAMETERS

RETURNS

POST/v1/billing_connections/{billing_connection_id}/mapping/deactivate
curl https://api.nochurn.sh/v1/billing_connections/scn_LVV5Gkx9djjhXDGN/mapping/deactivate \
  -X POST \
  -H "Authorization: Bearer nc_test_…"
const res = await fetch("https://api.nochurn.sh/v1/billing_connections/scn_LVV5Gkx9djjhXDGN/mapping/deactivate", {
  method: "POST",
  headers: {
    Authorization: "Bearer nc_test_…",
  },
});
const billingMapping = await res.json();
import requests

res = requests.post(
    "https://api.nochurn.sh/v1/billing_connections/scn_LVV5Gkx9djjhXDGN/mapping/deactivate",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
)
billing_mapping = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/billing_connections/scn_LVV5Gkx9djjhXDGN/mapping/deactivate")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer nc_test_…"

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
billing_mapping = JSON.parse(res.body)
RESPONSE 200
{
  "object": "billing_mapping",
  "billing_connection": "bcn_omV4hFm5EZYzNGTC",
  "active": false,
  "activated_at": null,
  "rules": [],
  "types": [
    "customer.upserted",
    "subscription.created",
    "subscription.updated",
    "subscription.paused",
    "subscription.resumed",
    "subscription.canceled",
    "subscription.renewed",
    "invoice.paid",
    "invoice.payment_failed",
    "invoice.uncollectible",
    "invoice.updated"
  ],
  "fields": {
    "customer": ["id", "email", "name", "country", "locale", "external_id"],
    "subscription": [
      "id",
      "status",
      "plan",
      "amount_cents",
      "currency",
      "interval",
      "interval_count",
      "current_period_end",
      "cancel_at_period_end",
      "started_at",
      "canceled_at",
      "ended_at"
    ],
    "invoice": [
      "id",
      "subscription_id",
      "status",
      "amount_due_cents",
      "amount_paid_cents",
      "amount_remaining_cents",
      "currency",
      "attempt_count",
      "decline_code",
      "failure_code",
      "next_attempt_at",
      "hosted_invoice_url"
    ]
  },
  "transforms": [
    "units_to_cents",
    "unix_seconds",
    "unix_millis",
    "lowercase",
    "boolean",
    "string"
  ],
  "sample": [],
  "summary": {
    "total": 0,
    "events": 0,
    "errors": 0,
    "ignored": 0
  }
}

Connected tools

  • Secret key (nc_test_… or nc_live_…). Restricted keys need read access.
  • AI apps (OAuth): read scope.

RETURNS

GET/v1/integrations
curl https://api.nochurn.sh/v1/integrations \
  -H "Authorization: Bearer nc_test_…"
const res = await fetch("https://api.nochurn.sh/v1/integrations", {
  headers: {
    Authorization: "Bearer nc_test_…",
  },
});
const page = await res.json();
import requests

res = requests.get(
    "https://api.nochurn.sh/v1/integrations",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
)
page = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/integrations")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer nc_test_…"

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
page = JSON.parse(res.body)
RESPONSE 200
{
  "object": "list",
  "has_more": false,
  "next_cursor": null,
  "data": [
    {
      "object": "integration",
      "id": "itg_GryteF3meCbHffEf",
      "kind": "slack",
      "status": "active",
      "external_account": "Acme",
      "config": {},
      "last_synced_at": null,
      "error": null,
      "conversations_count": null,
      "created_at": "2026-11-04T10:00:00Z"
    }
  ]
}

Connect Crisp (website or plugin token) or Gorgias (REST API key)

Crisp: identifier, key (a website token from Settings › Workspace Settings › Advanced configuration › API Token, or a Marketplace plugin token), website_id. Gorgias: domain (the part before .gorgias.com), email and api_key (Settings › Account › REST API). Read only; credentials are encrypted and never returned.

  • Secret key (nc_test_… or nc_live_…). Restricted keys need write access.
  • AI apps (OAuth): not available.

BODY PARAMETERS

One of:

RETURNS

ERRORS

  • 400 invalid_request Crisp refused the credentials or does not know the website
POST/v1/integrations
curl https://api.nochurn.sh/v1/integrations \
  -H "Authorization: Bearer nc_test_…" \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "crisp",
    "identifier": "id_test",
    "key": "key_test",
    "website_id": "8c1f3f52-2a8a-4d6b-9a0e-6f1f2c3d4e5f"
  }'
const res = await fetch("https://api.nochurn.sh/v1/integrations", {
  method: "POST",
  headers: {
    Authorization: "Bearer nc_test_…",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "kind": "crisp",
    "identifier": "id_test",
    "key": "key_test",
    "website_id": "8c1f3f52-2a8a-4d6b-9a0e-6f1f2c3d4e5f"
  }),
});
const integration = await res.json();
import requests

res = requests.post(
    "https://api.nochurn.sh/v1/integrations",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
    json={
      "kind": "crisp",
      "identifier": "id_test",
      "key": "key_test",
      "website_id": "8c1f3f52-2a8a-4d6b-9a0e-6f1f2c3d4e5f"
    },
)
integration = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/integrations")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer nc_test_…"
req["Content-Type"] = "application/json"
req.body = {
  "kind" => "crisp",
  "identifier" => "id_test",
  "key" => "key_test",
  "website_id" => "8c1f3f52-2a8a-4d6b-9a0e-6f1f2c3d4e5f"
}.to_json

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
integration = JSON.parse(res.body)
RESPONSE 201
{
  "object": "integration",
  "id": "itg_PTnp2N7f2MPagEv6",
  "kind": "crisp",
  "status": "active",
  "external_account": "Acme",
  "config": {},
  "last_synced_at": null,
  "error": null,
  "conversations_count": 0,
  "created_at": "2026-11-04T10:00:00Z"
}

OAuth URL of a support tool or Slack

The dashboard only redirects to url. Zendesk needs the account's subdomain (connect as a Zendesk admin). Intercom takes an optional region (us, eu, au: where the workspace is hosted; us by default) for its authorization host.

  • Secret key (nc_test_… or nc_live_…). Restricted keys need write access.
  • AI apps (OAuth): not available.

PATH PARAMETERS

  • kind enum REQUIRED
    • intercom
    • zendesk
    • hubspot
    • helpscout
    • slack

BODY PARAMETERS

RETURNS

ERRORS

POST/v1/integrations/{kind}/authorize
curl https://api.nochurn.sh/v1/integrations/intercom/authorize \
  -H "Authorization: Bearer nc_test_…" \
  -H "Content-Type: application/json" \
  -d '{}'
const res = await fetch("https://api.nochurn.sh/v1/integrations/intercom/authorize", {
  method: "POST",
  headers: {
    Authorization: "Bearer nc_test_…",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({}),
});
const authorizeUrl = await res.json();
import requests

res = requests.post(
    "https://api.nochurn.sh/v1/integrations/intercom/authorize",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
    json={},
)
authorize_url = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/integrations/intercom/authorize")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer nc_test_…"
req["Content-Type"] = "application/json"
req.body = {}.to_json

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
authorize_url = JSON.parse(res.body)
RESPONSE 200
{
  "object": "authorize_url",
  "kind": "intercom",
  "url": "https://app.intercom.com/oauth?client_id=ic_test&state=eyJfcmFpbHMiOnsiZGF0YSI6eyJhY2NvdW50X2lkIjoiYWNjX3F2YXRjSlR6d25DWjRaWUoiLCJ1c2VyX2lkIjpudWxsLCJraW5kIjoiaW50ZXJjb20iLCJub25jZSI6IjE2OWU1ZDQ5MTcxNGZjYmQifSwiZXhwIjoiMjAyNi0xMS0wNFQxMDozMDowMC4wMDBaIiwicHVyIjoiaW50ZWdyYXRpb24ifX0%3D--7d97ba0133a2d258517598968809f921d24c10e0"
}

Slack channel

  • Secret key (nc_test_… or nc_live_…). Restricted keys need write access.
  • AI apps (OAuth): not available.

PATH PARAMETERS

  • id string REQUIRED

BODY PARAMETERS

  • config object
    Show child parametersHide child parameters

RETURNS

PATCH/v1/integrations/{id}
curl https://api.nochurn.sh/v1/integrations/itg_WFTBKq2vf2R8QZMo \
  -X PATCH \
  -H "Authorization: Bearer nc_test_…" \
  -H "Content-Type: application/json" \
  -d '{
    "config": {
      "channel": "#retention"
    }
  }'
const res = await fetch("https://api.nochurn.sh/v1/integrations/itg_WFTBKq2vf2R8QZMo", {
  method: "PATCH",
  headers: {
    Authorization: "Bearer nc_test_…",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "config": {
      "channel": "#retention"
    }
  }),
});
const integration = await res.json();
import requests

res = requests.patch(
    "https://api.nochurn.sh/v1/integrations/itg_WFTBKq2vf2R8QZMo",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
    json={
      "config": {
        "channel": "#retention"
      }
    },
)
integration = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/integrations/itg_WFTBKq2vf2R8QZMo")
req = Net::HTTP::Patch.new(uri)
req["Authorization"] = "Bearer nc_test_…"
req["Content-Type"] = "application/json"
req.body = {
  "config" => {
    "channel" => "#retention"
  }
}.to_json

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
integration = JSON.parse(res.body)
RESPONSE 200
{
  "object": "integration",
  "id": "itg_WFTBKq2vf2R8QZMo",
  "kind": "slack",
  "status": "active",
  "external_account": "Acme",
  "config": {
    "channel": "#retention"
  },
  "last_synced_at": null,
  "error": null,
  "conversations_count": null,
  "created_at": "2026-11-04T10:00:00Z"
}

Disconnect

  • Secret key (nc_test_… or nc_live_…). Restricted keys need write access.
  • AI apps (OAuth): not available.

PATH PARAMETERS

  • id string REQUIRED

RETURNS

DELETE/v1/integrations/{id}
curl https://api.nochurn.sh/v1/integrations/itg_tRyqFBV8V6BgHf6d \
  -X DELETE \
  -H "Authorization: Bearer nc_test_…"
const res = await fetch("https://api.nochurn.sh/v1/integrations/itg_tRyqFBV8V6BgHf6d", {
  method: "DELETE",
  headers: {
    Authorization: "Bearer nc_test_…",
  },
});
const integration = await res.json();
import requests

res = requests.delete(
    "https://api.nochurn.sh/v1/integrations/itg_tRyqFBV8V6BgHf6d",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
)
integration = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/integrations/itg_tRyqFBV8V6BgHf6d")
req = Net::HTTP::Delete.new(uri)
req["Authorization"] = "Bearer nc_test_…"

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
integration = JSON.parse(res.body)
RESPONSE 200
{
  "object": "integration",
  "id": "itg_tRyqFBV8V6BgHf6d",
  "kind": "slack",
  "status": "revoked",
  "external_account": "Acme",
  "config": {},
  "last_synced_at": null,
  "error": null,
  "conversations_count": null,
  "created_at": "2026-11-04T10:00:00Z"
}

Sync now (support tools)

  • Secret key (nc_test_… or nc_live_…). Restricted keys need write access.
  • AI apps (OAuth): not available.

PATH PARAMETERS

  • id string REQUIRED

RETURNS

ERRORS

POST/v1/integrations/{id}/sync
curl https://api.nochurn.sh/v1/integrations/itg_GryteF3meCbHffEf/sync \
  -X POST \
  -H "Authorization: Bearer nc_test_…"
const res = await fetch("https://api.nochurn.sh/v1/integrations/itg_GryteF3meCbHffEf/sync", {
  method: "POST",
  headers: {
    Authorization: "Bearer nc_test_…",
  },
});
const integration = await res.json();
import requests

res = requests.post(
    "https://api.nochurn.sh/v1/integrations/itg_GryteF3meCbHffEf/sync",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
)
integration = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/integrations/itg_GryteF3meCbHffEf/sync")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer nc_test_…"

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
integration = JSON.parse(res.body)
RESPONSE 202
{
  "object": "integration",
  "id": "itg_Pa34cY9hMexK8b2u",
  "kind": "intercom",
  "status": "active",
  "external_account": "Acme",
  "config": {},
  "last_synced_at": null,
  "error": null,
  "conversations_count": 0,
  "created_at": "2026-11-04T10:00:00Z"
}