done.developers

Errors

The one shape every error has, and the error codes with what to do about each.

This page describes the shape of every error the API returns and lists the error codes.

Every error, from every endpoint, has the same shape. It is the internet standard for HTTP problem details (RFC 9457), with four extra fields: code, fix, param and request_id. The content type is application/problem+json.

{
  "type": "https://docs.done.com/errors/insufficient-credits",
  "title": "Not enough credits",
  "status": 402,
  "code": "insufficient_credits",
  "detail": "This run needs 120 credits and the workspace has 45.",
  "fix": "Top up credits in Plan and billing, or send 45 people or fewer.",
  "param": null,
  "request_id": "req_7Tq2LmXa"
}
FieldWhat it holds
typeA link to this error's page in the docs. It is https://docs.done.com/errors/ plus the code with hyphens instead of underscores. The page leads to the code's entry below.
titleThe error in a few words.
statusThe HTTP status code.
codeA stable code your code can branch on. Branch on this, never on title or detail.
detailWhat went wrong this time, in plain words.
fixOne sentence on what to do next.
paramThe request field at fault, as a dotted path, when there is one. It can also name a header such as Done-Workspace or Idempotency-Key. Otherwise null.
request_idThe id of this request. It matches the Request-Id header. Quote it when you contact support.
errorsEvery problem, when there is more than one. For example, a launch check lists each failed check here. Each item has code, detail and param.

Every answer, success or error, carries a Request-Id header.

New error codes can be added within an API version, so handle a code you do not know by its HTTP status. See Versions.

Handling errors

  1. Look at the HTTP status first. A 4xx status means the request needs to change, so do not send it again unchanged. Three cases are different: 429 and 503 are worth sending again after a wait, and so is a 409 with idempotency_key_in_progress.
  2. Branch on code for anything you want to handle in code.
  3. Show detail and fix to a person, or give them to an AI agent. The fix is written so a machine can act on it.
  4. Log request_id.

Codes

Each operation in the API reference lists the errors it can answer.

400 Bad request

CodeMeaning
invalid_fieldA field is malformed or out of range. param names it.
workspace_requiredThe key reaches more than one workspace and the call has no Done-Workspace header.
idempotency_key_missingThe call needs an Idempotency-Key header and has none. See Safe retries.
too_longA text is longer than allowed. param names the field.

401 Unauthorized

CodeMeaning
key_missingThe call has no key in the Authorization header.
key_invalidThe key is wrong. Check that you copied all of it.
key_revokedThe key was revoked. Make a new key in Settings, API keys.
key_expiredThe key passed its expiry date. Make a new key in Settings, API keys.

402 Payment required

CodeMeaning
insufficient_creditsThe workspace does not have the credits the call needs.
search_allowance_reachedThe month's search pages are used up. Credits do not lift this limit.
plan_limitThe plan allows no more of this, for example scouts.
account_limit_reachedThe plan's limit of sending accounts is reached.
webhook_limit_reachedThe plan's limit of webhook endpoints is reached.

403 Forbidden

CodeMeaning
permission_too_lowThe key has a lower permission than the call needs.
daily_credit_cap_reachedThe key has used its daily credit cap. Paid calls with this key are refused until the next UTC day.
workspace_not_in_reachThe Done-Workspace you sent is not one the key reaches.
not_available_in_test_modeA done_test_ key called an operation that has no test version yet. Use a live key for this call. See Test keys.
api_read_onlyThe done. API is accepting only calls that read right now. Calls that change or spend are refused for a while; try again later.
plan_does_not_includeThe workspace's plan does not include this operation. For example, people search and lookup are not part of the API-only plan.

404 Not found

CodeMeaning
not_foundNothing with that id exists in this workspace. Another workspace's ids answer the same way. param names the field.

409 Conflict

