Quickstart
This walks through the dock-control surface end to end against the sandbox — a zero-signup reference implementation of the reserved dock-control API. Every sample below is a self-contained TypeScript file: copy it, run it withtsx, and it talks to the real sandbox over plain fetch. No SDK, no shared helper library.
What you need
- Base URL:
https://outpost.earthity.com/api/sandbox. The sandbox serves the exact same paths, request/response shapes, and error catalog as production — only the base URL and the dock ids differ. - Auth: an “instant key” — any well-formed
Authorization: Bearer spk_<anything>header is accepted. Nothing is validated against a store or persisted; it exists purely so you exercise a real401path before you have a production credential. - Compressed timeline: the sandbox resolves a command in about a second (
queuedfor the first ~300ms,executinguntil ~1200ms, terminal after) instead of the ~45s a real dock stroke takes. Poll intervals and deadlines below are sized for that compressed timeline — widen them against a real dock.
Send a command
202 Accepted immediately — the physical stroke hasn’t happened yet. The body carries a commandId to poll, and the Location header points at that same command’s own resource. The Idempotency-Key header is required: omit it and the request is rejected with 400 validation_failed (see error anatomy below).
Poll to a terminal outcome
queued -> executing -> a terminal state (succeeded or failed, each carrying an outcome). Poll GET .../commands/{commandId} on a short interval until you observe a terminal status, or your own deadline elapses. Never assume the first GET after a 202 is already terminal — treat every non-terminal response as expected, not an error.
Failure is a terminal outcome, not an HTTP error
sbx-obstructed always resolves failed/OBSTRUCTED — the actuation didn’t complete. The GET that reports that is still HTTP 200: the command lifecycle succeeded (it reached a terminal state), independent of whether the actuation itself did. Decide success or failure from the response body’s status/outcome fields, never from the HTTP status code alone.
Handle dock_busy
409 dock_busy — a problem+json body, not a 2xx. The right response is to back off and retry later with a fresh Idempotency-Key; retrying with the same key just replays into the same busy dock.
Retry safely with idempotency
Idempotency-Key and the same request body replays the original 202 response verbatim — same commandId, no second actuation. That’s what makes it safe to retry a request you’re not sure landed: resend it unchanged. The same key with a different body is rejected with 409 idempotency_key_reused — the key identifies one specific request, not a reusable slot, so the server refuses to guess which body you meant. A genuinely different command needs a new key.
Error anatomy
application/problem+json body:
type— a URI identifying the error kind. It resolves to a docs page under/errors/<code>— this member is the documentation link.status— the HTTP status code, repeated in the body.title— a short, stable, human-readable summary of the error kind.code— the machine-readable error code. Stable across releases; safe to switch on in client code.detail— optional, request-specific detail. Present on some codes, absent on others — never rely on it being there.
instance, documentation_url, and request_id members for production use; the sandbox doesn’t populate them today, so treat type as your documentation link in the meantime.
Magic dock id reference
Every dock id below is deterministic — pick the one that exercises the behavior you’re testing.
Any other dock id returns
404 not_found.