Getting started
Getting started with the API
Make a key on the dashboard, send it with every request, and read the JSON that comes back.
Make a key
- Sign in to the dashboard and open API Keys. Choose New key.
- Give it a name. Choose when it expires (7, 30 or 90 days, a year, or never), its spending limit and how often that resets, and what it may do: Full access or Restricted. The API keys page explains each choice.
- Copy the key when it's shown. It's shown once. AttackDesk keeps only a hash of it, so it can't show it again.
- Keys start with
atk_. Keep them out of your code: the code server switches off any key it finds in a push. - People with the Every key permission can make keys for anyone on the team. Others make their own if their Team page allows Make their own API keys. App users can't make keys; someone makes one for them.
- Keys can be made once AttackDesk is open to your company. The API Keys page says when it isn't yet.
Base URL and header
Every route in these docs starts with:
https://dashboard.attackdesk.com/api/v1Send the key with every request:
Authorization: Bearer atk_…- Send request bodies as JSON, with
Content-Type: application/json. Answers are JSON, except a call recording, which is MP3 audio. - A key belongs to one company, and every call acts on that company. You may name the company with an
X-AttackDesk-Companyheader or a?company=parameter. It must be the key's own company, or the call is refused.
Your first call
List the people on your company and who's online now:
curl https://dashboard.attackdesk.com/api/v1/people \
-H "Authorization: Bearer atk_…"The answer (shortened):
{
"people": [
{
"id": "…",
"name": "Sam Rivera",
"email": "sam@example.com",
"role": "developer",
"self": true,
"canUseApp": true,
"online": true,
"onlineIn": ["dashboard"],
"lastSeenAt": "2026-09-27T17:02:11.000Z",
"lastSeenIn": "dashboard",
"app": { "role": "…", "grant": [], "deny": [] }
}
],
"invited": [],
"onlineSeconds": 180,
"at": "2026-09-27T17:03:00.000Z"
}This route needs the operation team.people.read, which new keys start with. The API reference lists every route, the operation it needs, what to send and what comes back.
What every call is checked for
- The key. It exists and isn't paused, deleted or expired. Its person is still on the company. Its own spending limit isn't used up.
- The operation. Each route needs one operation, such as
phone.messages.send. The key must hold it, and the key's person must be allowed it now. See API keys. - Paid services (phone and texts, email, address lookup, domains, AI worker boxes and publishing) also need: AttackDesk open to the company, the company on a plan with a card on file and paid up, the company's and the person's general spending limits not used up, and a balance left if the company pays only from prepaid funds. Each of these calls counts as one API call. See Limits.
Errors
An error comes back with an HTTP status and a JSON body:
{ "error": "<code>", "message": "<what happened, in plain words>" }message isn't on every error. A refusal by the operation check also names the operation in capability:
{
"error": "not_granted",
"capability": "phone.messages.send",
"message": "This key isn't allowed to send texts. An owner or admin can allow it for the key in API Keys."
}| Status | error | What it means |
|---|---|---|
400 | bad_request | The body or query isn't what the route takes. Some routes answer invalid_request or a code of their own, and some add fields, with a message for each field. |
401 | invalid_key | No key, or the key is unknown, paused, deleted or expired, its person has left the company, or its own spending limit is used up for this period. |
402 | payment_requiredneeds_managed_plancard_required | Money is needed first. See Limits. |
403 | not_grantedneeds_other_capabilityrolenot_delegatednot_memberactor_required | The key or its person isn't allowed this operation. The body names the operation (capability). See API keys. |
403 | shared_key | AI worker boxes and publishing work as one person. Use a person's own key. |
403 | company_context_mismatch | You named a company that isn't the key's. (Routes that don't charge answer 401 invalid_key instead.) |
403 | access_changed | The key or its person lost the permission between the check and the charge. Nothing was charged. |
403 | not_launched | AttackDesk isn't open to this company yet. |
403 | seal_changed | Paid services are paused for a connected copy whose protected core changed. Repair it in the app (Settings → AttackDesk account). |
404 | not_found | No such box, process, publish, call or recording. |
409 | box_startingbox_stoppedopted_outno_number… | What you asked for can't happen in its current state. |
410 | retired | The old website form routes (/api/v1/leads/intake and /api/v1/leads/forms). |
429 | rate_limitedspend_limit_reachedtoo_many_boxeslookup_limit | Too fast, or a limit is reached. See Limits. |
502, 503 | box_unavailableunavailablenot_configured… | A supplier or an AttackDesk service didn't answer, or a feature isn't switched on yet. |
Successful calls answer 200, or 201 when something was made (a box, a phone number), or 202 when the work goes on after the answer (a publish, a purchase still in progress).