Skip to content

Billing

One weighted spend over events, emails, webhooks, and journey runs, counted from rows that already exist, never incremented, never billed in arrears. Credit is the monthly free allowance ($1, resets each UTC month, no rollover) plus the prepaid wallet balance (carries over). At zero the platform hard-stops: 429 over_quota on ingestion, skipped_quota on sends. See the Billing guide.

Billing summary for the current UTC month

Auth: Clerk session token.

Response 200

{
"data": {
"allowanceMicros": 42,
"walletBalanceMicros": 42,
"periodStart": "2026-01-15T09:30:00.000Z",
"periodEnd": "2026-01-15T09:30:00.000Z",
"spentMicros": 42,
"remainingMicros": 42,
"usage": {
"events": 42,
"emails": 42,
"webhooks": 42,
"journeyRuns": 42
},
"prices": {
"event": 42,
"email": 42,
"webhook": 42,
"journeyRun": 42
},
"warn": true,
"over": true
},
"meta": {
"requestId": "string",
"nextCursor": "string",
"hasMore": true
}
}
Field Type Required Constraints
data object yes
data.allowanceMicros integer yes 0 ≤ x ≤ ∞
data.walletBalanceMicros integer yes 0 ≤ x ≤ ∞
data.periodStart string (date-time) yes
data.periodEnd string (date-time) yes
data.spentMicros integer yes 0 ≤ x ≤ ∞
data.remainingMicros integer yes 0 ≤ x ≤ ∞
data.usage object yes
data.usage.events integer yes 0 ≤ x ≤ ∞
data.usage.emails integer yes 0 ≤ x ≤ ∞
data.usage.webhooks integer yes 0 ≤ x ≤ ∞
data.usage.journeyRuns integer yes 0 ≤ x ≤ ∞
data.prices object yes
data.prices.event integer yes 0 ≤ x ≤ ∞
data.prices.email integer yes 0 ≤ x ≤ ∞
data.prices.webhook integer yes 0 ≤ x ≤ ∞
data.prices.journeyRun integer yes 0 ≤ x ≤ ∞
data.warn boolean yes
data.over boolean yes
meta object no
meta.requestId string no
meta.nextCursor string | null no
meta.hasMore boolean no

Errors follow the shared envelope and code table.

List wallet top-ups

Auth: Clerk session token.

Query parameters

{
"cursor": "string",
"limit": 50
}
Field Type Required Constraints
cursor string no
limit integer no default 50; 1 ≤ x ≤ 100

Response 200

{
"data": [
{
"id": "string",
"amountMicros": 42,
"status": "pending",
"stripeCheckoutSessionId": "string",
"createdAt": "2026-01-15T09:30:00.000Z",
"completedAt": "2026-01-15T09:30:00.000Z"
}
],
"meta": {
"requestId": "string",
"nextCursor": "string",
"hasMore": true
}
}
Field Type Required Constraints
data object[] yes
data[] object yes
data[].id string yes
data[].amountMicros integer yes 0 ≤ x ≤ ∞
data[].status “pending” | “completed” | “failed” yes
data[].stripeCheckoutSessionId string yes
data[].createdAt string (date-time) yes
data[].completedAt string (date-time) | null yes
meta object no
meta.requestId string no
meta.nextCursor string | null no
meta.hasMore boolean no

Errors follow the shared envelope and code table.

Start a wallet top-up

Auth: Clerk session token.

Request body

{
"data": {
"amountMicros": 10000000
}
}
Field Type Required Constraints
data object yes
data.amountMicros 10000000 | 50000000 | 200000000 yes

Response 201

{
"data": {
"checkoutUrl": "https://example.com/hooks/cowliss"
},
"meta": {
"requestId": "string",
"nextCursor": "string",
"hasMore": true
}
}
Field Type Required Constraints
data object yes
data.checkoutUrl string (uri) yes
meta object no
meta.requestId string no
meta.nextCursor string | null no
meta.hasMore boolean no

Errors follow the shared envelope and code table.

Stripe webhook (public)

Auth: None: verifies the caller’s own signature/token.

Errors follow the shared envelope and code table.