Integrations

Integration Basics

Learn the core concepts and requirements for building a Churnkey integration.

Project Structure

We recommend organizing your integration code in the following structure:

churnkey/
├── controllers/      # Data access endpoints
   ├── Customers.ts
   ├── Prices.ts
   ├── Subscriptions.ts
   ├── Coupons.ts   # optional
   ├── Families.ts  # optional
|   └── Products.ts  # optional
├── models/          # Data models
   ├── Customer.ts
   ├── Price.ts
   ├── Subscription.ts
   ├── Coupon.ts    # optional
   ├── Family.ts    # optional
   └── Product.ts   # optional
├── actions/         # Subscription modifications
   ├── Cancel.ts    # optional
   ├── ApplyCoupon.ts  # optional
   ├── ExtendTrial.ts  # optional
   ├── ChangePrice.ts  # optional
   └── Pause.ts     # optional
└── index.ts        # Integration entry point

Pagination

All list endpoints should support pagination to handle large datasets efficiently. Each list() method accepts pagination parameters and returns a paginated response. You can skip implementation of pagination if you are sure that the number of items will be small. However, it is strongly recommended to implement pagination just in case.

Request Parameters

Pagination is controlled through query parameters:

GET /churnkey/customers?limit=10&cursor=abc123

Response Format

List endpoints return paginated responses in this format:

Error Handling

When an error occurs, return an appropriate HTTP status code along with a structured error response:

{
  "code": 500, // HTTP status code
  "message": "A human-readable error message"
}

Common status codes:

  • 400 - Bad Request (invalid parameters)
  • 401 - Unauthorized (invalid or missing token)
  • 404 - Not Found (resource doesn't exist)
  • 500 - Internal Server Error

Test Mode

Every request includes an X-Churnkey-Mode header indicating whether it's a test or live request:

X-Churnkey-Mode: test   # Test mode
X-Churnkey-Mode: live   # Live mode (default)

Use this header to determine which environment (test or production) to use for your billing system operations. Test mode must be explicitly enabled in the Churnkey dashboard.

Authentication

Every request to your integration endpoints will include an Authorization header with your integration token:

Authorization: Bearer your_integration_token

Verify this token matches the one from your Churnkey dashboard before processing any requests.

Features Manifest

Your integration must expose a /churnkey/features endpoint that describes which functionality is supported. This helps Churnkey understand which cancel flow options to enable.

The manifest includes:

  • Supported controllers (required and optional)
  • Available actions and their configurations
  • Supported features for each action (e.g., immediate vs end-of-period cancellation)

Implementing Context

Your custom context should extend the SDK Integrator.Context class. You can add any properties/methods you need to the context object.

import { Integrator } from '@churnkey/sdk'
export class Context extends Integrator.Context {
    db: DbConnection
    constructor(mode: Integrator.Mode, db: DbConnection) {
        super(mode)
        this.db = db
    }
}

Instantiating Context

When you expose your integration to the internet, you should provide a function that returns a new instance of your context. This function will be called for every request.

import { Integrator } from './churnkey/Integration'

const app = express()
Integration.expose({
    app: app, // express app instance
    token: process.env.CK_INTEGRATION_TOKEN, // your integration token
    ctx(req, req) {
        return new Context(
            req.headers['X-Churnkey-Mode'],
            req.db
        )
    } 
})