CodeMeaning
idempotency_key_reusedThe Idempotency-Key was used in the last 24 hours with a different body.
idempotency_key_in_progressA request with this Idempotency-Key is still running. Wait, then send the same request again.
version_conflictThe object changed since you read it. Read it again and reapply your change.
status_changedThe expected_status you sent does not match the object's status now.
status_transition_refusedThe object's status cannot make that move at all.
run_finishedThe scoring run has already finished, failed or been cancelled.
already_scoredThis Idempotency-Key already scored this person and was charged, and that result is no longer kept. Send a new key to score them again; it is charged again.
all_already_scoredEveryone was scored for this customer profile in the last 90 days.
research_in_progressThe customer profile is being researched now.
not_runningThere is no research running for this customer profile, so there is nothing to cancel.
profile_in_useThe customer profile cannot be deleted: its research is running, a scoring run has used it, or a campaign or scout that is not archived uses it. Cancel the research first, or keep the profile.
list_in_useThe list cannot be deleted while a scout that is not archived adds people to it, a campaign that has not launched takes people from it, or an active lead magnet puts the people who claim it on the list.
built_in_read_onlyBuilt-in styles cannot be changed or deleted. Copy one first.
confirmation_requiredThe change applies to campaigns that use the style. Confirm it to go ahead.
style_in_useCampaigns use the style, so it cannot be deleted.
first_look_waitingA scout's first look is waiting for your decision.
no_first_look_waitingThe scout's first look is not waiting for a decision.
run_in_progressA scout run has not finished. Wait for scout.run_finished, then run again.
nothing_new_leftThe scout has found everyone its search can reach.
locked_after_launchA campaign setting is fixed once the campaign has launched.
already_launchedThe campaign is already active.
account_still_unavailableA sending account the campaign needs is still disconnected. Reconnect it, then resume.
campaign_not_accepting_peopleThe campaign takes no new people, for example because it is completed.
not_retryableThe person is not stuck, so there is nothing to retry.
maybe_sentA message might already have been sent. Check before you retry.
sign_in_in_progressA LinkedIn sign-in for this workspace is already open.
already_connectedThe account is connected and needs no new link.
already_handledThe draft was already handled.
person_not_in_sequenceThe person left the sequence, for example because they replied.
own_reply_not_rewrittenA reply written by a person is never rewritten.
person_state_refuses_sendThe person cannot be messaged, for example because they are on the do-not-contact list.
no_campaignThe conversation was not started by a campaign, so done. cannot send a reply into it.
own_reply_waitingA reply you wrote is queued for this conversation and has not gone out yet.
webhook_disabledThe endpoint was switched off after 20 failed deliveries in a row.

413 Request too large

CodeMeaning
request_too_largeThe request body is larger than 256 KB. Send less in one call.

422 Unprocessable content

CodeMeaning
profile_not_readyThe customer profile has nothing to aim for yet. fix says what to add.
people_cap_requiredA scout without a first look needs people_cap.
kind_retiredThat kind of scout can no longer be created.
no_destinationThe scout has no list or campaign to send approved people to.
not_enough_writingThere is not enough writing to learn a voice from.
no_sending_accountThe workspace has no connected LinkedIn account to send from.
launch_checks_failedThe campaign cannot launch yet. errors lists each failed check.
invalid_time_zoneA time zone must be a place name such as Europe/London, not an offset.
conflicting_settingsTwo settings cannot be on at the same time. param names the one to change.
url_not_allowedA webhook URL must be https and reachable from the public internet.

429 Too many requests

CodeMeaning
rate_limitedThe key made more than 120 calls in a minute. Wait for Retry-After seconds. See Rate limits.
daily_limit_reachedA per-day limit on one kind of work is reached. The reset time is in detail and Retry-After.

500 Internal error

CodeMeaning
internal_errordone. could not finish this request. Try again in a moment, with the same Idempotency-Key if the call takes one; if it keeps happening, contact support with the request_id.
score_outcome_unknownWe could not confirm whether a score finished. It was not charged and is never run again under this Idempotency-Key. Send the request again with a new key.

503 Service unavailable

CodeMeaning
connection_unavailableConnecting a LinkedIn account is temporarily unavailable. Wait for Retry-After, then ask for a new link.

Example: reading an error in code

const response = await fetch('https://api.done.com/v1/scoring_runs/run_3WmK9pQa', {
  headers: { Authorization: `Bearer ${process.env.DONE_API_KEY}` },
});

if (!response.ok) {
  const problem = await response.json();
  switch (problem.code) {
    case 'not_found':
      // The id is wrong, or it belongs to another workspace.
      break;
    case 'rate_limited':
      // Wait for Retry-After seconds, then try again.
      break;
    default:
      console.error(problem.status, problem.code, problem.detail, problem.fix, problem.request_id);
  }
}

On this page