> 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.

# Create a staff invitation

> Invite a person into one Sailor workspace with retry-safe tenant isolation.

The staff API creates or renews a tenant-pinned Sailor staff invitation in the exact workspace owned by the API key. The invited person becomes a Sailor staff member after accepting the invitation.

> **Info**
>
> Sailor derives the organization and subaccount from the API key. Neither identifier can be supplied or overridden in the request.

## Request

The API key needs the `staff:write` scope. Send a unique `Idempotency-Key` for each intended invitation.

```bash
curl https://api.sailorhq.io/staff/invites \
  --request POST \
  --header "Authorization: Bearer $SAILOR_API_KEY" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: $SAILOR_IDEMPOTENCY_KEY" \
  --data '{
    "email": "agent@example.com",
    "role": "agent",
    "team_ids": ["00000000-0000-4000-8000-000000000012"]
  }'
```

| Field      | Required | Description                                                    |
| ---------- | -------- | -------------------------------------------------------------- |
| `email`    | Yes      | Invitation recipient. Sailor normalizes it to lowercase.       |
| `role`     | Yes      | `admin` or `agent`.                                            |
| `team_ids` | No       | Up to 100 unique Sailor team IDs from the API key's workspace. |

Unknown fields are rejected. A caller cannot provide organization, subaccount, or external-system identifiers.

## Response

```json
{
  "ok": true,
  "staff_invite": {
    "id": "00000000-0000-4000-8000-000000000010",
    "email": "agent@example.com",
    "role": "agent",
    "subaccount_id": "00000000-0000-4000-8000-000000000011",
    "team_ids": ["00000000-0000-4000-8000-000000000012"],
    "status": "email_sent",
    "expires_at": "2026-08-18T00:00:00.000Z"
  }
}
```

`email_delivery_failed` means the tenant-pinned invitation exists but its email needs to be resent from Sailor. It does not mean the invitation was lost.

## Recovery

| Code                      | Meaning                                                               | Recovery                                                            |
| ------------------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------- |
| `invalid_request`         | The email, role, body, or a team ID is invalid for this workspace.    | Correct the request and use a new idempotency key.                  |
| `resource_conflict`       | The email is already an active member or a concurrent invitation won. | Use Sailor staff access controls or resend the existing invitation. |
| `temporarily_unavailable` | Sailor could not persist or verify the invitation.                    | Wait for `Retry-After`, then retry.                                 |

If Sailor returns `409 request_in_progress`, retry with the same key after `Retry-After`. A completed response is replayed exactly for that key.

> **Tip**
>
> Create one key per automation and grant only `staff:write` when it manages only Sailor staff invitations.

## Related

* [Authentication](/authentication)
* [Rate limits](/rate-limits)
* [Smart Lists](/smart-lists)