Authenticate and manage API keys

Every request to the Circularo API authenticates with an API key passed in the Authorization header. In this guide you verify your key works, create a second key for another system, and revoke it again — the full key lifecycle in five calls.

Before you begin

  • Your first API key. Create it in the Circularo application under My Account → Manage API keys. The API can manage additional keys, but the first one always comes from the application.

All paths in this guide are relative to your instance's base URL — the examples use:

https://sandbox.circularo.com/api/v1/public
Warning

An API key carries the same permissions as the user who created it. It is a secret credential: keep it in a secret manager or environment variable, never in source control or client-side code.

Step 1: Make your first authenticated call

GET /me returns the account your key belongs to — the quickest way to check that your key and connectivity work:

GET /me
Authorization: Bearer YOUR_API_KEY

The same call as a shell one-liner, for trying a key out before you write any code:

Bash
curl "https://sandbox.circularo.com/api/v1/public/me" \
    -H "Authorization: Bearer YOUR_API_KEY"
HTTP/2 200

{
    "fullname": "John Smith",
    "email": "john.smith@example.com",
    "role": "member",
    "organizationId": "Wq6NzXbT4vK8mPdY2cRj",
    "status": "active",
    ...
}

If the key is missing or wrong, you get 401 instead. Everything the key does — documents it sees, actions it may take — happens as this account, with this account's permissions.

Step 2: Create a second API key

Use one key per system that talks to Circularo, so each can be revoked independently. Create a new key with a description that tells you later what it is for:

POST /api-keys
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
    "description": "CI pipeline"
}
HTTP/2 201

{
    "apiKey": "b7e4a1f09c2d58e3a6b4f19d07c5e8a2d4f6b09c1e3a57d9f2b48e60c3a1d5f7",
    "id": "Jd4RwQn8XcV2tZk6PbHs"
}

Store the apiKey secret now — it is returned only in this one response and cannot be retrieved again. The id is the key's non-secret handle for management calls.

Step 3: List your keys

The list shows every active key with a masked preview of its secret — enough to recognize a key, never enough to use it:

GET /api-keys
Authorization: Bearer YOUR_API_KEY
HTTP/2 200

{
    "pagination": null,
    "results": [
        {
            "createdAt": "2026-05-11T09:30:00.000Z",
            "description": "Production backend",
            "id": "Xk2VbNs5QwR9dTj4GmCe",
            "lastUsedAt": "2026-05-11T09:34:00.000Z",
            "maskedApiKey": "****9f4c"
        },
        {
            "createdAt": "2026-05-11T09:32:00.000Z",
            "description": "CI pipeline",
            "id": "Jd4RwQn8XcV2tZk6PbHs",
            "lastUsedAt": "2026-05-11T09:32:00.000Z",
            "maskedApiKey": "****d5f7"
        }
    ],
    "total": 2
}

lastUsedAt tells you when a key last authenticated a request — useful for spotting keys that are no longer used and can be revoked.

Step 4: Revoke a key

Deleting a key revokes it immediately:

DELETE /api-keys/Jd4RwQn8XcV2tZk6PbHs
Authorization: Bearer YOUR_API_KEY
HTTP/2 204

Revocation is permanent — if the system needs access again, create a new key.

Replacing a key that is still in use combines the two calls above, in this order: create the replacement, switch the system over to it, and revoke the old key only once the new one is live. Both keys authenticate in the meantime, so the swap costs no downtime.

Rotate on the schedule your security policy sets, and immediately whenever a key may have leaked. Deleting the compromised key ends its access at once, whatever holds it.

Step 5: Verify the revoked key is rejected

Any request with the revoked key now fails with 401:

GET /me
Authorization: Bearer b7e4a1f09c2d58e3a6b4f19d07c5e8a2d4f6b09c1e3a57d9f2b48e60c3a1d5f7
HTTP/2 401

{
    "status": 401,
    "type": "AUTH:UNAUTHORIZED",
    "message": "Authentication failed",
    "requestId": "f3b9d0c46a714e289c5d84b2e1f7a690"
}

This is the error envelope every failed request returns: a machine-readable type, a human-readable message, and a requestId you can quote when contacting support. Handle errors covers working with errors in detail.

Complete example

Rotating the key of one system — issue the replacement, prove it works, retire the old one — as a Node.js script. Error handling is minimal for brevity — in production, inspect the error envelope of non-2xx responses.

JavaScript
const BASE_URL = "https://sandbox.circularo.com/api/v1/public"; // your instance's base URL
const MANAGING_KEY = "YOUR_API_KEY";
const RETIRED_KEY_ID = "Hs9pXm4TkQ7wZv2nRbLd"; // the id of the key being replaced

const call = (path, options, key) => fetch(`${BASE_URL}${path}`, {
    ...options,
    headers: { "Authorization": `Bearer ${key}`, "Content-Type": "application/json" }
});

const createRes = await call("/api-keys", {
    method: "POST",
    body: JSON.stringify({
        description: "CI pipeline"
    })
}, MANAGING_KEY);
if (!createRes.ok) throw new Error(`Key creation failed: ${createRes.status}`); // error handling kept minimal for brevity

const { apiKey, id } = await createRes.json();
await storeSecret(apiKey); // your own secret manager - this response is the only place the secret appears

// prove the replacement authenticates before the old key goes away
const check = await call("/me", {}, apiKey);
if (!check.ok) throw new Error(`The new key does not authenticate: ${check.status}`);

const revoked = await call(`/api-keys/${RETIRED_KEY_ID}`, { method: "DELETE" }, MANAGING_KEY);
console.log(`Key ${id} is live, ${RETIRED_KEY_ID} revoked with ${revoked.status}`);

Next steps