Base URL

EnvironmentBase URL
Productionhttps://api.kurnl.ca/api/v1
Sandboxhttps://api.kurnl.ca/api/v1 (same host, different credentials)
All endpoints are HTTPS only.

Authentication

See Authentication for the full guide. Quick reference:
HeaderUsed for
X-API-Key: krnl_live_...Subscriber management, plan queries, bulk provisioning, reports
X-Webhook-Secret: ...CKO-03 external checkout callbacks

Rate limits

LimitValue
External checkout endpoints120 requests / minute per IP
All other authenticated endpoints300 requests / minute per API key
Rate limit headers are included in every response:
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 118
X-RateLimit-Reset: 1714000060
When the limit is exceeded, kurnl returns 429 Too Many Requests. Retry after the X-RateLimit-Reset timestamp.

Response format

All responses are JSON. Successful responses vary by endpoint. Error responses always follow this structure:
{
  "detail": "Location not found for location_hash"
}
Validation errors return an array:
{
  "detail": [
    {
      "loc": ["body", "subscriber", "email"],
      "msg": "value is not a valid email address",
      "type": "value_error.email"
    }
  ]
}

Common HTTP status codes

StatusMeaning
200Success
201Created
202Accepted (async operation queued)
204No content (e.g. successful delete)
400Bad request — invalid input
401Unauthorized — missing or invalid credentials
403Forbidden — valid credentials but insufficient permissions
404Not found
409Conflict — e.g. duplicate subscription for a unit
422Unprocessable entity — validation failure
429Rate limit exceeded
500Server error — safe to retry

Idempotency

Several endpoints are idempotent by design:
  • POST /external-checkout/complete — same email + plan_version_id returns the existing subscription
  • POST /provisioning/bulk — resubmitting the same subscriber email returns the existing subscription
  • POST /provisioning/provider-initiated — same as above
On 5xx errors, retry the full request. kurnl rolls back partial state automatically on server failures.

Pagination

List endpoints support cursor-based pagination:
GET /provider/subscribers?page=2&page_size=50
Response includes total, page, page_size, and has_more fields alongside the results array.