Errors and limits
How the API tells you something went wrong, what the common messages mean and how to fix them, and the limits to design around.
How errors come back
There are two kinds of error, and your code should check for both.
The request was refused before it ran, because the key is missing or wrong. You get HTTP status 401 and a single error message:
{ "error": "Access denied - Invalid API key" }
The request ran but something in it failed, such as a misspelled field or a change you're not allowed to make. You get an errors list, with a message for each problem and where it happened. Anything that did succeed is still in data, and the part that failed is null:
{
"errors": [
{
"message": "A description of what went wrong",
"locations": [{ "line": 2, "column": 3 }],
"path": ["createTodo"]
}
],
"data": { "createTodo": null }
}
Mistakes in the query itself (a field that doesn't exist, a missing required argument) come back with HTTP status 400. Problems with the data come back with 200, so don't rely on the status code alone: always check for errors.
Common errors
Find the message or problem you hit below. Each one says what it means and how to fix it.
Access denied - Valid API key, access token, or session required
The request had no Authorization header, or it wasn't in the form Bearer <key>. Send Authorization: Bearer suc_api_... with every request.
Access denied - Invalid API key
The key is wrong, has been deleted, belongs to someone who's been deactivated, or was cut short when you copied it. Check the key, or create a new one on the API Keys page.
Access denied - Invalid or expired access token
The key was sent without its suc_api_ start, so it was read as a different kind of token. Send the whole key exactly as you copied it, including suc_api_.
Cannot query field "..." on type "..."
That field doesn't exist on that object, often a typo or an old field name. Check the name in Data model or the full schema. Older examples are covered below.
Field "..." of required type "...!" was not provided
A required field is missing from what you're creating. Add it. The message names the field.
A change is refused for permissions
The message mentions a security policy. You don't have permission for this change: for example, adding to a team you can't see, or making changes with an Observer's key. Use a key from someone with the right access, or give the key's owner access in the app.
An ID isn't recognized
The message mentions a foreign key. An ID you sent (a team, user or measurable) doesn't exist in this company. Look the ID up again; IDs differ between companies.
A value isn't accepted
The message mentions a check. A field has a value it doesn't accept, such as a To-do type other than team or private. Use one of the values in Data model.
A Scorecard value is refused for its date
The message says which day of the week, month or year the date must fall on. A Scorecard value's startDate isn't the start of its period. Send the period's first day; see Scorecards.
A Scorecard value already exists
The message mentions a duplicate. That measurable already has a value for that period (possibly a deleted one). Update the existing value instead; see the weekly Scorecard recipe.
The request times out
The message mentions a timeout. The request took longer than 30 seconds. Ask for fewer items per request and page through them, or ask for fewer related lists at once.
Changes are not allowed on demo sites.
The key belongs to a demo company, where changes are switched off. Use a key from a real or test company.
Coming from older examples
Some older examples of the Success.co API used longer names for related items. Those names no longer exist, and using them gives a Cannot query field error. The current names are shorter:
| Old name | Use instead |
|---|---|
teamByTeamId | team |
userByUserId | user |
todoStatusByTodoStatusId | todoStatus |
usersOnTeamsByUserId, usersOnTeamsByTeamId | usersOnTeams |
meetingAgendaByMeetingAgendaId | meetingAgenda |
meetingAgendaSectionsByMeetingAgendaId | meetingAgendaSections |
The same goes for mutations: there's no deleteUser, deleteTodo and so on. Delete by setting stateId to DELETED, as in Creating and updating data.
Limits
- 30 seconds per request. A request that runs longer is stopped. Big exports should page through results a few hundred at a time; see Reading data.
- 50 MB per request body, far more than any normal request needs.
- Rate limits. Requests are rate limited. Keep to a sensible pace: a few requests a second at most, and one at a time for bulk jobs. If you get HTTP status
429(Too many requests), wait and retry with a growing delay. - One company per key. A key works in the company it was created in. To work with several companies, create a key in each.
How keys behave
- A key acts as you. It sees and changes what you can in the app, and changes it makes are recorded as yours.
- A key stops working when its owner is deactivated. If the person who created it is made inactive or removed from the company, or the company's account is closed, requests with their key are refused. Before deactivating someone, check whether any of your integrations use their key.
- Changes apply straight away. If you delete a key, your role changes or you're deactivated, the key's access changes with it immediately.
- Keys don't expire. Delete keys you no longer use, and replace any key that might have been exposed. The API Keys page shows when each key was last used.
Getting help
If something isn't working and this guide doesn't explain it, email support@success.co with the query you sent and the full error response (leave your API key out).