ClocknextHelp
DocumentationAPI ReferenceMCP Tools
Dashboard

Get started

OverviewQuickstart

Good to know

Response formatHandling errorsPaginating resultsSending data reliablyYour own customer idsWebhooks

API reference

Record credit POSTRecord outcome POSTComplete outcome POSTRecord wallet POSTRecord unit POSTComplete composite POST
List customers GETCreate a customer POSTGet a customer GETUpdate a customer PATCHDelete a customer DELETEGet a customer's balances GETGet a customer's wallet ledger GETSet a customer's low-balance alert PUTGet a customer's current plan GETChange a recurring grant PUTList Customer Usage Log GETLook Up Usage Logs by ID GET
Manage a customer's credit balance POSTManage a customer's outcome balance POSTManage a customer's unit balance POSTManage a customer's composite balance POSTManage a customer's wallet balance POST
List a customer's members GETAdd a member POSTUpdate a member PATCHRemove a member DELETE
PlansCreditsOutcomesUnitsComposites
List taxes GETCreate a tax POSTGet a tax GETUpdate a tax PATCH
List purchases GETCreate a purchase POSTGet a purchase GETUpdate a purchase's auto-payment setting PATCHCancel a purchase POST
List invoices GETGet an invoice GETMint a hosted pay link GET
List payments GETGet a payment GET
wallet.balance.update POSTwallet.balance.drop POST
Mint a customer-portal access token POST

API Reference

Response format

Every endpoint — success or error — returns the same predictable envelope. Here's the contract.

Every response from the API, whether it succeeds or fails, has the same shape. Parse it once and reuse that logic everywhere.

{
  "statusCode": 200,
  "statusDetail": { "status": "SUCCESS", "message": "OK" },
  "result": { }
}

Fields

Prop

Type

On success

statusDetail.status is SUCCESS and the payload rides in result. For a list endpoint result holds the rows (and paging info); for a single-record endpoint it holds that record.

{
  "statusCode": 201,
  "statusDetail": { "status": "SUCCESS", "message": "Customer created" },
  "result": { "id": "cus_abc123", "name": "Acme Inc", "email": "ops@acme.com" }
}

On error

statusDetail.status is ERROR, result is always an empty object, and the reason is in statusDetail.message. See Errors for the full list of status codes.

{
  "statusCode": 404,
  "statusDetail": { "status": "ERROR", "message": "Customer not found" },
  "result": {}
}

Handling it in code

If you call the API directly, branch on the HTTP status (or equivalently on statusDetail.status), read result on success, and surface statusDetail.message on failure.

const res = await fetch("https://payments.clocknext.com/api/v1/customers", {
  headers: { Authorization: `Bearer ${process.env.CLOCKNEXT_API_KEY}` },
});

const body = await res.json();
if (body.statusDetail.status !== "SUCCESS") {
  throw new Error(`${body.statusCode}: ${body.statusDetail.message}`);
}
const customers = body.result;

The official @clocknext/sdk client does this for you — every method returns result directly and throws a typed error on failure, so you never unwrap the envelope by hand:

const customers = await cnk.customers.list(); // already unwrapped

Quickstart

Create a customer, package a Plan, and record your first usage signal — start to finish.

Handling errors

Every status code the API returns, what it means, and how to handle it.

On this page

FieldsOn successOn errorHandling it in code