> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.sailorhq.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.sailorhq.io/_mcp/server.

# Authentication

> Authenticate requests to the Sailor public API.

Sailor public API requests use a one-workspace API key. An owner or admin creates the key in **Settings → Integrations → API access**. Sailor shows the secret once; store it before closing the dialog.

Production keys begin with `sl_live_`. Send the key only from a trusted backend. Do not put it in browser code, mobile clients, extensions, public repositories, analytics, or support screenshots.

Every request should include `Authorization: Bearer $SAILOR_API_TOKEN`.

## Request Shape

```bash
curl https://api.sailorhq.io/phone-system/outcomes \
  -H "Authorization: Bearer $SAILOR_API_TOKEN" \
  -H "Content-Type: application/json"
```

## Workspace And Permission Scope

Every key is permanently attached to the workspace where it was created. A request cannot select or override another organization or workspace. Choose the minimum required scopes when creating the key:

| Scope                         | Allows                                                                           |
| ----------------------------- | -------------------------------------------------------------------------------- |
| `phone_system.outcomes:read`  | List phone-system outcomes.                                                      |
| `phone_system.outcomes:write` | Create, update, and delete phone-system outcomes.                                |
| `staff:write`                 | Create Sailor staff invitations in this exact workspace.                         |
| `smart_lists:read`            | List Smart Lists and inspect member state in this exact workspace.               |
| `smart_lists:write`           | Create, update, clone, delete, and populate Smart Lists in this exact workspace. |

Sailor returns [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) problem details as `application/problem+json` when authentication or authorization fails.

> **Warning**
>
> Treat the API key as a workspace-scoped secret. A public key leak is a workspace incident: revoke or rotate it immediately.

## Write Requests

Create and update requests require an `Idempotency-Key` header. Use an opaque 8–255 character value that is stable for one logical operation. Retrying the same operation with the same key returns the stored response; using that key with different request data returns `422 idempotency_key_reused`.

```bash
curl https://api.sailorhq.io/phone-system/outcomes \
  -X POST \
  -H "Authorization: Bearer $SAILOR_API_TOKEN" \
  -H "Idempotency-Key: $SAILOR_REQUEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "outcome_name": "Interested",
    "outcome_type": "action",
    "destination_type": "smart_list",
    "destination_id": "00000000-0000-4000-8000-000000000000",
    "webhook_url": "https://example.com/sailor/outcomes"
  }'
```

## Header Checklist

| Request                                           | Required headers                                                            |
| ------------------------------------------------- | --------------------------------------------------------------------------- |
| `GET /phone-system/outcomes`                      | `Authorization`                                                             |
| `POST /phone-system/outcomes`                     | `Authorization`, `Idempotency-Key`, `Content-Type`                          |
| `PATCH /phone-system/outcomes/{outcomeId}`        | `Authorization`, `Idempotency-Key`, `Content-Type`                          |
| `DELETE /phone-system/outcomes/{outcomeId}`       | `Authorization`; `Idempotency-Key` is optional but recommended for retries. |
| `POST /staff/invites`                             | `Authorization`, `Idempotency-Key`, `Content-Type`                          |
| `GET /smart-lists`                                | `Authorization`                                                             |
| `GET /smart-lists/{smartListId}` and member reads | `Authorization`                                                             |
| `POST /smart-lists`                               | `Authorization`, `Idempotency-Key`, `Content-Type`                          |
| `PATCH /smart-lists/{smartListId}`                | `Authorization`, `Idempotency-Key`, `Content-Type`                          |
| Smart List clone and member mutations             | `Authorization`, `Idempotency-Key`, `Content-Type`                          |
| `DELETE /smart-lists/{smartListId}`               | `Authorization`, `Idempotency-Key`                                          |

## Idempotency Keys

| Situation                           | Use this key                      |
| ----------------------------------- | --------------------------------- |
| Retrying the same logical operation | Reuse the same `Idempotency-Key`. |
| Starting a new intended operation   | Generate a new `Idempotency-Key`. |

If Sailor returns `409 request_in_progress`, wait for the `Retry-After` delay, then retry the same logical operation with the same key. A replayed response includes `Idempotent-Replayed: true`.

## Common Auth Errors

| Error                     | Meaning                                                                      | What to check                                                         |
| ------------------------- | ---------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| `unauthorized`            | Sailor could not authenticate the request.                                   | Confirm the bearer key is complete, live, unexpired, and not revoked. |
| `insufficient_scope`      | The key is valid but lacks the operation's scope.                            | Create or rotate a key with the documented scope.                     |
| `feature_not_available`   | Phone-system outcomes are not enabled for the key's workspace.               | Enable the phone-system feature in that same workspace.               |
| `rate_limit_exceeded`     | A credential or workspace quota is exhausted.                                | Wait for `Retry-After`; inspect `RateLimit` and `RateLimit-Policy`.   |
| `temporarily_unavailable` | A deadline, concurrency lease, or durable control could not safely complete. | Wait for `Retry-After` and retry idempotently.                        |

Problem responses have this stable shape:

```json
{
  "type": "https://docs.sailorhq.io/problems/insufficient-scope",
  "title": "Insufficient scope.",
  "status": 403,
  "code": "insufficient_scope",
  "request_id": "2eab7d20-219b-4d17-9f4f-2c26c54d91c4",
  "detail": "This operation requires phone_system.outcomes:write."
}
```

## Security Checklist

* Store keys in server-side secret storage.
* Rotate keys if they appear in logs, screenshots, or client bundles.
* Use an IP allowlist when your outbound addresses are stable.
* Set an expiration for temporary integrations.
* Use HTTPS for webhook URLs and API calls.
* Treat webhook payloads as operational events, not as an authentication mechanism.