SOT Guild Logo
SOT Ship Invite API
v1.0

SOT Ship Invite API — Documentation

A minimal REST API to create Sea of Thieves captain's ships sessions.

Sea of Thieves API Guild

Quickstart

  1. Get an API key from the admin and keep it secret.
  2. Send the X-Api-Key header with every request.
  3. Call POST /api/invitations with shipId and gamertag.
  4. Follow progress with SSE events or poll the status endpoint.

Base URL

Production
https://sotguildapi.live

Authentication

Every request must include:

X-Api-Key: <your_base64_key>

Missing or invalid keys return 401/403.

Errors

Errors are structured like:

{
  "detail": { "code": "invalid_api_key", "message": "X-Api-Key missing or invalid" }
}
HTTP Meaning
400Bad request (missing/invalid JSON or headers)
401/403Missing/invalid API key
404Not found (e.g., shipId absent from DB)
502Upstream Xbox error or expired token not recoverable
500Internal server error

GET /health

Simple heartbeat to confirm the API is running.

Request
curl -s https://sotguildapi.live/health
200 Response
{"status":"ok"}

POST /api/invitations

Starts a SOT session + Xbox crew session and sends an invitation to the provided gamertag.

Body (JSON)
{
  "shipId": "<shipID>",     // UUID
  "gamertag": "<gamertag>" // ex: 2584878536129841
}
Headers
Content-Type: application/json
X-Api-Key: <base64_key>
Example (curl)
curl -X POST https://sotguildapi.live/api/invitations \
  -H 'Content-Type: application/json' \
  -H 'X-Api-Key: YOUR_CLIENT_KEY' \
  -d '{"shipId":"<shipID>","gamertag":"<gamertag>"}'
202 Response (example)
{
  "task_id": "<taskId>",
  "status_url": "/api/invitations/<taskId>",
  "events_url": "/api/invitations/<taskId>/events"
}

If shipId is not found in DB, the API returns 404. Xbox 403 triggers a token refresh; if refresh fails, 502 is returned.

GET /api/invitations/{taskId}

Check the current state of an invitation task (use it if you prefer polling instead of SSE).

Request
curl -s -H 'X-Api-Key: YOUR_CLIENT_KEY' \
https://sotguildapi.live/api/invitations/<taskId>
200 Response (examples)
{
  "taskId": "...",
  "state": "pending",         // pending | running | succeeded | failed | cancelled
  "progress": 35,             // 0..100 (optional)
  "lastEvent": "session.created",
  "updatedAt": "2025-09-02T12:34:56Z"
}

{
  "taskId": "...",
  "state": "succeeded",
  "invited": { "gamertag": "<gamertag>", "xuid": "..." }
}

{
  "taskId": "...",
  "state": "failed",
  "error": { "code": "xbox_token_expired", "message": "Token could not be refreshed" }
}

GET /api/invitations/{taskId}/events

Server-Sent Events stream to follow real-time progress.

Request
curl -N \
  -H 'Accept: text/event-stream' \
  -H 'X-Api-Key: YOUR_CLIENT_KEY' \
  https://sotguildapi.live/api/invitations/<taskId>/events
Events (examples)
event: session.created
data: {"sessionId":"...","type":"SmallShip"}

event: invite.sent
data: {"to":"<gamertag>","xuid":"..."}

event: member.joined
data: {"gamertag":"<gamertag>"}

event: error
data: {"message":"Xbox token expired","retry":true}

Examples

Python (requests)
import requests
API="https://sotguildapi.live/api/invitations"
headers={"X-Api-Key":"YOUR_CLIENT_KEY","Content-Type":"application/json"}
body={"shipId":"<shipID>","gamertag":"<gamertag>"}
r=requests.post(API,json=body,headers=headers,timeout=30)
print(r.status_code, r.text)
Node.js (fetch)
const res = await fetch('https://sotguildapi.live/api/invitations', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Api-Key': process.env.API_KEY
  },
  body: JSON.stringify({ shipId: 'f07b...', gamertag: '<gamertag>' })
});
console.log(res.status, await res.text());

Notifications

  • SSE via /api/invitations/{taskId}/events
  • Polling via /api/invitations/{taskId}