Developer reference

Binnacle AI API

Read your fleet, credentials, voyages, and compliance data over a versioned REST API. Push events into Slack, Zapier, HubSpot, or your own systems with HMAC-signed webhooks. No SDK install required — every endpoint is plain HTTPS + JSON.

Authentication

Every request to /api/v1/* must include an Authorization header. Tokens look like bnk_live_ followed by 32 characters and are issued from Admin → API keys.

curl https://binnacleai.com/api/v1/vessels \
  -H "Authorization: Bearer bnk_live_yourtokengoeshere"

Tokens are bcrypt-hashed at rest. The cleartext is shown once at creation and is not recoverable — store it in a secrets manager.

Pagination + envelope

List endpoints accept limit (default 50, max 200) and offset (default 0). Responses use a consistent envelope:

{
  "data": [...],
  "pagination": { "limit": 50, "offset": 0, "total": 245 },
  "links": {
    "self": "https://binnacleai.com/api/v1/vessels?limit=50&offset=0",
    "next": "https://binnacleai.com/api/v1/vessels?limit=50&offset=50",
    "prev": null
  }
}

Rate limits

100 requests per minute per key, with a short burst allowance up to 200 req/min. Every successful response carries:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 73
X-RateLimit-Reset: 1714780320

When exceeded, the API returns 429 with Retry-After in seconds.

Errors

{ "error": "InvalidApiKey", "message": "Provide Authorization: Bearer ..." }
  • 401 InvalidApiKey — missing/malformed Authorization header
  • 401 RevokedApiKey / ExpiredApiKey
  • 404 NotFound — out-of-org or missing record
  • 429 RateLimitExceeded
  • 503 InternalError — transient

Endpoints

GET/api/v1/vessels

List vessels in the org with paginated envelope.

GET/api/v1/vessels/:id

Single vessel + crew + COI requirements.

GET/api/v1/crew

Paginated crew with nested credentials.

GET/api/v1/crew/:id

Single crew member with full assignment + credential detail.

GET/api/v1/credentials/expiring?days=30

Credentials expiring within N days. Default 30, max 365.

GET/api/v1/voyages

Voyages with vessel + manifest summary. Filter by status.

GET/api/v1/incidents

Cyber + maritime incidents. Filter by severity, status.

GET/api/v1/insurance/policies

Insurance policies (P&I, H&M, etc.). Filter by status, type.

GET/api/v1/cyber/plan

Org cyber plan(s) with element compliance rollup.

GET/api/v1/compliance/summary

Fleet-wide compliance score + COI / credential rollups.

Sample: GET /api/v1/vessels

curl https://binnacleai.com/api/v1/vessels?limit=2 \
  -H "Authorization: Bearer bnk_live_..."

{
  "data": [
    {
      "id": "ckxv...",
      "name": "Pacific Explorer",
      "official_number": "1234567",
      "subchapter": "T",
      "home_port": "Honolulu, HI",
      "coi_expiration": "2026-08-15T00:00:00.000Z"
    }
  ],
  "pagination": { "limit": 2, "offset": 0, "total": 14 },
  "links": { "self": "...", "next": "...", "prev": null }
}

Webhooks

Subscribe to compliance events from Admin → Webhooks. Pick events, point at your endpoint, and we'll POST a signed JSON payload every time the event fires. We retry failed deliveries at 1m, 5m, 30m, and 2h — after 5 consecutive failures the subscription is auto-disabled.

Available events

  • CREDENTIAL_EXPIRING 30/7/0 days before a credential expires.
  • CREDENTIAL_EXPIRED Credential past expiration.
  • DRILL_OVERDUE Required drill not logged within window.
  • DRILL_LOGGED New drill record posted.
  • INCIDENT_CREATED Any incident created.
  • INCIDENT_CLOSED Incident moved to closed.
  • COI_EXPIRING Vessel CoI within 90 days of expiry.
  • CYBER_INCIDENT_REPORTED 46 CFR 101.620 cyber incident reported.
  • WORK_REST_VIOLATION Sub M / STCW work-rest threshold exceeded.
  • OFAC_MATCH_FLAGGED OFAC SDN screening returned a positive match.
  • INSURANCE_RENEWAL_DUE Policy entering renewal notice window.
  • SURVEY_OVERDUE Class survey past due date.
  • PORT_CALL_PLANNED New port call scheduled.
  • CREW_ASSIGNED Crew member assigned to a vessel.
  • VOYAGE_DEPARTED Voyage transitioned to UNDERWAY.
  • VOYAGE_ARRIVED Voyage transitioned to COMPLETED.
  • ALL Wildcard — receive every event.

Sample payload

POST /your/endpoint
Content-Type: application/json
User-Agent: Binnacle-Webhook/1.0
X-Binnacle-Event: CREDENTIAL_EXPIRING
X-Binnacle-Delivery-Id: 4f3c2b...
X-Binnacle-Signature: sha256=8a7c4f...
X-Binnacle-Timestamp: 2026-04-22T18:00:00.000Z

{
  "event": "CREDENTIAL_EXPIRING",
  "orgId": "org_abc",
  "timestamp": "2026-04-22T18:00:00.000Z",
  "data": {
    "credential": {
      "id": "cred_123",
      "type": "STCW Basic Training",
      "expiration_date": "2026-05-22T00:00:00.000Z",
      "days_left": 30
    },
    "crew_member_id": "crew_456"
  }
}

Verify the signature (Node.js)

import crypto from "node:crypto";

function verify(secret, rawBody, headerSig) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");
  // Constant-time compare to defeat timing attacks.
  return crypto.timingSafeEqual(
    Buffer.from(`sha256=${expected}`),
    Buffer.from(headerSig)
  );
}

// Express:
app.post("/binnacle", express.raw({ type: "application/json" }), (req, res) => {
  if (!verify(process.env.BINNACLE_SECRET, req.body, req.header("X-Binnacle-Signature"))) {
    return res.status(401).send("bad signature");
  }
  const event = JSON.parse(req.body.toString());
  // ... handle event
  res.status(200).send("ok");
});

Verify the signature (Python)

import hmac, hashlib

def verify(secret: str, raw_body: bytes, header_sig: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode(), raw_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, header_sig)

# Flask:
@app.post("/binnacle")
def binnacle():
    sig = request.headers.get("X-Binnacle-Signature", "")
    if not verify(os.environ["BINNACLE_SECRET"], request.get_data(), sig):
        abort(401)
    event = request.get_json()
    # ... handle event
    return "ok", 200

Sandbox + support

Want a sandbox key with seed data so you can wire a Zap or test your endpoint without touching production?

Request a sandbox key

Built for evaluation-grade trust