Skip to main content

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 with tsx, 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 real 401 path before you have a production credential.
  • Compressed timeline: the sandbox resolves a command in about a second (queued for the first ~300ms, executing until ~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.
Every sample targets a different magic dock id — a deterministic dock that always behaves the same way, so you can exercise every status/outcome/error with zero physical hardware. The full reference table is at the bottom of this page.

Send a command

Expected output (command ids will differ):
A command send returns 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

Expected output (command ids will differ):
A command moves through 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

Expected output (command ids will differ):
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

Expected output (command ids will differ):
A dock runs one command at a time. Sending a command to a dock that already has one in flight returns 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

Expected output (command ids will differ):
The same 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

Expected output (command ids will differ):
Every error is an RFC 9457 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.
The schema also reserves 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.