Athos Developer Docs
Backend

Managing agencies and agents

Create an agency under your own id, register your reps into it, and look anyone up by the id you already hold.

Athos keeps a roster for your account: the agencies you serve and the agents (reps) in each. Your backend maintains it with three calls, in this order: create the agency, register its reps, look anyone up. Every call — practice or real — is attributed to one agent and one agency on this roster, and the ids these calls return are what you use everywhere else.

An agency always comes first. Registration never creates one: a rep is registered into an agency you have already created, named by your own id for it.

A handle is any of the three values a rep can be identified by: npn (National Producer Number), email, or platformAgentId (your own id for them).

Create or update an agency — POST /v1/agencies

One call creates an agency under your own id for it, and the same call renames it later. Send it once per agency before you register that agency's first rep — and again whenever the name changes.

POST https://app.useathos.ai/api/external/v1/agencies
Authorization: Bearer ath_live_…
Content-Type: application/json

Request body

Prop

Type

Both fields are required; null is treated as omitted (and so as missing). Leading and trailing whitespace is removed from both.

Response 201 Created when the agency was created, 200 OK when one of your agencies already carried that platformAgencyId and its name was updated. The body is the same agency object either way:

{
  "id": "athos_agency_V1StGXR8Z5jdHi6B-myT",
  "name": "Acme Senior Solutions",
  "platformAgencyId": "acme-7731",
  "createdAt": "2026-09-16T14:02:11.000Z"
}

A repeat POST is always safe — it is how you rename an agency, and a POST with the same name is a no-op 200. Two concurrent first POSTs for one platformAgencyId resolve to one agency. Ids are scoped to your account (another partner's agencies are invisible to you), so this endpoint has no 404; a missing field or a reserved athos_ prefix is 400 INVALID_REQUEST.

curl -X POST https://app.useathos.ai/api/external/v1/agencies \
  -H "Authorization: Bearer $ATHOS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"platformAgencyId":"acme-7731","name":"Acme Senior Solutions"}'
const r = await fetch('https://app.useathos.ai/api/external/v1/agencies', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.ATHOS_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    platformAgencyId: agency.id, // your id for the agency
    name: agency.name,
  }),
});
const body = await r.json();
if (r.status === 201 || r.status === 200) {
  await db.saveAthosAgencyId(agency.id, body.id); // optional — you can keep using your own id
}

Register — POST /v1/agents

POST https://app.useathos.ai/api/external/v1/agents
Authorization: Bearer ath_live_…
Content-Type: application/json

Request body

Prop

Type

At least one of npn, email or platformAgentId is required, and exactly one of platformAgencyId or agencyId — neither or both is 400 INVALID_REQUEST. For every optional field, send it or omit it — null is treated as omitted.

Response 201 Created

{
  "agent": {
    "id": "athos_agent_bR4kQ2wZ9Lp0nH3xVq1Yt",
    "firstName": "Dana",
    "lastName": "Reyes",
    "email": "dana@acme.test",
    "npn": null,
    "platformAgentId": "rep_8842",
    "agencyId": "athos_agency_V1StGXR8Z5jdHi6B-myT",
    "createdAt": "2026-09-16T14:02:11.000Z"
  },
  "agency": {
    "id": "athos_agency_V1StGXR8Z5jdHi6B-myT",
    "name": "Acme Senior Solutions",
    "platformAgencyId": "acme-7731",
    "createdAt": "2026-09-16T14:02:11.000Z"
  }
}

The agency must already exist — registration never creates one. A platformAgencyId you have not created, or an agencyId that is not yours, is 404 AGENCY_NOT_FOUND; create the agency with POST /v1/agencies and register again. Every rep of that agency is registered the same way, with the same platformAgencyId (or the same agencyId).

Already registered? Registering a rep who already exists under any handle you sent is a 409 AGENT_ALREADY_EXISTS. error.details carries the existing ids and which handle matched (matchedOn is one of platformAgentId, npn, email — the handles a registration can send), so a create retried after a network timeout resolves in one call:

