{"openapi":"3.1.0","info":{"title":"Kleos API","version":"2026-08-04","description":"Sell Kleos under your own brand. Your customers get the whole platform; your users never see anything but you.","contact":{"name":"Kleos","email":"api@kleos.click","url":"https://docs.kleos.click"}},"servers":[{"url":"https://api.kleos.click/v1","description":"Production"}],"security":[{"bearerAuth":[]}],"paths":{"/me":{"get":{"operationId":"getMe","summary":"Who this key belongs to","description":"The first call to make. Confirms the key works, which mode it is in, and what it is allowed to do. Needs no permission beyond a valid key.","security":[{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"object":"account","id":"e1b9c4e2-1f4e-4b0b-9f5a-2c1d0f7a41c8","slug":"acme-dialer","name":"Acme Dialer","status":"test","mode":"test","country":"BE","onboarding":{"kyb_status":"submitted","agreement_signed":false,"agreement_version":null},"key":{"id":"b0a1…","label":"Production backend","prefix":"kls_test_","last_four":"9f2c","scopes":["customers:read","customers:write"],"expires_at":null},"limits":{"requests_per_minute":120,"burst":240,"concurrent_calls":3,"max_customers":null},"customers":{"count":4}}}}}}}},"/customers":{"get":{"operationId":"listCustomers","summary":"List your customers","description":"Returns the customers created with a key in the SAME mode. A test key never sees live customers and a live key never sees test ones. Requires the `customers:read` permission.","security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"How many to return. Defaults to 100, capped at 200.","schema":{"type":"integer"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"object":"list","data":[{"object":"customer","id":"0f2a6c4e-96a2-4f2e-8f2b-6c1a0e73d8b1","external_ref":"crm-8842","name":"Vandeputte Plumbing","brand_name":"Vandeputte","website_url":"https://vandeputte.be","country":"BE","timezone":"Europe/Brussels","status":"prospect","mode":"test","created_at":"2026-08-04T09:12:44.000Z"}],"has_more":false}}}}}},"post":{"operationId":"createCustomer","summary":"Create a customer","description":"Creates the account one of your customers will be run under. Creating it provisions nothing: no number is bought, no agent is published, nothing dials. Send `Idempotency-Key` and a retry after a timeout is safe. Requires the `customers:write` permission.","security":[{"bearerAuth":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Your own unique string. Replaying it returns the first response for 24 hours.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"The customer's legal or trading name."},"external_ref":{"type":"string","description":"Your own id for them. Unique per account, and usable in place of the Kleos id in every other call."},"brand_name":{"type":"string","description":"What the agent should call the business on a call, if it differs from `name`."},"website_url":{"type":"string","description":"Used for research before calls."},"country":{"type":"string","description":"ISO-3166 alpha-2. Decides the calling rules and the language the agent is certified in."},"timezone":{"type":"string","description":"IANA name, e.g. Europe/Brussels. Decides when calling is allowed."}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"object":"customer","id":"0f2a6c4e-96a2-4f2e-8f2b-6c1a0e73d8b1","external_ref":"crm-8842","name":"Vandeputte Plumbing","brand_name":"Vandeputte","website_url":"https://vandeputte.be","country":"BE","timezone":"Europe/Brussels","status":"prospect","mode":"test","created_at":"2026-08-04T09:12:44.000Z"}}}},"400":{"description":"name_required — `name` was missing or blank.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"customer_limit_reached — Your account has a customer ceiling and it is full.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"idempotency_key_reused — The same `Idempotency-Key` arrived with a different body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/customers/{id}":{"get":{"operationId":"getCustomer","summary":"Retrieve one customer","description":"`{id}` is either the Kleos id or your own `external_ref` — whichever you have to hand. Requires the `customers:read` permission.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Kleos id or your `external_ref`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"object":"customer","id":"0f2a6c4e-96a2-4f2e-8f2b-6c1a0e73d8b1","external_ref":"crm-8842","name":"Vandeputte Plumbing","brand_name":"Vandeputte","website_url":"https://vandeputte.be","country":"BE","timezone":"Europe/Brussels","status":"prospect","mode":"test","created_at":"2026-08-04T09:12:44.000Z"}}}},"404":{"description":"customer_not_found — No customer with that id in this mode.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/customers/{id}/readiness":{"get":{"operationId":"customerReadiness","summary":"Can this customer take a live call yet?","description":"The honest answer, with machine-readable blockers. If `ready_for_live_calls` is false, the blocker list is exactly what the call path would refuse on — this endpoint never claims ready when a call would be turned away. Requires the `customers:read` permission.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Kleos id or your `external_ref`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"object":"readiness","customer_id":"0f2a6c4e-96a2-4f2e-8f2b-6c1a0e73d8b1","external_ref":"crm-8842","country":"BE","calling_language":"nl-BE","ready_for_live_calls":false,"blockers":[{"code":"emporos_not_live","message":"This account is not approved for live calls yet."},{"code":"no_number_in_country","message":"No Kleos number is available for this customer's country yet."}],"checks":{"account_live":false,"business_verified":true,"agreement_signed":true,"balance_loaded":false,"speech_certified_for_language":true,"number_in_country":false,"script_certified":false}}}}},"404":{"description":"customer_not_found — No customer with that id in this mode.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/customers/{id}/limits":{"get":{"operationId":"getCustomerLimits","summary":"Read one customer's spending limits","description":"What this customer may spend and how many calls they may run at once, plus what they have spent today and this month. A limit of `null` means no limit of your own — your account-wide caps still apply. Requires the `customers:read` permission.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Kleos id or your `external_ref`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"object":"customer_limits","customer_id":"0f2a6c4e-96a2-4f2e-8f2b-6c1a0e73d8b1","external_ref":"crm-8842","daily_spend_cap_cents":2000,"monthly_spend_cap_cents":40000,"max_concurrent_calls":2,"spend":{"today_cents":640,"month_cents":9120}}}}},"404":{"description":"customer_not_found — No customer with that id in this mode.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updateCustomerLimits","summary":"Cap one customer's spending","description":"The pool is shared, so one customer's runaway campaign can spend money that is funding the rest. Send only the fields you want to change; send `null` to clear one. Caps stop NEW calls — a call already in progress is never cut off. Requires the `customers:write` permission.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Kleos id or your `external_ref`.","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Your own unique string. Replaying it returns the first response for 24 hours.","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","required":[],"properties":{"daily_spend_cap_cents":{"type":"integer","description":"Most this customer may spend in a UTC day. `null` clears it."},"monthly_spend_cap_cents":{"type":"integer","description":"Most this customer may spend in a calendar month. `null` clears it."},"max_concurrent_calls":{"type":"integer","description":"Most calls this customer may have running at once. Never raises your account ceiling."}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"object":"customer_limits","customer_id":"0f2a6c4e-96a2-4f2e-8f2b-6c1a0e73d8b1","external_ref":"crm-8842","daily_spend_cap_cents":2000,"monthly_spend_cap_cents":40000,"max_concurrent_calls":2}}}},"400":{"description":"invalid_limit — A limit was negative, fractional, or not a number.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"customer_not_found — No customer with that id in this mode.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/balance":{"get":{"operationId":"getBalance","summary":"What is in the pool, and what a minute costs","description":"Both halves matter. `available_cents` excludes money held against calls already running, so it is what your next call can actually draw on. The rate is the one in force right now — it drops as the month's minutes cross a tier, so a figure hard-coded in your own billing will be wrong from the 5,001st minute onwards. All amounts are whole US cents. Requires the `billing:read` permission.","security":[{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"object":"balance","currency":"usd","available_cents":41250,"balance_cents":43100,"paid_cents":40000,"bonus_cents":3100,"bonus_expires_at":"2027-08-04T00:00:00.000Z","reserved_cents":1850,"minimum_top_up_cents":2500,"low_balance":"ok","rates":{"call_cents_per_minute":20,"minutes_used_this_month":1840,"estimated_call_minutes_remaining":2062,"number_cents_per_month":1500,"caller_id_cents_per_month":1200,"chat_message_cents":2,"prospect_cents":4,"call_tiers":[{"from_minutes":0,"cents_per_minute":20},{"from_minutes":5000,"cents_per_minute":18},{"from_minutes":25000,"cents_per_minute":16},{"from_minutes":100000,"cents_per_minute":15}]},"spend":{"today_cents":3120,"month_cents":36800,"daily_cap_cents":null,"monthly_cap_cents":null}}}}}}}},"/usage":{"get":{"operationId":"getUsage","summary":"Every movement of money, itemised","description":"The ledger you rebill your own customers from. Each line carries `customer_id`, so attribution never has to be reconstructed. Negative is money out, positive is money in. Test-mode lines are returned with `applied: false` — they show what live traffic would have cost and were never charged. Requires the `billing:read` permission.","security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"How many to return. Defaults to 100, capped at 200.","schema":{"type":"integer"}},{"name":"customer_id","in":"query","required":false,"description":"Only lines belonging to this customer.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"object":"list","data":[{"object":"usage_entry","id":"7c2f1a90-2c3e-4c0a-9b76-3f0a1e8d44c2","type":"usage","amount_cents":-80,"currency":"usd","balance_after_cents":41170,"applied":true,"customer_id":"0f2a6c4e-96a2-4f2e-8f2b-6c1a0e73d8b1","reference":"call_9f31c0","description":"Call — 4 minutes","mode":"live","created_at":"2026-08-04T09:41:02.000Z"}],"has_more":false}}}}}}},"/brand":{"get":{"operationId":"getBrand","summary":"Read your branding","description":"The name, logo and colours your customers see anywhere Kleos renders something on your behalf. Requires the `brand:read` permission.","security":[{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"object":"brand","display_name":"Acme Dialer","logo_url":"https://cdn.acme.example/logo.svg","primary_color":"#0B1F3A","accent_color":"#C8A24A","email_from_name":"Acme Dialer","support_email":"help@acme.example","domain":"app.acme.example"}}}}}},"patch":{"operationId":"updateBrand","summary":"Change your branding","description":"Send only the fields you want to change. Sending `null` clears one. Colours are hex; URLs must be https, because a logo served over http would downgrade every page it appears on — including your customers' onboarding. Requires the `brand:write` permission.","security":[{"bearerAuth":[]}],"parameters":[],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","required":[],"properties":{"display_name":{"type":"string","description":"The name your customers see."},"logo_url":{"type":"string","description":"https URL to your logo."},"primary_color":{"type":"string","description":"Hex, e.g. #0B1F3A."},"accent_color":{"type":"string","description":"Hex, e.g. #C8A24A."},"email_from_name":{"type":"string","description":"The sender name on emails sent on your behalf."},"support_email":{"type":"string","description":"Where your customers should reply."},"domain":{"type":"string","description":"The domain your customers use you at."}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"object":"brand","display_name":"Acme Dialer","logo_url":"https://cdn.acme.example/logo.svg","primary_color":"#0B1F3A","accent_color":"#C8A24A","email_from_name":"Acme Dialer","support_email":"help@acme.example","domain":"app.acme.example"}}}},"400":{"description":"invalid_brand_field — A colour was not hex, or a URL was not https.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Your Kleos API key: `Authorization: Bearer kls_live_…` (or `kls_test_…`)."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["invalid_request_error","authentication_error","permission_error","not_found_error","conflict_error","api_error"]},"code":{"type":"string","enum":["invalid_api_key","key_revoked","key_rotated","key_expired","scope_missing","ip_not_allowed","emporos_suspended","live_not_enabled","customer_not_found","idempotency_key_reused","rate_limit_exceeded","invalid_limit","invalid_json","api_error"]},"message":{"type":"string"},"request_id":{"type":"string"}}}}}}},"x-kleos-scopes":["customers:read","customers:write","calls:read","calls:write","chat:write","numbers:read","numbers:order","brand:read","brand:write","events:read","billing:read"]}