Changelog
History of changes to the SAMO-TRANS public API.
Newest entries on top. Every change to the public contract lands here.
For the compatibility rules, see Versioning.
v1.1
-
Added: transport listings now have an optional
vehicleTypefield, independent fromcarTypes. The newGET /reference/vehicle-typesendpoint supplies valid codes;nullin aPATCHclears the value. Responses return either the code ornull. The field is rejected for cargo listings. This is additive: existing records and integrations remain valid. -
Added:
GET /reference/car-typesnow also returns the specialised body codesbox_type,walking_floor_type,coil_carrier_type,timber_truck_type,concrete_mixer_type, andhooklift_type. This is an additive dictionary change; integrations should read the endpoint and tolerate new codes instead of maintaining a closed local enum. -
Added: listings now carry an optional temperature range. Create and update bodies accept
temperatureMinandtemperatureMax(°C, range −99…+99, either bound may be omitted); responses returntemperatureMinCandtemperatureMaxC, bothnullwhen no range is set. The fields are accepted only together with a temperature-controlled body (ref,ref-tushe,izoterm), otherwise the request fails with400 validation_error. APATCHthat changes the body type to a non-temperature-controlled one resets both bounds. The change is additive: existing integrations lose nothing and may simply ignore the new fields. -
Changed: contacts are now stripped from
descriptionbefore a listing is stored — phone numbers, e-mail addresses,@handlesand links (including bare domains and messenger links). Applies toPOST /proposals/cargo,POST /proposals/transport,POST /proposals/batchandPATCH /proposals/{id}. This is not validation: a request carrying a phone number in the description still succeeds — there is no error, the listing is simply saved with the cleaned text. Consequence for integrations: thedescriptionin the response and on any laterGETmay be shorter than the one you sent — do not compare those strings for equality. Text without contacts comes back untouched: trip dates, tax numbers, weights and prices are never mistaken for a phone number. The field's description in the reference was updated. -
Fixed: a non-numeric locality id no longer answers
500 internal.startLocalities/endLocalitiesonGET /proposals/search, plusstartLocations[].osmIdandendLocations[].osmIdwhen creating or updating a listing, accept only a positive integer OSM ID. Anything else — letters, a decimal, a sign, a value past thebigintrange — now returns400with codevalidation_error; such a request used to fail with500 internal. Valid ids behave exactly as before. -
Changed:
POST /proposals/{id}/bumpis now also available to an owner or manager of the company the listing belongs to — exactly the rights that already applied toupdate,archiveanddelete. Previously only the listing's author or contact person could bump it, so a company owner got403 forbiddenon their own employee's listing while being able to edit it or take it off air. Nothing is narrowed — access is only widened, so existing integrations lose nothing. -
GET /proposals/searchacceptsstartLocalityCountriesandendLocalityCountries— the country of each entry instartLocalities/endLocalities, in the same order. With them the results also include listings posted for that whole country ("any direction"), not only the ones tied to the city itself. Both are optional — without them search behaves as before. -
GET /employees— list company staff. -
GET /employees/{id}/proposals-count— how many listings name the employee as contact. -
PATCH /employees/{id}/status— activate or temporarily deactivate an employee. -
PATCH /employees/{id}— change role or display name. -
New scopes
employees:readandemployees:write. Previously issued keys do not carry them — create a new key. -
contactPersonIdis now accepted when creating and updating a listing (batch included). Only the company owner and employees with statusACTIVEare allowed. -
Changed:
GET /localities/searchnow also returns regions (type: "region") — the response used to carry countries and localities only, so a region could not be found by name. Order is countries → regions → localities. No new fields, one more kind of array entry — if you expect anosmIdon every record, filter bytype === "locality". -
Changed:
GET /proposals/searchreturns closed listings after every open one, newest first within each group. Ordering used to be bycreatedAtalone, so withincludeInactive=trueclosed listings were mixed in among the open ones. The response is unchanged — only its order; if you relied on a purely chronological sequence, sort bycreatedAton your side. -
Changed:
descriptionon listing create and update (batch included) is capped at 250 characters. Its length used to go unchecked — any string was accepted. A longer text now gets a400with codevalidation_error; trim the description on your side. The cap is also visible in the reference as the field'smaxLength. -
Fixed:
GET /employeesnow always returns the company owner, with roleOWNER. Companies carried over from the previous platform had no such record, so their staff list started with hired people. No field changed — the array simply has one more element. If you size your staff by the length of the response, count the owner in. -
Fixed:
avatar(on employees and on a listing's contact person) is always an absolute URL. Some records used to carry a bare storage key (avatars/….jpeg), which a client resolved against its own address and got a 404 for. The field's type is unchanged — it is the same URL string. -
Fixed:
includeInactiveonGET /proposals/searchused to read any non-empty value astrue, so evenincludeInactive=falsereturned closed listings. It is now read as written:true/1/yes/onenable it,false/0/no/offdisable it, and an unrecognised value behaves as if the parameter were absent. If your integration sentfalseand relied on getting closed listings back, it will now receive a different set — sendtrueexplicitly.
v1.0
The first public release of the API.
Dictionaries
GET /reference/countries,/reference/regions— geography.GET /reference/car-types,/load-types,/permits,/currencies,/payment-types— code dictionaries with labels in five languages.GET /localities/search— locality search, the source of routeosmIds.
Exchange
GET /proposals/search— search the whole exchange with the web app's filters, plusupdatedSincefor incremental sync.GET /proposals/{id}— listing detail.GET /companies/{id},GET /companies/{id}/reviews— counterparty profile and approved reviews.
Your own listings
POST /proposals/cargo,POST /proposals/transport— creation.POST /proposals/batch— up to 25 listings per request with a per-item result.GET /proposals/my— listings of the company the key belongs to.PATCH /proposals/{id},POST /proposals/{id}/bump,/archive,/restore,DELETE /proposals/{id}.
Platform
- Authentication with
samo_live_keys carryingreference:read,proposals:readandproposals:writescopes plus an optional IP allowlist. - Per-key rate limits with
X-RateLimit-*headers and the stablerate_limited/quota_exceededcodes. Idempotency-Keysupport for safe write retries.- Webhooks for
proposal.created/updated/deletedandproposal.matched, signed withX-Samo-Signature. - The stable error envelope
{ error: { code, message, requestId } }.