{
  "error": {
    "code": "AGENT_ALREADY_EXISTS",
    "message": "An agent with that email is already registered",
    "requestId": "req_…",
    "details": {
      "agentId": "athos_agent_bR4kQ2wZ9Lp0nH3xVq1Yt",
      "agencyId": "athos_agency_V1StGXR8Z5jdHi6B-myT",
      "matchedOn": "email"
    }
  }
}
curl -X POST https://app.useathos.ai/api/external/v1/agents \
  -H "Authorization: Bearer $ATHOS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"firstName":"Dana","lastName":"Reyes","email":"dana@acme.test","platformAgentId":"rep_8842","platformAgencyId":"acme-7731"}'
const r = await fetch('https://app.useathos.ai/api/external/v1/agents', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.ATHOS_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    firstName: rep.firstName,
    lastName: rep.lastName,
    email: rep.email,
    platformAgentId: rep.id,         // your id for the rep
    platformAgencyId: rep.agencyId,  // your id for their agency — created earlier with POST /v1/agencies
  }),
});
const body = await r.json();
if (r.status === 201) {
  await db.saveAthosIds(rep.id, body.agent.id, body.agency.id);
} else if (body.error?.code === 'AGENT_ALREADY_EXISTS') {
  await db.saveAthosIds(rep.id, body.error.details.agentId, body.error.details.agencyId);
}

Look up — GET /v1/agents

The "do you have this person?" call. Filter by exactly one handle and get that agent back — or an empty data when nobody matches. A miss is a normal answer, never a 404; more than one handle is 400 INVALID_REQUEST.

ParamNotes
agentIdThe athos_agent_… id you were given.
platformAgentIdYour own id for the rep, as registered.
npnNon-digits are stripped before matching; what is left must be 4–10 digits or the request is a 400.
emailMatched case-insensitively.
agencyIdRestrict to one of your agencies (an id that is not yours is 404 AGENCY_NOT_FOUND). Combines with a handle by AND.
limitPage size, 1–100, default 50. Out of range or not an integer is 400 INVALID_REQUEST — it is not clamped.
cursorOpaque token from a previous nextCursor. A cursor you did not get from this endpoint is 400 INVALID_REQUEST.

With agencyId alone it lists that agency's agents. With no filter at all it lists your whole roster.

curl -G https://app.useathos.ai/api/external/v1/agents \
  -H "Authorization: Bearer $ATHOS_API_KEY" \
  --data-urlencode "email=dana@acme.test"
{
  "data": [
    {
      "id": "athos_agent_bR4kQ2wZ9Lp0nH3xVq1Yt",
      "firstName": "Dana",
      "lastName": "Reyes",
      "email": "dana@acme.test",
      "npn": null,
      "platformAgentId": "rep_8842",
      "agencyId": "athos_agency_V1StGXR8Z5jdHi6B-myT",
      "createdAt": "2026-09-16T14:02:11.000Z"
    }
  ],
  "nextCursor": null
}

Paging, once

Every list endpoint pages the same way: pass limit and the opaque cursor you were last given, stop when nextCursor is null, and never parse a cursor. GET /v1/agents and GET /v1/calls return the same { data, nextCursor } envelope, so one pager loop serves both.

What you cannot change (v1)

An agent's handles and agency are fixed at registration: there is no endpoint to update an agent, move one to another agency, or remove one. A second POST /v1/agents for the same person is the 409 above, never an update. If a rep's email, NPN or agency changes, ask your Athos contact. An agency's name is the only roster field you can change yourself — by POSTing to /v1/agencies again with the same platformAgencyId. The platformAgencyId itself is the agency's key and cannot be changed.

Your own ids

platformAgentId and platformAgencyId are your ids, stored and echoed back on every object, call and delivery so you never have to map ours to yours (see Two id families). Leading and trailing whitespace is removed from every string field — on registration, and again wherever you send an id back (the mint, the lookup, the calls filters) — so " rep_8842 " and "rep_8842" are the same rep, and a whitespace-only value is a 400 INVALID_REQUEST. Two rules:

  • Neither may begin with athos_agent_ or athos_agency_ — those are Athos ids. That is a 400 INVALID_REQUEST everywhere.
  • Each is unique within your account. A platformAgentId already registered answers 409 AGENT_ALREADY_EXISTS. A platformAgencyId you already created updates that agency on POST /v1/agencies and joins it on POST /v1/agents — it is never an error.

The id you register a rep under is also what attributes their real calls — see Register your reps first.

On this page