Vessels
Vessel records the caller's API key can see (owned or team-member access).
/vesselsList vessels
Returns every vessel the API key's creator-user owns or has team-member access to. Deliberately a **bare array of `Vessel` objects wrapped only by the envelope** (`{ data: Vessel[] }`) — there is no `pagination` block on this endpoint (see "Known gaps" in `docs/api.md`: the multi-vessel downgrade-lock annotation needs the full owned-vessel set to compute `isLocked`/`lockReason` correctly, so this endpoint isn't cursor-paginated). Owned vessels beyond the caller's plan's vessel limit are annotated with `isLocked: true` rather than omitted.
| Field | Type | Required | Description |
|---|---|---|---|
| data | array<object> | required | — |
| data[].id | string (uuid) | optional | — |
| data[].ownerId | string (uuid) | optional | — |
| data[].vesselName | string | optional | — |
| data[].make | string | null | optional | — |
| data[].model | string | null | optional | — |
| data[].year | integer | null | optional | — |
| data[].hullNumber | string | null | optional | — |
| data[].vesselType | string | null | optional | VesselType enum, e.g. motor_yacht, sailing_yacht, catamaran. |
| data[].status | string | optional | VesselStatus enum, e.g. in_service, laid_up, in_refit. |
| data[].engineType | string | null | optional | — |
| data[].engineCount | integer | null | optional | — |
| data[].homePort | string | null | optional | — |
| data[].homePortLat | number | null | optional | — |
| data[].homePortLon | number | null | optional | — |
| data[].homePortResolved | string | null | optional | — |
| data[].homePortNeedsReview | boolean | optional | — |
| data[].length | number | null | optional | — |
| data[].beam | number | null | optional | — |
| data[].draft | number | null | optional | — |
| data[].airDraft | number | null | optional | — |
| data[].loaTotal | number | null | optional | — |
| data[].displacement | integer | null | optional | — |
| data[].grossTonnage | integer | null | optional | — |
| data[].fuelCapacity | integer | null | optional | — |
| data[].waterCapacity | integer | null | optional | — |
| data[].maxAccommodation | integer | null | optional | — |
| data[].maxRange | integer | null | optional | — |
| data[].cruisingSpeed | number | null | optional | — |
| data[].imoNumber | string | null | optional | — |
| data[].mmsi | string | null | optional | — |
| data[].callSign | string | null | optional | — |
| data[].flagState | string | null | optional | — |
| data[].complianceProfile | string | null | optional | — |
| data[].multiCurrencyEnabled | boolean | optional | — |
| data[].defaultCurrency | string | optional | — |
| data[].photo | string | null | optional | — |
| data[].dataConsistencyWarnings | array<object> | null | optional | — |
| data[].owner | object | optional | — |
| data[].owner.id | string (uuid) | optional | — |
| data[].owner.firstName | string | null | optional | — |
| data[].owner.lastName | string | null | optional | — |
| data[].owner.email | string | null | optional | — |
| data[].owner.phone | string | null | optional | — |
| data[].owner.profilePhoto | string | null | optional | — |
| data[].captain | object | null | optional | — |
| data[].captain.id | string (uuid) | optional | — |
| data[].captain.firstName | string | null | optional | — |
| data[].captain.lastName | string | null | optional | — |
| data[].captain.email | string | null | optional | — |
| data[].captain.phone | string | null | optional | — |
| data[].captain.profilePhoto | string | null | optional | — |
| data[].permissions | object | optional | Per-feature read/full permission map computed for the impersonated user. |
| data[].isLocked | boolean | optional | Present only when this owned vessel is over the caller's plan's vessel-count limit. |
| data[].lockReason | string | optional | — |
| data[].createdAt | string (date-time) | optional | — |
| data[].updatedAt | string (date-time) | optional | — |
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"]
# Respect Retry-After on 429s rather than hammering the endpoint. RATE_LIMITED# also carries meta.retryAfterMs on the JSON body if a proxy strips the header.import timeimport requestsdef get_with_backoff(url, headers, max_attempts=5):for attempt in range(max_attempts):resp = requests.get(url, headers=headers)if resp.status_code != 429:resp.raise_for_status()return resp.json()retry_after = resp.headers.get("Retry-After")wait_s = float(retry_after) if retry_after else 2 ** attempttime.sleep(wait_s)raise RuntimeError("exceeded max retries on 429 RATE_LIMITED")vessels = get_with_backoff("https://api.owlmar.com/v1/vessels",{"Authorization": f"Bearer {OWLMAR_API_KEY}"},)["data"]
/vessels/{id}Get a vessel
Returns a single vessel with its captain, permissions, and (unlike the list endpoint) the most recent equipment, maintenance events, documents, and trip logs nested inline (each capped at the most recent 10 rows — use the dedicated list endpoints for full history). 404 if the vessel doesn't exist or the caller has no access.
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | string (uuid) | required | — |
| Field | Type | Required | Description |
|---|---|---|---|
| data | any | required | GET /vessels/{id} — Vessel plus the 10 most recent nested equipment/maintenance/documents/trips and full inventory. |
curl -sS "https://api.owlmar.com/v1/vessels/$VESSEL_ID" \-H "Authorization: Bearer $OWLMAR_API_KEY"
const res = await fetch(`https://api.owlmar.com/v1/vessels/${vesselId}`, {headers: { Authorization: `Bearer ${process.env.OWLMAR_API_KEY}` },});if (res.status === 404) throw new Error('vessel not found or out of key scope');const { data: vessel } = await res.json();
resp = requests.get(f"https://api.owlmar.com/v1/vessels/{vessel_id}",headers={"Authorization": f"Bearer {OWLMAR_API_KEY}"},)vessel = resp.json()["data"]
