Trawish APIdeveloper docs

Odaduu · DMC QuoteOps · v1

Odaduu Public API

A small, stable HTTP surface for B2B partners to pull booking status, browse our reference catalogs, and submit new RFQs into the Odaduu sales pipeline. Bearer-authenticated, JSON in and JSON out, cursor-paginated where it matters.

Base URLhttps://builder.odaduu.com/api/public/v1

Overview

Every request is bearer-authenticated. Keys are minted per partner and (optionally) bound to a specific agent — an agent-scoped key can only see its own bookings and can only submit RFQs on that agent’s behalf. Reference catalogs are always org-wide.

Default rate limit is 1000 requests per rolling hour per key. Every response carries X-RateLimit-Limit and X-RateLimit-Remaining headers.

Authentication

Send your key in the Authorization header:

Authorization: Bearer odaduu_live_ab12CDEfghIJKlmnOP34

We show the full secret once at mint time. If you lose it, revoke the key and mint a fresh one — we cannot recover the plaintext. The first 20 characters (the odaduu_live_ab12CDEf prefix) stay visible in our admin so we can identify a key without seeing the secret.

Response envelope

All successful responses wrap the payload:

{
  "ok": true,
  "data": { "id": "cl...", "ref": "OD-2026-4132", "status": "quote_sent", ... },
  "meta": { "count": 10, "nextCursor": "eyJ0Ijoi..." }
}

Errors follow the same shape:

{
  "ok": false,
  "error": { "code": "unauthorized", "message": "invalid API key" }
}

List endpoints return an opaque meta.nextCursor. Pass it back on the next request to page forward — its value is stable across concurrent writes.

Endpoints

Health

GET/health

Verifies your key and echoes the tenant it resolves to. Hit this first after mint.

Returns { status: 'ok', orgId, agentId, apiVersion, serverTime }.

Bookings

GET/bookings

List bookings visible to your key, newest first. Agent-scoped keys see only their own bookings.

ParamTypeNotes
statusstring, optionaldraft_quote | quote_sent | client_confirmed | ops_in_progress | travel_completed | cancelled
limitint, optionalPage size (default 25, max 100)
cursorstring, optionalOpaque token from a prior response's meta.nextCursor

Returns a page of BookingSummary. meta.nextCursor is null when there is no more.

GET/bookings/{id}

Full detail for one booking, including the currently active quote's total in your sell currency.

POST/quotes

Submit an RFQ. Creates a DRAFT_QUOTE booking on our side; sales picks it up in the internal dashboard and builds the itinerary.

{
  "destinationCode": "JP",
  "guestName": "Mr. Sharma",
  "arrivalDate": "2026-11-05",
  "departureDate": "2026-11-14",
  "pax": { "adults": 2, "children": 1, "infants": 0 },
  "childAges": [8],
  "leadSource": "EMAIL",
  "agentRequirements": "Vegetarian meals"
}

Returns the created BookingDetail (activeQuote is null until sales builds it).

Reference catalogs

GET/destinations

Destinations available for RFQ submission.

GET/hotels

Hotel catalog. Filter by city or free-text name match.

ParamTypeNotes
citystring, optionalCase-insensitive equality
qstring, optionalSubstring match on name
limitint, optionalDefault 100, max 200
GET/sightseeings

Paid activities + free stops.

ParamTypeNotes
citystring, optionalMatches against the catalog's cities[] array
categorystring, optionalPAID | FREE
kindstring, optionalSIGHTSEEING | ACTIVITY | SHOPPING | WALKING
qstring, optionalSubstring match on name
GET/fullday-tours

Private full-day tour catalog with per-seater JPY pricing.

ParamTypeNotes
citystring, optionalMatches against the catalog's cities[] array
qstring, optionalSubstring match on name

Error codes

Codes are stable across versions. Messages may drift; match on codes.

CodeHTTPWhen it fires
unauthorized401Missing / malformed / unknown / expired key.
forbidden403Key is valid but not permitted for this resource.
not_found404Booking (or similar) does not exist or is out of scope for your key.
bad_request400Payload validation failed. `error.details` carries specifics.
rate_limited429Hourly quota exceeded. `error.details.retryAfterSec` tells you when to retry.
conflict409Reserved for write endpoints; not raised by v1 today.
internal_error500Server-side fault. Please report with `error.details.hint`.
not_implemented501Public API is disabled on this deployment.

curl examples

Health check — first thing to run after minting a key.

curl -H 'Authorization: Bearer odaduu_live_...' \
  https://builder.odaduu.com/api/public/v1/health

List your quote-sent bookings.

curl -H 'Authorization: Bearer odaduu_live_...' \
  'https://builder.odaduu.com/api/public/v1/bookings?limit=10&status=quote_sent'

Submit an RFQ.

curl -X POST -H 'Authorization: Bearer odaduu_live_...' \
  -H 'Content-Type: application/json' \
  -d '{
    "destinationCode": "JP",
    "guestName": "Mr. Sharma",
    "arrivalDate": "2026-11-05",
    "departureDate": "2026-11-14",
    "pax": { "adults": 2, "children": 1, "infants": 0 },
    "childAges": [8],
    "leadSource": "EMAIL",
    "agentRequirements": "Vegetarian meals; wheelchair-friendly hotels"
  }' \
  https://builder.odaduu.com/api/public/v1/quotes

Getting started

  1. Ask your Odaduu account manager at [email protected] to mint you a key. They will send you the full secret once — store it in your secret manager immediately.
  2. Run the /health call above to confirm auth is wired up and your key resolves to the right tenant.
  3. Poll /bookings to pull your live pipeline, or hit /quotes to open new RFQs directly from your system.
  4. Watch X-RateLimit-Remaining on every response and back off when it approaches zero — a 429 comes with retryAfterSec in the error details.