Room Matching APIReference · latest POST · GZIP · TEXT/PLAIN room-matching.com ↗
Room Matching · Real-time room type mapping

Room Matching API

Turn raw supplier room names into structured, comparable room types in real time, straight from your live availability responses. No pre-mapped cache. One POST call gives you back the mapped room type, its attributes, an equivalence group for cross-supplier matching, a quality score and AI-ready room names in six languages.

The engine reads the live supplier room name and description, detects room type, category, view, bed setup, amenities, restrictions and commercial signals, then groups equivalent rooms by real similarity, not by supplier label. Mapping happens at request time, so a label that was never seen before, or that just changed, gets mapped instantly. Nothing is missed by a stale cache.

Base URL & format

POST https://travelmap.tech/map/room
ItemValue
MethodPOST
Content-Typetext/plain, the body is a JSON string
Compressiongzip supported on request and response
Responseapplication/json
AccessBy credential (in the body) or by IP allow-list

Why text/plain?

The payload is sent as a JSON string over text/plain so it can be gzip-compressed transparently and stays cheap to stream at high availability-call volume. Serialize your object with JSON.stringify (or your language's equivalent) and send it as the raw body.

The call maps a batch of supplier rooms in one request. Rooms that describe the same physical product are given the same group, so you can compare and deduplicate across suppliers even when names, codes and languages differ.

Authentication

Every request carries a credential field in the JSON body. Credentials are scoped to your account and rate tier. Server-to-server integrations can also be authorized by IP allow-list. In that case the credential still identifies the account for billing and profile selection.

Workflows

Send any combination of suppliers, hotels and rooms in one list. Common shapes:

  • 1 supplier - 1 hotel - 1 room
  • multiple suppliers - 1 hotel - 1 room
  • 1 supplier - 1 hotel - multiple rooms
  • 1 supplier - multiple hotels - multiple rooms
  • multiple suppliers - 1 hotel - multiple rooms
  • multiple suppliers - multiple hotels - multiple rooms

The API returns them sorted by the supplier alias and hotel code you send.

Maximum accepted: 30k rooms per call.

Best practice. Send a rooms list per hotel.

Quickstart: list all rooms

Send one or more supplier rooms in list. Each item is a room exactly as your supplier returned it. A name is enough to start. Add description and rate and you get richer attributes and price optimization on top.

cURL
# body is a JSON string, sent as text/plain, gzip optional
curl https://travelmap.tech/map/room \
  --compressed \
  -H "Content-Type: text/plain" \
  --data-binary '{"credential":"mycredential","list":[{"hid":"79683","supplier":"OTA","name":"overwater suite Two Bedrooms DOUBLE OU TWIN - VARANDA pool","rate":354}]}'

Room name & description

Two fields carry the room: name and description. The name is the headline, the description is the detail. You can send either, but the more you send the richer the mapping and the higher the curated coverage.

FieldNotes
nameThe raw supplier room label. Everything found here is flagged inName:true in the response, so you know it came from the headline. Treat these as the room's promises: type, beds, view, size.
descriptionThe long room text. It adds the attributes a name leaves out (amenities, surface in m², board, policies) and can carry HTML and HTML entities, which the engine strips before reading.

How they work together

  • Name for the headline, description for the depth. A name gives you type, beds and view fast. A description fills in the rest and lifts curated.
  • Description wins on conflict. When the name and the description disagree, the description is trusted. See the override example.
  • HTML is fine. Tags and entities in the description are stripped, so you can pass supplier content as-is. See the HTML example.
  • Mixed languages are fine. Names like "Vista al mar + King Bed" map the same way, and the output comes back in every supported language.

Send at least a name. Add a description whenever you have one: it is where most amenities, the surface and the policies come from.

Request body

A JSON object with a credential and a list of room items.

Top level

FieldTypeNotes
credential requiredstringYour account credential.
list requiredarrayOne or more room items (batch supported).

Room item (list[])

FieldTypeNotes
name requiredstringRaw supplier room name.
description optionalstringRaw room description. Strongly improves attribute extraction (amenities, surface, policies).
hid optionalstringSupplier hotel code. Keeps results traceable per hotel.
supplier optionalstringSupplier / source name. Echoed back as suppl.
roomCode1 optionalstringSupplier room / rate-plan code. Echoed as rcode1.
roomCode2 optionalstringSecondary room / rate code. Echoed as rcode2.
rate optionalnumberRoom price. Required to enable cheapest-in-group / cheapest-in-range price signals.
Request · JSON body
{
  "credential": "mycredential",
  "list": [{
    "hid": "79683",
    "supplier": "OTA",
    "roomCode1": "156641",
    "roomCode2": "RM0",
    "rate": 354,
    "name": "overwater suite Two Bedrooms DOUBLE OU TWIN - VARANDA pool",
    "description": "77.0m2; bathroom shower bathtub hairdryer tv internet kitchen washing machine air conditioning balcony terrace wheelchair accessible wifi private beach ..."
  }]
}

// Send several items in list to map and compare a whole hotel in one call.

Call example: description & HTML

Pass the room name and a full description. The description can hold raw HTML and HTML entities. The engine strips the markup and reads the text inside, so you send supplier content as-is without cleaning it first. It still catches every signal in there: board (breakfast for 2), policy (no cancel), beds (2 king and murphy bed), accessibility (ADA compliant, hearing impaired) and occupancy (3ad+2ch).

Request · name + HTML description
{
  "credential": "mycredential",
  "list": [
    {
      "hid": "123456",
      "suppl": "supplier",
      "rcode1": "7654321",
      "rcode2": "booking ref: 234567",
      "name": " 2 bdrm duplex Luxussuite with an amazing ocean view on corner.",
      "description": "<div class=&#x27;preserveHtml&#x27;>room only</b> - 2 king and murphy bed &#013; 1 shared bathroom- free parking - ADA compliant hearing impaired (3ad+2ch) breakfast for 2 no cancel</div>",
      "amount": 1200
    }
  ]
}

Call example: with override

When the name and the description disagree, the description wins. Here the name says CANCELABLE full board, but the description says none cancelable halfboard. The mapped room follows the description: non-cancelable, half board. Use it to correct a wrong or promotional room name with the facts you trust.

Request · description overrides the name
{
  "credential": "mycredential",
  "list": [
    {
      "hid": "123456",
      "suppl": "supplier",
      "rcode1": "7654321",
      "rcode2": "booking ref: 234567",
      "name": " 2 bdrm duplex Luxussuite CANCELABLE full board.",
      "description": "**** none cancelable halfboard",
      "amount": 1200
    }
  ]
}

The description overrides the name on conflicting signals, so the final CAN and BRD come from the description, not the label.

Call example: multiple sources

Put several suppliers in one list and map them together. The same room in different wording and languages lands in one group, so you get cross-supplier matching, duplicate removal and best-rate comparison in a single call. Send amount on each to unlock the price signals. rcode2 is a free field: pass a booking ref, a wildcard, anything. It does not affect mapping.

Request · one room, four sources
{
  "credential": "mycredential",
  "list": [
    {
      "hid": "1234567",
      "suppl": "bedbank1",
      "rcode1": "7654321",
      "rcode2": "this is a wildcard",
      "name": "hilton 2 bdrm large duplex Luxussuite with an amazing sea view on corner. kitchen and balkon - private pool & Jacuzzi on rooftop- room only - 2 king and murphy bed - free parking - ADA compliant (3ad+2ch) breakfast for 2 no cancel",
      "amount":"1234.54"
    },
    {
      "hid": "AA2345",
      "suppl": "bedbank2",
      "rcode1": "7654321",
      "rcode2": "booking ref: 234567",
      "name": "  2 bedrooms wide duplex suite deluxe corner sea view balcony - private pool 2 king and extra bed",
      "amount":"1200"
    },
    {
      "hid": "AA2123",
      "suppl": "gds1",
      "rcode1": "AAD435444",
      "rcode2": "//ERTYYO 6543222 REZZ67899@@<mention value="3">3</mention>##",
      "name": "  2 bedrooms wide duplex suite deluxe corner sea view view balcony",
      "amount":"1310"
    },
    {
      "hid": "76589054",
      "suppl": "gds2",
      "rcode1": "TT5555",
      "rcode2": "this is a wildcard",
      "name": "  2 bdrm large dupleix suite delujo corner vista mar balcon",
      "amount":"1299"
    }
  ]
}

All four names describe the same room in different wording and languages. They map to one group, and groupCheapest marks the 1200 rate (bedbank2) as the best.

One room call

One room in, the full mapped object out. Here is a real call, the same example you see on the landing page.

Request
{
  "credential": "mycredential",
  "list": [
    {
      "hid": "79683",
      "supplier": "OTA",
      "roomCode1": "156641",
      "roomCode2": "RM0",
      "rate": 354,
      "name": "overwater suite Two Bedrooms DOUBLE OU TWIN  - VARANDA pool",
      "description": "77.0m²; bathroom shower bathtub hairdryer tv internet access kitchen utensils plates & cups kitchen tea and coffee making facilities washing machine ironing set individually adjustable air conditioning living room balcony terrace wheelchair accessible wi fi wake up service pillow menu bluetooth speaker alarm clock toiletries desk bathrobes slippers make up mirror smoking rooms dishwasher number of bedrooms housekeeping dining area clothes dryer private beach area electric kettle"
    }
  ]
}

One room response

Each mapped room echoes its identifiers and adds the mapping result: a canonical group, a quality range, a per-attribute dataset, flat attribute summaries, AI-ready room names per language and an overall score.

FieldTypeMeaning
hid, suppl, rcode1, rcode2stringEchoed identifiers for traceability.
name, descriptionstringEchoed input.
groupstringEquivalence key. Rooms that are the same physical product share it. Use it to match and dedupe across suppliers.
rangestringHuman-readable quality tier (e.g. "High-end family meal suite").
curatednumberCuration ratio 0–100: how much of the source text was confidently mapped.
datasetobjectStructured attributes keyed by code (TYP, AMN, BED…). See below.
BDR,TYP,VEW,BLC,BED,AMN,ADA,CAN,BRD,SMKstringFlat, readable summary per attribute family.
LangENLangDEstringAI-ready normalized room name in EN, ES, PT, FR, IT, DE.
scorenumberOverall room richness / match score.

Extra fields with a full credential

Beyond the fields above, a full credential also returns rate / amount, the price flags groupCheapest and rangeCheapest, the stable mapid keys, and leftover (source tokens that were not mapped, useful for QA and coverage).

Response
Loading…

The dataset object

Inside dataset, every attribute family is an object with the same shape. This is where the detail lives. Use class for a quick label, or walk map[] for per-item facts and translations.

KeyTypeMeaning
scorenumberConfidence / weight of this attribute for the room.
rangestring[]Raw tags detected for the attribute.
classstringReadable, comma-joined summary of the mapped items.
map[]object[]One entry per detected item (see below).

Inside map[]

KeyMeaning
type / catThe detected value and its category (e.g. pool / facility pool).
mapidStable identifier for this mapped concept (e.g. AMN341). Use it as a language-independent key.
indexCanonical display label.
inNametrue if it came from the room name (vs. the description).
langOutTranslations: EN, SP, PT, FR, IT, DE.
negativetrue when the feature is explicitly absent (e.g. "no pool").
Qty, grade, accessible, cancelable, smokingAttribute-specific extras when relevant.

Attribute reference

Attribute families you can expect in dataset and in the flat summaries. Not every family shows up for every room, only what the source text supports.

Room core

TYPType / classroom, suite, villa…
CATCategorystandard, deluxe, high-end
BDRBedrooms / roomscount of rooms
BEDBed setupking, twin or double…
PAXCapacityoccupancy, extra bed
SGLSingle usesingle occupancy
VEWView / orientationsea, overwater, city
BLCBalcony / patiobalcony, terrace
FLRFloorground, top floor

Amenities & board

AMNAmenities & facilitieswifi, pool, surface (m²)…
BRDBoard / meal planroom only, breakfast, AI
SHRShared facilitiesshared bath, dorm
ADAAccessibilitywheelchair, roll-in

Policies & commercial signals

REFRefundablerefundable / non-ref.
CANCancellationcancelable / not
DEPDepositrequired or not
SMKSmokingsmoking / non-smoking
MKGMarketing / SEO"stunning", "art deco"
CHAChain / brandHilton, Marriott…
MBRMembershipmember rate / type
PLAPlan & promoon sale, early bird

Mapping object

The mapping object holds the mapped rooms, grouped by supplier and then by hotel id. Each hotel id points to an array of its mapped rooms. Every room in that array is the structured room: raw supplier text turned into facts, with its group, range, curated coverage, per-attribute dataset, flat attribute summaries and AI-ready names in six languages.

FieldMeaning
hid, suppl, rcode1, rcode2Echoed identifiers for the room and its supplier.
nameRaw supplier room name, echoed.
groupCanonical equivalence label for the room.
rangeQuality tier for the room.
curatedCoverage ratio 0–100.
datasetPer-code attributes with map[], class, translations. See dataset.
CAT, BED, TYP, VEWFlat readable value per attribute family.
LangENLangDENormalized room name per language.
scoreOverall room score.
mapping
{
  "mapping": {
    "ean5": {
      "202113278": [ … ],  // 38 items
      "202113386": [ … ],  // 26 items
      "202113403": [ … ],  // 38 items
      "202113577": [ … ],  // 23 items
      "202114726": [ … ],  // 7 items
      "202115215": [ … ],  // 44 items
      "202115228": [  // 39 items
        {
          "hid": "202115228",
          "suppl": "ean5",
          "rcode1": "549",
          "rcode2": "1 King Bed-Classic Room-Room Only",
          "name": "1 King Bed Classic Room RO Room Only",
          "group": "Classic",
          "range": "Moderate",
          "curated": 100,
          "dataset": { … },  // 2 props
          "CAT": "classic",
          "BED": "king",
          "LangEN": "Classic, King.",
          "LangES": "Clásico, King.",
          "LangPT": "Clássico, King.",
          "LangFR": "Classique, King.",
          "LangIT": "Classico, King.",
          "LangDE": "Klassisch, King.",
          "score": 0
        }  // 38 more items
      ]
    }
  }
}

Matching object

The matching object is the index of equivalence groups. Each key is a canonical group label, and every room that maps to that group is filed under it. Use it to pull all rooms that are the same product, across suppliers and languages, in one lookup. The list is alphabetical and as wide as the rooms you sent.

FieldMeaning
keyCanonical group label. Same key means same room. Its precision is set by your grouping definition.
value { }The group bucket (one prop), holding the rooms filed under that group.

Match on the group key, not on supplier room codes. Codes drift, the group stays stable. See grouping & matching to tune how wide or narrow the groups are.

matching
{
  "matching": {  // one prop per group
    "2 bedrooms apartment": { … },
    "2 bedrooms apartment family": { … },
    "2 bedrooms apartment pool view": { … },
    "2 bedrooms apartment sea view": { … },
    "2 bedrooms apartment view": { … },
    "Accessible": { … },
    "Apartment": { … },
    "Apartment family": { … },
    "Apartment family pool view": { … },
    "Apartment pool view": { … },
    "Apartment sea view": { … },
    "Apartment single use": { … },
    "Apartment street": { … },
    "Apartment view": { … },
    "Balcony": { … },
    "Balcony double": { … },
    "Balcony double single use": { … },
    "Basic single": { … },
    "Bedroom": { … },
    "Business": { … },
    "City design single": { … },
    "City design triple": { … },
    "City view cool": { … },
    "Classic": { … },
    "Classic double": { … },
    "Classic double single use": { … },
    "Comfort": { … },
    "Comfort double": { … },
    "Comfort double single or double": { … },
    "Comfort family": { … },
    "Comfort single or double": { … },
    "Connected show view": { … },
    "Cool": { … },
    // … more groups, alphabetical
  }
}

Ranging object

The ranging object positions rooms along quality / value tiers, the "room range". It is an index keyed by range label (for example Moderate, Luxe, and their variants like Moderate family or Luxe with view). Each tier holds the rooms that fall into it, so you can order rooms from entry to premium, compare market ranges and drive upsell / downsell.

FieldMeaning
keyRange tier label. Broad tiers (Moderate, Luxe) plus refined variants built from the room attributes.
value { }The tier bucket, holding the rooms in that range. The prop count is how many rooms landed in it.

Use the range to widen a fallback: when an exact match is sold out, offer the closest room in the same tier.

ranging
{
  "ranging": {
    "Moderate with view": { … },  // 24 props
    "Moderate studio with view": { … },  // 1 prop
    "Moderate studio": { … },  // 1 prop
    "Moderate private vacation home": { … },  // 1 prop
    "Moderate park wing": { … },  // 1 prop
    "Moderate main building": { … },  // 1 prop
    "Moderate group capsules": { … },  // 1 prop
    "Moderate family with view": { … },  // 1 prop
    "Moderate family park wing": { … },  // 1 prop
    "Moderate family capsules": { … },  // 3 props
    "Moderate family": { … },  // 10 props
    "Moderate apartment": { … },  // 1 prop
    "Moderate": { … },  // 34 props
    "Luxe with view": { … },  // 17 props
    "Luxe villa": { … },  // 1 prop
    "Luxe studio": { … },  // 2 props
    "Luxe south wing": { … },  // 4 props
    "Luxe main building": { … },  // 1 prop
    "Luxe house": { … },  // 1 prop
    // … more ranges
  }
}

Scoring object

The scoring object is an index keyed by score value. Each key is a room score, and its bucket holds the groups that scored it. Drill into a score to see which groups sit there. Use it to rank and sort rooms by score, from 0 up to the richest matches.

FieldMeaning
keyRoom score. Higher means a richer, more complete match.
value { }The score bucket, keyed by group label, holding the groups that landed on that score. The prop count is how many.

Sort by the score key to order rooms by quality, and combine it with price before showing a cheaper room. See price optimization.

scoring
{
  "scoring": {
    "0": { … },  // 30 props
    "1": {
      "Studio standard": { … }  // 1 prop
    },
    "3": { … },  // 3 props
    "5": { … },  // 2 props
    "8": { … },  // 24 props
    "9": { … },  // 1 prop
    "11": { … },  // 2 props
    "12": { … },  // 1 prop
    "14": { … },  // 2 props
    "15": { … },  // 13 props
    "16": { … },  // 4 props
    "18": { … },  // 7 props
    "20": {
      "Deluxe view double": { … },  // 1 prop
      "Deluxe view": { … }  // 1 prop
    },
    "23": { … },  // 8 props
    "26": { … },  // 5 props
    "29": { … },  // 3 props
    "30": { … },  // 2 props
    "32": { … },  // 1 prop
    "35": { … },  // 1 prop
    "40": { … },  // 1 prop
    "50": { … }  // 2 props
  }
}

Leftover & unknown management

The engine never forces a bad match. Anything it can't map with confidence stays visible instead of being guessed, so you always know what was understood and what wasn't. Two fields tell you this: leftover and curated.

FieldMeaning
leftoverSource tokens from the name or description that were not mapped to any dictionary code. What the engine saw but did not claim.
curatedCoverage ratio 0–100. How much of the source text was confidently mapped. Read it next to leftover to judge a mapping.

An unknown value is kept in leftover, not squeezed into the wrong attribute. An explicit absence ("no pool") is mapped with negative:true, not dropped. Nothing is silently invented.

Unknown hotels and rooms are handled the same way: mapped on the fly from live supplier listings, with no pre-mapped cache, even for inventory you have never seen before.

leftover + curated
{
  "curated": 100,
  "leftover": "",
  // low curated + long leftover = something new to add
  "curated": 62,
  "leftover": "chimblick gaga nonsense"
}

Grouping & matching customization

The group value is the heart of the API: it's the key that decides which rooms are "the same room". Grouping is fully configurable. You choose which dictionary codes (the attribute codes: TYP, BED, VEW, AMN…) define a match. Two rooms land in the same group only when they agree on every code you put in the group definition. Fewer codes → broader groups; more codes → tighter, finer groups.

There are two main ways to group rooms correctly. Pick the one that matches what you're doing with the result, or keep one profile of each.

Method 1 · Detailed matching

Aggregate many dictionary codes into the group. You build the group key from a rich set of codes, so rooms only match when all of them are identical. This produces precise, narrow groups where every member really is the same physical product.

  • Strict, high-precision equivalence.
  • Best for exact deduplication, clean best-rate on identical rooms, and safe automatic rebooking.
  • The resulting group doubles as a stable room fingerprint.
Group definition · aggregate many codes
// same room only if ALL these codes match
group: [ "TYP", "BDR", "BED", "VEW", "BLC", "AMN" ]

// → "2 rooms suite overwater balcony twin or double"
//   matches only an identical room across suppliers

Method 2 · Generic group + filtering

Define the matching group with only the generic dictionary codes, then filter on the rest. You group on a few core codes to get broad buckets, then apply additional filtering on the other codes as a second pass to refine or select inside each bucket.

  • Broad, flexible buckets you can slice on demand.
  • Best for discovery, upsell / downsell across similar rooms, and market-range comparison.
  • One mapping pass serves many different filtered views.
Group definition · generic codes + filter
// broad bucket from generic codes only
group:  [ "TYP", "BED" ]

// then refine within the bucket on the other codes
filter: [ "VEW", "AMN", "CAN", "REF" ]

// → all "suite / twin or double" grouped together,
//   then filter to VEW=overwater, CAN=cancelable, …

Choosing an approach

Method 1 · DetailedMethod 2 · Generic + filter
Codes in the groupMany (core + amenities + policies)Few generic codes only
Group breadthNarrow, preciseBroad, then sliced
MatchingStrict, all codes must agreeLoose, refine with filters
Best forDedup, best-rate, auto-rebookingDiscovery, upsell, range comparison
Group stabilityHigh (good fingerprint)Depends on the filter you apply

Rule of thumb

Aggregate more codes when a wrong match is expensive (you're deduping money or rebooking a guest). Group on generic codes and filter when you want one broad catalog you can navigate many ways (discovery, upsell, analytics). Grouping and filter code sets are defined in your mapping profile.

Usage modes

The same mapping engine plugs in wherever your flow needs it, from a one-off backfill to live search-time calls. The mode you pick changes only when you map, not the response shape.

STATICStatic cachemap listings, feeds, logs, booking history
HYBRIDHybrid / deferredmap only new or changed room names
BATCHBatch / 24-hourbulk map on a schedule
LIVEReal-time on the flymap each availability response at search time

Real-time is the cache-free mode: because rooms are mapped from each live availability response, a label that has never been seen or has just changed is mapped instantly instead of being missed by a stale cache. Batch several rooms per hotel into one list to cut request overhead.

Optimizing mapping for rebooking

Rebooking breaks when supplier room codes and labels drift between the original booking and the recheck. Map on the identity that survives that drift.

Do this

  • Fingerprint by group, not by code. Supplier roomCode1/2 and even wording change over time; the group value stays stable for the same physical room. Store it at booking and re-match on it at recheck.
  • Re-map live on each availability response. Since there is no cache, a room whose label changed since booking still resolves to the same group, so no stale-cache misses.
  • Keep the mapid set as a secondary key. The list of mapids (e.g. TYP0, BED0, VEW0) is a language-independent signature; a high overlap confirms "same room" even across suppliers.
  • Fallback to equivalents when sold out. If the booked room is gone, query the same group across your other suppliers and offer the closest match; widen to the same range only if needed.
  • Trust inName for hard constraints. Attributes flagged inName:true are the room's headline promises (e.g. overwater, 2 rooms). Require them to match before you auto-rebook, and watch negative:true so you never swap in a room that dropped a promised feature.

Optimizing for price & margin

Grouping is what makes price comparison honest: you can only compare rates once you know two rooms are truly the same product. Feed prices in, and let the response point you at the best one.

Do this

  • Always send rate. Without a price the engine can group but can't rank. With it, you get the cheapest-in-group and cheapest-in-range signals.
  • Dedupe on group, keep the winner via groupCheapest. Collapse identical rooms sold by several suppliers into a single line and surface the lowest rate. Instant margin capture.
  • Upsell / downsell with rangeCheapest. Within a quality range (e.g. "High-end … suite"), find the cheapest comparable option to move guests up or down a tier without breaking expectations.
  • Guard quality with score and negative. Before showing a cheaper room, confirm its score is close and no high-value AMN/VEW attribute is missing or flagged negative:true. Cheap-but-worse is not a win.
  • Read leftover for hidden value. A rich room with lots of unmapped leftover text may be under-priced for what it actually offers. That's a repricing or upsell opportunity.
  • Compare wide. Map the same room across as many sources as possible in one list batch; the more suppliers in a group, the better your best-rate and margin decision.

Errors & limits

A successful call returns 200 with a JSON body. Any non-2xx status means the request was not mapped. Check your credential, body format and volume tier before retrying.

SituationWhat to check
Non-2xx responseBody must be valid JSON sent as text/plain; credential present and active.
Empty / thin resultAdd description, most attributes come from it. Check curated and leftover for coverage.
Rate limitedYou may be over your monthly volume tier. Batch rooms per hotel into one list call to reduce request count.

Volume is billed per mapped room per month. Batching many rooms in a single list does not change what you're billed for the mappings, but it cuts request overhead and latency.

Code samples

Same call, common stacks. Body is a JSON string over text/plain; enable gzip where your client supports it.

const body = JSON.stringify({
  credential: "mycredential",
  list: [{ hid: "79683", supplier: "OTA", rate: 354,
    name: "overwater suite Two Bedrooms DOUBLE OU TWIN - VARANDA pool" }]
});
const res = await fetch("https://travelmap.tech/map/room", {
  method: "POST",
  headers: { "Content-Type": "text/plain" },
  body
});
const mapped = await res.json();
console.log(mapped.group, mapped.LangEN, mapped.score);