Authentication
Authenticate API requests with a Sillage workspace API key.
The API uses workspace API keys, generated in your Sillage settings. They start with sk_live_. A key gives access to the workspace it was generated for, and only to that workspace.
Header
Send the API key in the Authorization header:
Authorization: Bearer <YOUR_API_KEY>Example request
curl "https://api.getsillage.com/api/v3/lists?page_size=5" \
-H "Authorization: Bearer $SILLAGE_API_KEY"Status codes
| Status | Meaning |
|---|---|
| 200 | The request succeeded. |
| 401 | The API key is missing or invalid, or the workspace it belongs to was deleted (workspace_inactive). |
| 403 | Your workspace can have only one persona (persona create), or the workspace is blocked, so no run can be launched. |
| 404 | The resource does not exist. |
| 405 | The path exists but not with this method. The Allow header lists the methods it takes. |
| 409 | The request conflicts with the current state of a resource. |
| 422 | The request is refused: the body is not valid JSON, or a field, a parameter, a value or a cursor is not valid, or not known. |
| 429 | Rate limit exceeded. |
| 500 | An unexpected server error occurred. |
Error model
Every error is an RFC 9457 problem document, sent with Content-Type: application/problem+json. It has these fields:
| Field | Description |
|---|---|
| type | Always about:blank. |
| title | A short name for the problem, the same every time it happens. |
| status | The HTTP status code. |
| code | A stable identifier for the problem, such as invalid_body. Use it, not title or detail, to tell one problem from another. See Error codes. |
| detail | What went wrong this time. |
| instance | The path of the request. |
| errors | Only on 422, and absent on a 422 that names no field: the fields at fault, each with the list of what is wrong with it. |
| signal_setup_ids | Only on the list_persona_setup_conflict 409: the IDs of the signal setups that block the change. |
{
"type": "about:blank",
"title": "Unprocessable Entity",
"status": 422,
"code": "invalid_body",
"detail": "Invalid request body",
"instance": "/api/v3/contents/query",
"errors": {
"limit": ["must be at most 100"]
}
}An error about the request as a whole, or about several fields together, such as a missing body, is named _root. An unknown field is named in errors, under its own name:
{
"type": "about:blank",
"title": "Unprocessable Entity",
"status": 422,
"code": "invalid_body",
"detail": "Invalid request body",
"instance": "/api/v3/contents/query",
"errors": {
"keyword": ["Unknown field: keyword"]
}
}Input is never silently replaced by a default: an unknown field, parameter or value, an invalid date, or a cursor that does not belong to the request is refused with 422. Only a body sent with GET or DELETE is ignored.
Error codes
The code of a problem is one of these values. Branch on it, never on title or detail.
| Status | Code | When |
|---|---|---|
| 401 | invalid_api_key | The API key is missing, malformed, revoked or expired. |
| 401 | workspace_inactive | The workspace of the API key was deleted. |
| 402 | insufficient_credits | Your credit balance cannot pay for the signal run. Nothing was started. |
| 403 | workspace_blocked | The workspace is blocked, so no run can be launched. |
| 403 | single_persona | Your workspace can have only one persona. |
| 404 | not_found | The resource named in the path does not exist. |
| 404 | route_not_found | No route matches the path. |
| 405 | method_not_allowed | The path exists but not with this method. The Allow header lists the methods it takes. |
| 409 | run_in_progress | A run of this signal setup is still in progress. |
| 409 | setup_disabled | The signal setup is disabled. |
| 409 | last_list_of_tier | The list is the only one of its kind for its persona (for a prospect list, of its tier), so it cannot be deleted or archived. |
| 409 | list_in_use | A signal setup still uses the list. |
| 409 | smart_list | Smart lists are managed in the app: their members cannot be added or removed through the API. |
| 409 | tag_taken | Another persona of the workspace already uses this tag. |
| 409 | template_unavailable | The signal template is archived, so no signal can be set up from it. |
| 409 | list_persona_conflict | The list is attached only to personas other than the signal setup's persona. |
| 409 | list_persona_setup_conflict | Changing the personas of a list would leave signal setups on a list that is not attached to their persona. signal_setup_ids names them. |
| 409 | no_covered_account | Every account the signal setup would check has monitoring turned on but unpaid. Nothing was started. |
| 409 | no_monitored_account | No account the signal setup would check is monitored. Nothing was started. |
| 409 | conflict | The request conflicts with the current state of a resource. |
| 422 | invalid_body | The body is not valid: a field is missing, has the wrong type or value, or is not known. |
| 422 | invalid_query | A query parameter is not valid or not known. |
| 422 | invalid_url_params | A value in the path is not valid. |
| 422 | invalid_json | The body is not valid JSON. |
| 422 | body_required | The route needs a JSON body and none was sent. |
| 422 | invalid_reference | An ID in the body or in a filter does not match a resource of your workspace. |
| 422 | invalid_date_range | A _from date is after its _to date. |
| 422 | persona_incomplete | The workspace has no persona, or its persona is missing something the request needs. |
| 422 | persona_required | The workspace has several personas, so the request must say which one with persona_id. |
| 422 | discovery_needs_job_titles | The signal run needs job titles, on the signal setup or on the persona. Nothing was started. |
| 422 | launch_not_possible | The signal setup cannot be launched as configured, for example it has no list or no keywords. Nothing was started. |
| 429 | rate_limited | Too many requests. The Retry-After header tells you how many seconds to wait. |
| 500 | internal_error | An unexpected error on our side. |
New codes may be added; for a code you don't know, act on the HTTP status.
Common response headers
Every response includes:
| Header | Description |
|---|---|
| X-Request-Id | Request UUID, to quote when you contact support. |
| X-Response-Time | How long the server took to answer. |
| X-RateLimit-Limit | Maximum number of requests allowed in the time window. |
| X-RateLimit-Remaining | Requests left in the current window. |
| X-RateLimit-Reset | When the window resets, as a Unix timestamp in milliseconds. |
A 429 response also carries Retry-After, the number of seconds to wait before you retry.
Security
Treat API keys like passwords
Store them on your servers, never in a browser or a mobile app, and rotate a key when someone who had access to it leaves your organization or when it may have been copied.