API Reference

View as Markdown

The PaymentKit API is organized around REST. Our API has predictable resource-oriented URLs, accepts JSON-encoded request bodies, returns JSON-encoded responses, and uses standard HTTP response codes and authentication.

Base URL

All API requests should be made to:

https://app.paymentkit.com/api

For example, to list customers: https://app.paymentkit.com/api/customers

Authentication

The PaymentKit API uses API keys to authenticate requests. You can view and manage your API keys in the Dashboard.

Authentication is performed via HTTP Bearer token. Include your secret token in the Authorization header:

$curl https://app.paymentkit.com/api/customers \
> -H "Authorization: Bearer st_prod_your_secret_token"

PaymentKit provides two types of tokens:

Token typePrefixUsage
Secret tokenst_Server-side API calls. Keep secure, never expose in client code.
Publishable tokenpt_Client-side code (e.g., PaymentKit.js). Safe to expose in browsers.

Your secret tokens carry many privileges, so keep them secure. Do not share them in publicly accessible areas such as GitHub, client-side code, or browser requests.

Request format

Send request data as JSON with the Content-Type: application/json header:

$curl https://app.paymentkit.com/api/customers \
> -H "Authorization: Bearer st_prod_your_secret_token" \
> -H "Content-Type: application/json" \
> -d '{"email": "customer@example.com", "name": "Jane Smith"}'

Errors

PaymentKit uses conventional HTTP response codes to indicate the success or failure of an API request.

CodeDescription
200Success
400Bad Request — Invalid parameters
401Unauthorized — Invalid or missing API key
403Forbidden — Access denied to this resource
404Not Found — Resource doesn’t exist
409Conflict — Clashes with the current state of the resource
422Unprocessable Entity — Validation error
429Too Many Requests — Rate limit exceeded
500Server Error — Something went wrong on our end

Error responses include a JSON body with details:

1{
2 "type": "about:blank",
3 "title": "Bad Request",
4 "status": 400,
5 "detail": "Customer email is required",
6 "instance": "/api/customers",
7 "request_id": "req_abc123"
8}

The request_id can be used when contacting support to help diagnose issues.

Retryable errors

Most errors mean something about the request needs to change. A few mean the request was fine but arrived while a conflicting operation was in progress — the identical request will succeed once that finishes.

These carry a top-level error_code and "retryable": true:

error_codeMeaningWhat to do
invoice_lockedAnother operation is modifying one of the subscription’s invoices.Retry the same request after a few seconds.
1{
2 "type": "about:blank",
3 "title": "Invoice Locked",
4 "status": 409,
5 "detail": "Cannot change subscription sub_abc123 right now: invoice in_xyz789 is being modified by another operation. Retry in a few seconds.",
6 "instance": "https://app.paymentkit.com/api/acc_abc123/subscriptions/sub_abc123/items",
7 "request_id": "req_abc123",
8 "error_code": "invoice_locked",
9 "invoice_id": "in_xyz789",
10 "subscription_id": "sub_abc123",
11 "retryable": true
12}

An invoice_locked refusal modifies nothing, so retrying with a short backoff is enough — there is no cleanup to perform and no need to poll.

Not every retryable 409 uses this shape, and not every one is side-effect free. The change-request apply flow’s PARTIAL_APPLY_RETRYABLE reaches you as a 409 whose detail is a stringified object rather than nested JSON, and it is raised after payment has been collected with some steps already applied — so retrying it resumes work rather than repeating it. Check for a top-level error_code first; treat anything else as endpoint-specific.

Pagination

List endpoints return paginated results. Use limit and offset query parameters:

$curl "https://app.paymentkit.com/api/customers?limit=20&offset=0" \
> -H "Authorization: Bearer st_prod_your_secret_token"

Paginated responses include metadata:

1{
2 "items": [...],
3 "total": 150,
4 "has_more": true
5}
ParameterDefaultMaxDescription
limit50100Number of items to return
offset0Number of items to skip

Expanding responses

Some endpoints support expanding related data. Use the expand query parameter:

$curl "https://app.paymentkit.com/api/customers/cus_prod_abc123?expand=custom_fields" \
> -H "Authorization: Bearer st_prod_your_secret_token"

Available expansions vary by endpoint. Common expansions include custom_fields for entities that support custom field values.

Deprecations

PaymentKit follows semantic versioning and provides advance notice before deprecating API endpoints or features. Active deprecations are documented in endpoint-specific guides with migration paths to replacement functionality.

Currently announced deprecations:

When an endpoint is deprecated, we:

  1. Announce the deprecation in documentation with migration guides
  2. Add Deprecation: true and Sunset: <date> headers to API responses (minimum 6 months notice)
  3. Sunset the endpoint on the announced date (returns 410 Gone with replacement endpoint)

IDs

All objects have a unique identifier prefixed with the object type and environment:

ObjectPrefixExample
Accountacc_acc_prod_a1b2c3d4
Customercus_cus_prod_x9y8z7w6
Subscriptionsub_sub_prod_m3n4o5p6
Invoicein_in_prod_q1r2s3t4
Productprod_prod_prod_u5v6w7x8
Priceprice_price_prod_a9b8c7d6
Checkout Sessioncs_cs_prod_f1g2h3i4

All IDs use the _prod_ prefix for both live and sandbox accounts.