Want the full platform? Book a demo

API Reference · v1

The CargoMode API

Pull your bookings, containers and RFQ quotes out of CargoMode and into your own TMS, CRM or warehouse. REST over HTTPS, JSON in and out, built for incremental sync.

Your first request
curl https://www.cargomo.de/api/v1/bookings \
  -H "Authorization: Bearer cm_live_YOUR_API_KEY"

Endpoints

Authentication

Every /api/v1 request is authenticated with a bearer token. Keys look like cm_live_ followed by 40 hex characters, and are scoped to a single organization — a key only ever returns your own data.

curl https://www.cargomo.de/api/v1/bookings \
  -H "Authorization: Bearer cm_live_YOUR_API_KEY"

Getting a key

Keys are issued by the CargoMode team. Email us with your organization name and what you're building, and we'll provision one and send it over securely.

api@cargomo.de →

Keep keys server-side. A key carries full read access to your organization's bookings and quotes, so it belongs in an environment variable on your backend — never in browser JavaScript or a mobile app. Only a SHA-256 hash of each key is stored, so a lost key can't be recovered; ask us to revoke it and we'll issue a replacement.

Pagination & sync

List endpoints return rows ordered by updatedAt ascending — oldest change first. Pass the meta.nextSince value from one response back as the since parameter of the next request to walk forward through changes. When nextSince comes back null, you are caught up.

  1. 1

    First run: call without since to get the oldest page.

  2. 2

    Store meta.nextSince and pass it as since on the next call.

  3. 3

    nextSince: null means no more rows. Persist the last cursor and resume from it on your next scheduled run.

Incremental sync loop
// Walk every page, then persist the cursor for the next run.
let since = await loadCursor() // null on first run
let url = new URL('https://www.cargomo.de/api/v1/bookings')
url.searchParams.set('limit', '100')

while (true) {
  if (since) url.searchParams.set('since', since)

  const res = await fetch(url, {
    headers: { Authorization: `Bearer ${process.env.CARGOMODE_API_KEY}` }
  })
  const { data, meta } = await res.json()

  for (const booking of data) await upsertIntoYourTms(booking)

  if (!meta.nextSince) break // caught up
  since = meta.nextSince
}

await saveCursor(since)

Because the cursor tracks updatedAt, a record that changes after you've synced it reappears in a later page. Upsert on the record id rather than inserting blindly.

Errors

Errors use standard HTTP status codes and return a JSON body with a human-readable message.

  • 400A parameter is malformed — e.g. `since` is not a valid ISO 8601 timestamp.
  • 401No `Authorization` header, a key that is not `cm_live_…`, or a revoked key.
  • 404The record does not exist, or belongs to another organization.
  • 500Unexpected server error. Safe to retry with backoff.
401 Unauthorized
{
  "statusCode": 401,
  "message": "Missing API key. Send it as: Authorization: Bearer cm_live_..."
}

What v1 covers

v1 is a read API. It exists so the data CargoMode assembles — bookings enriched from documents and carrier APIs, RFQs with their extracted fields and quotes — can flow into whatever system you already run your business on.

Writing bookings or RFQs back in over HTTP isn't part of v1 yet. Today that happens through the product itself: documents emailed to your ingestion address, and rate requests emailed to your RFQ address, both of which create records the API then returns. Tell us what you need to write — it shapes what ships next.