Quickstart
This page gets you from "no key" to "first successful call" in under 15 minutes. If it takes longer than that, something on this page is wrong — tell us at [email protected].
1. Get a key
- Log in to the app and go to Settings → API Keys.
- Click Create API Key, give it a label (e.g. "Quickstart test key"), and leave the default scope (all vessels, no module restriction) for now — you'll narrow it later.
- Copy the raw secret shown on screen. This is the only time it's shown — OwlMar never stores or displays it again, only its SHA-256 hash.
Store the key somewhere you can find it — an environment variable, a secrets manager, a password manager. If you lose it, revoke it and create a new one; it cannot be recovered.
Export it in your shell for the rest of this page:
export OWLMAR_API_KEY="owlmar_live_..."
2. Make your first call
curl -sS "https://api.owlmar.com/v1/vessels" \-H "Authorization: Bearer $OWLMAR_API_KEY"
const res = await fetch('https://api.owlmar.com/v1/vessels', {headers: { Authorization: `Bearer ${process.env.OWLMAR_API_KEY}` },});const { data: vessels } = await res.json();console.log(vessels.map(v => v.vesselName));
import requestsresp = requests.get("https://api.owlmar.com/v1/vessels",headers={"Authorization": f"Bearer {OWLMAR_API_KEY}"},)vessels = resp.json()["data"]
3. Read the response
A successful call returns every vessel your key's creator-user owns or has team-member access to, wrapped in the standard envelope:
{"data": [{"id": "3f1c9e2a-...","vesselName": "Sea Wolf","make": "Sunseeker","model": "Predator 68","year": 2022,"status": "in_service"}]}
Every /v1/* response — list or single record — has a data key. List endpoints that support
cursor pagination also carry a pagination block. Full contract:
Response Envelope.
4. Handle an error
Try the same call with a broken key to see the shape of a failure:
curl -sS "https://api.owlmar.com/v1/vessels" \-H "Authorization: Bearer owlmar_live_not_a_real_key"
{ "error": "Invalid or revoked API key", "code": "AUTH_REQUIRED" }
Every error response has an error (human-readable, may change wording) and a code
(machine-readable, stable — switch on this in your integration). A 403 for a scope you don't
have looks like this instead:
{ "error": "This API key is not scoped for read access to maintenance_logs", "code": "INSUFFICIENT_SCOPE" }
Auth failures never distinguish "missing header" from "wrong key" from "revoked key" — all
three return the same generic 401 AUTH_REQUIRED, the same non-enumeration principle as the
app's own login form.
5. Next steps
- Narrow your key's scope to just the vessels and modules your integration needs — see Authentication.
- Read Pagination before writing any code against a list endpoint with more than a handful of rows.
- If your integration writes data, read Idempotency before your
first
POST— retrying a network timeout without it can create duplicate records. - Adapt one of the four Recipes — each is a complete, runnable script.
