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/jsonRequest 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/jsonRequest 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.
| Param | Notes |
|---|---|
agentId | The athos_agent_… id you were given. |
platformAgentId | Your own id for the rep, as registered. |
npn | Non-digits are stripped before matching; what is left must be 4–10 digits or the request is a 400. |
email | Matched case-insensitively. |
agencyId | Restrict to one of your agencies (an id that is not yours is 404 AGENCY_NOT_FOUND). Combines with a handle by AND. |
limit | Page size, 1–100, default 50. Out of range or not an integer is 400 INVALID_REQUEST — it is not clamped. |
cursor | Opaque 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_orathos_agency_— those are Athos ids. That is a400 INVALID_REQUESTeverywhere. - Each is unique within your account. A
platformAgentIdalready registered answers409 AGENT_ALREADY_EXISTS. AplatformAgencyIdyou already created updates that agency onPOST /v1/agenciesand joins it onPOST /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.