API documentation

Integrate the SAMO-TRANS exchange into your TMS or CRM

API documentation

Pagination and sync

The cursor, page limits and incremental synchronisation via updatedSince.

Lists (GET /proposals/search, GET /proposals/my) return the same wrapper:

{
  "data": [ /* … listings … */ ],
  "nextCursor": "eyJvIjoyMH0",
  "total": 137
}
  • data — the page of results.
  • nextCursor — an opaque string for the next page, or null when there are no more.
  • total — how many records match the filter in total.

Page size

The limit parameter defaults to 20 and maxes out at 100. A larger value is not an error — it is silently clamped. limit=500 returns 100 rows, not a 400.

Walking pages

Pass the nextCursor you received as cursor:

# first page
curl "https://api.samo-trans.com/api/public/v1/proposals/search?type=CARGO&limit=50" \
  -H "Authorization: Bearer $SAMO_KEY"

# next one
curl "https://api.samo-trans.com/api/public/v1/proposals/search?type=CARGO&limit=50&cursor=eyJvIjo1MH0" \
  -H "Authorization: Bearer $SAMO_KEY"

The cursor is opaque: do not parse or construct it, just echo back exactly what the server gave you. Its format may change without a version bump.

Important: this cursor is not keyset

The cursor currently encodes an offset, not a position in a stable ordering. Two practical consequences follow:

  1. Deep pages get expensive. Walking thousands of pages to mirror the whole exchange is a poor pattern — slow for you and heavy for us.
  2. The feed shifts between pages. While you read page 3, new listings arrive; a record can reappear on another page or slip past you entirely.

So always deduplicate by id, and do not assume the union of all pages contains exactly total distinct records. One more factor: reactivating a listing refreshes its createdAt, which moves it up the ordering.

The right way to synchronise

To maintain your own copy of the data, pull a delta rather than walking everything — that is what updatedSince is for:

curl "https://api.samo-trans.com/api/public/v1/proposals/search?updatedSince=2026-08-05T09:00:00.000Z&limit=100" \
  -H "Authorization: Bearer $SAMO_KEY"

Only listings changed at or after that moment come back. The loop:

  1. Record the time your sync starts.
  2. Request pages with updatedSince set to the last successful sync time.
  3. Apply changes locally, matching on id (insert or update).
  4. Store the new timestamp and repeat on a schedule.

Overlap slightly (say, a minute earlier than the last run). That is safe precisely because you deduplicate by id, and it protects you from edge effects on the second boundary.

If you need to react in real time rather than on a schedule, see webhooks: the proposal.matched event arrives on its own the moment a matching listing is published.