Authentication
Authenticate to the Cooledge API with the X-Api-Key header. Covers the ck_live key format and lifecycle, the full scope list and how to read 401 and 403 errors.
Authentication
Every request to the Cooledge API is authenticated with an API key sent in the X-Api-Key request header. API keys are the primary authentication method for direct integrations. OAuth access tokens issued through an MCP connection also work as bearer tokens on the same endpoints, with the same scopes.
X-Api-Key: ck_live_AB12CD_your_secret_here
There is no session, no login exchange and no token refresh. Each request carries the key on its own. OAuth is available through an MCP connection; for direct integrations the X-Api-Key header is how you authenticate.
Key format and lifecycle
A Cooledge API key looks like this:
ck_live_AB12CD_xxxxxxxxxxxxxxxxxxxxxxxx
It has two visible parts joined by underscores:
- The identifier (prefix). The
ck_live_AB12CDportion is the key identifier. It is stored and displayable, so you can recognise which key a request used without ever exposing the secret. When you have several keys, the prefix is how you tell them apart. - The secret. Everything after the prefix is the secret. You send the whole string, prefix and secret together, in the
X-Api-Keyheader.
The full secret is shown once at creation and cannot be retrieved again. Store it in a secrets manager or an environment variable as soon as you receive it. If the secret is lost you cannot recover it, so you request a replacement key and rotate to it.
The account owner creates and manages API keys from the Developers page in Settings, on the Growth and Scale plans. Admins can see the keys but cannot create or revoke them. Each key carries the scopes you choose and can be rotated or revoked at any time. Treat the secret like a password: never commit it to source control, never put it in a client-side bundle and never share it in plain text.
Scopes
Each key is granted a set of scopes. A scope is a permission to read or write one kind of record. A request is allowed only if the key holds the scope the endpoint requires. Ask for the narrowest set of scopes that does the job.
| Scope | What it allows |
|---|---|
customers:read | Read customers and their sites |
customers:write | Create, update and archive customers and sites |
jobs:read | Read jobs and their details |
jobs:write | Create, update and progress jobs |
quotes:read | Read quotes and their line items |
quotes:write | Create, update and send quotes |
invoices:read | Read invoices and their payment state |
invoices:write | Create, update and send invoices |
bookings:read | Read bookings and scheduled visits |
bookings:write | Create, reschedule and cancel bookings |
leads:read | Read leads and their status |
leads:write | Create, update and convert leads |
tasks:read | Read tasks and their status |
tasks:write | Create, update, complete and reopen tasks |
messages:read | Read conversations, their messages and calls and the drafts waiting in them. Also needed to subscribe to the message webhook events |
messages:draft | Create, update and delete reply drafts. It never sends a message |
webhooks:manage | Manage webhook subscriptions |
The scopes your key actually holds are returned on the caller.scopes array from GET /v1/me, so you can confirm what a key can do at any time.
The Messages scopes
messages:read and messages:draft cover the team inbox. See the Messaging API guide. They are granted on purpose, never by default:
- On the key screen, they are the Messages row, with Read and Write drafts (never sends). The Full access and Read-only presets leave the row unticked, so tick it yourself.
- Existing keys and connections gain nothing. A key or OAuth connection made before these scopes existed keeps exactly the scopes it had.
- Not in the OAuth default. An app that connects without asking for particular scopes gets the default set, which leaves both out. An app has to ask for them. The consent screen shows them as Read conversations and messages and Write message drafts (never sends).
No scope lets a key or app send or schedule a message. A person on the team always sends a draft from Cooledge.
The Tasks scopes
tasks:read and tasks:write cover tasks, through /v1/tasks and the MCP task tools:
- On the key screen, they are the Tasks row. The Full access preset ticks Read and Write, and Read-only ticks Read.
- Existing keys and connections gain nothing. A key or OAuth connection made before these scopes existed keeps exactly the scopes it had. A key's scopes cannot be changed, so create a new key with the Tasks row ticked. Disconnect an older OAuth connection and connect it again to approve them.
- In the OAuth default. An app that connects now without asking for particular scopes gets both. The consent screen shows them as View tasks and Create, update and complete tasks.
401 versus 403
The API distinguishes a credential that is wrong from a credential that is right but not permitted. The two cases need different fixes, so check the status code first.
A 401 means the credential is missing or invalid. The X-Api-Key header was absent, malformed or did not match a live key. Check that you are sending the header, that you copied the whole key including the secret and that the key has not been revoked. A 401 is about the credential itself, not about what it is allowed to do.
A 403 means the credential is valid but not permitted. The key was recognised, so authentication succeeded, but the request was refused. A 403 can mean any of these:
- The key does not hold a scope the endpoint requires. Request a key with that scope or use a key that already has it.
- The business is not on a plan tier that includes the endpoint.
- The subscription has lapsed. An expired trial, a past due payment or a cancellation blocks all API access, reads and writes alike, until it is resolved. Once the subscription is active again, access returns.
So a 401 points you at the key. A 403 points you at the key's scopes or at the account's plan and subscription state. Errors follow the RFC 7807 problem-details format, covered in Pagination and errors.
Need a hand with an integration? Contact support