ClocknextHelp
DocumentationAPI ReferenceMCP Tools
Dashboard

Get started

OverviewQuickstart

Core concepts

The response envelopeErrorsPaginationAsync, flushing & reliability

API reference

Record Signals POSTRecord usage logs POST
List customers GETCreate a customer POSTGet a customer GETUpdate a customer PATCHDelete a customer DELETEGet a customer's balances GETGet a customer's current plan GETList a customer's wallet transactions GETAdd a wallet transaction POSTAdjust a customer's credit balance POSTAdjust a customer's outcome balance POSTAdjust a customer's unit balance POST
List a customer's members GETAdd a member POSTUpdate a member PATCHRemove a member DELETE
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
Mint a customer-portal access token POST
Usage

Record Signals

Records exactly one Signal — a single metered request against a wallet, credit or outcome meter.

POST
/usage

Authorization

apiKey
AuthorizationBearer <token>

Per-organisation API key from Settings → API Keys, sent as Authorization: Bearer cnk_…. Missing, unknown or expired keys return 401.

In: header

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Pricing-metric tag ( credit / outcome / unit ). A pricing metric is addressed by its refId as a property name on this body — send { "voice_ai": "call_5f3a" } to tag the voice_ai metric with your correlation value. Reporting only: it never changes what is billed, never fails the signal, and is ignored on wallet signals or when the name matches no live metric.

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/usage" \  -H "Content-Type: application/json" \  -d '{    "customerId": "cus_abc123",    "type": "credit",    "agentKey": "credit.research",    "member": "dana@acme.com",    "model": "openai/gpt-4o",    "inputTokens": 1200,    "outputTokens": 350,    "cacheTokens": 200,    "custom": {      "feature": "chat",      "region": "eu"    }  }'

{  "statusCode": 200,  "statusDetail": {    "status": "SUCCESS",    "message": "OK"  },  "result": {    "usageLog": {      "id": "log_8m3n5p",      "customerId": "cus_abc123",      "modelName": "gpt-4o",      "creditName": "Deep Research",      "member": "dana@acme.com",      "inputTokens": 1200,      "outputTokens": 350,      "cacheTokens": 200,      "credit": 2,      "providedCost": 0.0087,      "customerCost": 0.012,      "status": "SUCCESS",      "appliedRules": [        {          "ruleId": "rule_7q2w4e",          "ruleName": "EU region uplift",          "creditsApplied": 2        }      ],      "outcome": null,      "balance": {        "dimension": "credit",        "remaining": 18,        "name": "Deep Research"      },      "createdAt": "2026-07-21T14:03:22.000Z"    }  }}

{  "statusCode": 200,  "statusDetail": {    "status": "SUCCESS",    "message": "OK"  },  "result": {    "queued": true,    "messageId": "msg_2f4a1b8c"  }}
{  "statusCode": 400,  "statusDetail": {    "status": "ERROR",    "message": "Request body must be valid JSON."  },  "result": {}}
{  "statusCode": 401,  "statusDetail": {    "status": "ERROR",    "message": "Invalid API key."  },  "result": {}}
{  "statusCode": 404,  "statusDetail": {    "status": "ERROR",    "message": "No customer with id \"cus_abc123\"."  },  "result": {}}
{  "statusCode": 422,  "statusDetail": {    "status": "ERROR",    "message": "No credit with agent key \"summarize\" exists in this workspace."  },  "result": {}}
{  "statusCode": 500,  "statusDetail": {    "status": "ERROR",    "message": "Could not complete the request."  },  "result": {}}

Async, flushing & reliability

How the SDK sends signals — buffered by default, with retries, idempotency, and the flush() you must call before a serverless function exits.

Record usage logs POST

Records one usage log against a catalogue unit, addressed by its stable `agentKey`. Units are fixed-price meters with no tokens — the price comes from the unit's catalogue configuration, so a caller can never post a price.

customerId*string
Length1 <= length
type?string

Accepted case-insensitively.

Value in

  • "wallet"
  • "credit"
  • "outcome"
model?string

Catalog model id, matched case-insensitively. Required when type is set.

Length1 <= length
agentKey?string

Stable agent key of the credit (type=credit) or outcome step (type=outcome).

Length1 <= length
runId?string

Required for type: outcome. Groups every signal of one workflow run into a single billable outcome — a step may repeat within a run, and the run bills once, when a signal sets complete: true. Opaque: any id you can correlate (a ticket, a session). A run id belongs to one (outcome, customer) pair, and reusing a completed one is rejected.

Length1 <= length <= 255
complete?boolean

Only meaningful for type: outcome. Set true on the final step of a run to close and bill it — completion is never inferred from step coverage. Sending it twice is a safe no-op.

member?string

Member email this Signal is attributed to.

inputTokens*integer

Prompt tokens (required).

Range0 <= value
outputTokens*integer

Completion tokens (required).

Range0 <= value
cacheTokens?integer

Cached tokens — optional; defaults to 0.

Range0 <= value
Default0
custom?

Free-form metadata; credit rules can target custom.<key> paths.

[key: string]?|||

Pricing-metric tag. A pricing metric's ref id is a property NAME on this body, not a value: a metric voice_ai is tagged by sending "voice_ai": "wbwbewj21" alongside the rest of the Signal. The value is yours — whatever you correlate by (a session, a call, a tenant) — and is stored verbatim; reports roll a metric up one row per distinct value. Scalars only (string / number / boolean); objects and arrays are read as ordinary payload and ignored. A property that names no metric is simply ignored, and a bad tag never fails the Signal. The tag may also be sent inside custom, where a top-level property of the same name wins. Only meaningful for type: credit and type: outcome — a tag on a wallet Signal is ignored.