{"info":{"_postman_id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","name":"Global Airport Concierge API v1","description":"<html><head></head><body><p>The <strong>Global Airport Concierge API v1</strong> lets a partner price and book airport concierge services: Meet &amp; Assist, Porter, Lounge Access and more, at over 500 airports.</p>\n<p><strong>Base URL:</strong> <code>https://api-prod.globalairportconcierge.com/api/v1</code></p>\n<p><strong>Published documentation:</strong> <a href=\"https://api-docs.globalairportconcierge.com\">https://api-docs.globalairportconcierge.com</a></p>\n<p>GAC issues your credentials, and a sandbox base URL if you want one, when your integration is set up. In Postman every request reads the host from the <code>base_url</code> variable, so pick an environment before you send anything.</p>\n<h2 id=\"getting-started\">Getting started</h2>\n<ol>\n<li><strong>01 Get access token</strong> — exchange your <code>client_id</code> and <code>client_secret</code> for a bearer token. Send it as <code>Authorization: Bearer …</code> on everything else. Tokens last a year, so cache it.</li>\n<li><strong>02 List services at an airport</strong> — find out what is available and at what rate.</li>\n<li><strong>03 Create quote</strong> — send the itinerary and get a price back. The booking is created in status <code>quote</code>.</li>\n<li><strong>06 Confirm quote</strong> — commit it. Status becomes <code>booking</code> and the customer is emailed.</li>\n<li><strong>09 / 10 / 11</strong> — read it back later, by our id, our reference, or your own.</li>\n</ol>\n<p>Requests are numbered in the order you would normally call them.</p>\n<h2 id=\"booking-lifecycle\">Booking lifecycle</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>         03 Create quote\n               |\n            [quote]  --- 04 Replace / 05 Reprice ---&gt; [quote]\n               |\n         06 Confirm quote\n               |\n           [booking]\n               |\n         07 Cancel booking\n               |\n          [cancelled]\n</code></pre><p><code>cancelled</code> is terminal. Every other endpoint refuses a cancelled booking.</p>\n<p>A quote is valid for <strong>one week</strong>. After that, reprice it before confirming.</p>\n<h2 id=\"response-envelope\">Response envelope</h2>\n<p>Every endpoint except <strong>01 Get access token</strong> wraps its payload:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{ \"message\": \"…\", \"status\": 200, \"responseTime\": \"125ms\", \"trace\": [], \"data\": { } }\n</code></pre>\n<p>List endpoints add a <code>pagination</code> block and put an array in <code>data</code>:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">\"pagination\": { \"total_count\": 7, \"total_pages\": 4, \"current_page\": 1, \"limit\": 2 }\n</code></pre>\n<h2 id=\"errors\">Errors</h2>\n<p>Every error carries an <code>error_code</code>. <strong>Branch on <code>error_code</code>, not on the message.</strong> The code is a contract; the wording is ours to improve.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"message\": \"No booking found with id 99999999. It may not exist, or it may belong to another company.\",\n  \"status\": 404,\n  \"responseTime\": \"22ms\",\n  \"error_code\": \"booking_not_found\",\n  \"data\": { \"errors\": [] }\n}\n</code></pre>\n<p>Validation failures add a top-level <code>errors</code> object keyed by field, and report <strong>every</strong> problem at once rather than stopping at the first:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"message\": \"The currency field is required. (and 2 more errors)\",\n  \"status\": 422,\n  \"error_code\": \"validation_failed\",\n  \"errors\": {\n    \"currency\": [\"The currency field is required.\"],\n    \"journeys\": [\"At least one journey is required.\"]\n  },\n  \"data\": []\n}\n</code></pre>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th><code>error_code</code></th>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>validation_failed</code></td>\n<td>422</td>\n<td>Your payload is wrong. <code>errors</code> says exactly where. Fix and resend.</td>\n</tr>\n<tr>\n<td><code>invalid_client_credentials</code></td>\n<td>401</td>\n<td><code>client_id</code> or <code>client_secret</code> was rejected at <strong>01 Get access token</strong>.</td>\n</tr>\n<tr>\n<td><code>unauthenticated</code></td>\n<td>401</td>\n<td>Bearer token missing, invalid or expired. Get a new one.</td>\n</tr>\n<tr>\n<td><code>forbidden</code></td>\n<td>403</td>\n<td>Your client is not allowed to do this.</td>\n</tr>\n<tr>\n<td><code>invoice_terms_required</code></td>\n<td>403</td>\n<td>Your company is not set up for invoice payments, so bookings cannot be confirmed.</td>\n</tr>\n<tr>\n<td><code>booking_not_found</code></td>\n<td>404</td>\n<td>No booking with that id or reference, or it belongs to another company. The two are deliberately indistinguishable.</td>\n</tr>\n<tr>\n<td><code>agent_not_found</code></td>\n<td>404</td>\n<td>No agent with that id or reference on your account.</td>\n</tr>\n<tr>\n<td><code>endpoint_not_found</code></td>\n<td>404</td>\n<td>No such endpoint. Check the method and path.</td>\n</tr>\n<tr>\n<td><code>method_not_allowed</code></td>\n<td>405</td>\n<td>Wrong HTTP method for that path.</td>\n</tr>\n<tr>\n<td><code>booking_cancelled</code></td>\n<td>409</td>\n<td>The booking is cancelled and cannot be changed. Terminal, do not retry.</td>\n</tr>\n<tr>\n<td><code>booking_already_confirmed</code></td>\n<td>409</td>\n<td>Already confirmed. Read it back rather than confirming again.</td>\n</tr>\n<tr>\n<td><code>quote_expired</code></td>\n<td>409</td>\n<td>Reprice with <strong>05 Reprice quote</strong>, then confirm.</td>\n</tr>\n<tr>\n<td><code>payment_incomplete</code></td>\n<td>409</td>\n<td>Payment has not settled yet. Retry later.</td>\n</tr>\n<tr>\n<td><code>booking_not_confirmable</code></td>\n<td>409</td>\n<td>The booking's state blocks confirmation. Read it back to see why.</td>\n</tr>\n<tr>\n<td><code>booking_total_too_low</code></td>\n<td>422</td>\n<td>No chargeable total. Check a service is attached and priced.</td>\n</tr>\n<tr>\n<td><code>rate_limit_exceeded</code></td>\n<td>429</td>\n<td>Too many requests. Back off for the number of seconds in <code>Retry-After</code>.</td>\n</tr>\n<tr>\n<td><code>server_error</code></td>\n<td>500</td>\n<td>Our fault. Nothing was changed. The message carries a reference to quote to GAC support.</td>\n</tr>\n</tbody>\n</table>\n</div><p>A <code>4xx</code> other than <code>429</code> will not succeed on retry without a change on your side. <code>429</code> and <code>500</code> are the only ones worth retrying as-is.</p>\n<h2 id=\"what-you-can-book\">What you can book</h2>\n<p>Nine services are bookable. Seven are priced from the journey's passenger and bag counts alone; Car Transfer and Airport By Invitation take extra inputs through <code>service_options</code>. <strong>03 Create quote</strong> carries the full table, the service ids, how many airports hold rates for each, and a worked example of every one.</p>\n<p>Two things worth knowing before you plan an integration:</p>\n<ul>\n<li><strong>02 List services at an airport</strong> returns only Meet &amp; Assist, Porter and Lounge Access. The other six are bookable but not discoverable, so take their ids from <strong>03 Create quote</strong> and ask GAC which airports carry them.</li>\n<li><strong>Car Transfer has no rates loaded yet.</strong> It books, and returns a line worth <code>0</code>. Do not sell it without talking to GAC first.</li>\n</ul>\n<p>Services can also be sold as a named package at a discount. Bundles apply automatically when a booking carries every member service on the same stop, so there is nothing extra to send. See <strong>02b List service bundles</strong>.</p>\n<h2 id=\"rate-limiting\">Rate limiting</h2>\n<p>300 requests per minute, counted <strong>per API key</strong>, so nobody else's traffic eats your budget and yours does not eat theirs.</p>\n<p>Every response carries <code>X-RateLimit-Limit</code> and <code>X-RateLimit-Remaining</code>, so you can pace yourself before you run out. Go over and you get <code>429 rate_limit_exceeded</code> with a <code>Retry-After</code> header giving the seconds to wait. Honour it rather than retrying immediately.</p>\n<p>If you expect sustained volume above this, talk to GAC before you go live rather than discovering the ceiling in production.</p>\n<h2 id=\"your-agents\">Your agents</h2>\n<p>If several people book on your account, each needs an agent record, because <strong>03 Create quote</strong> refuses a <code>booker_id</code> that is not one of yours. That is what attributes a booking to the person who made it and puts the right name on the confirmation email.</p>\n<p>You create and remove them yourself through <strong>13 Manage your agents</strong>. They are booking records rather than logins: your own system signs the agent in at your end and tells us who it was.</p>\n<h2 id=\"known-quirks\">Known quirks</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Behaviour</th>\n<th>What to do</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>confirm: true</code> on <strong>03 Create quote</strong> does not confirm anything. The booking stays a <code>quote</code> and no error is returned.</td>\n<td>Call <strong>06 Confirm quote</strong> explicitly.</td>\n</tr>\n<tr>\n<td><strong>04 Replace quote</strong> is a full replace. It regenerates <code>ref_no</code>, resets <code>status</code> to <code>quote</code>, clears <code>billing.status</code> and resets <code>expires_on</code>.</td>\n<td>Echo the existing <code>ref_no</code> back, and never replace a confirmed booking unless you mean to un-confirm it.</td>\n</tr>\n<tr>\n<td><code>trace</code> is always <code>[]</code> on success, and <strong>08 List bookings</strong> omits the key entirely.</td>\n<td>Ignore it.</td>\n</tr>\n<tr>\n<td>Quote validity is one week, not the four hours some older documentation implies.</td>\n<td>Trust <code>expires_on</code>.</td>\n</tr>\n<tr>\n<td><code>X-Tenant-ID</code> is fixed server-side.</td>\n<td>Do not send it.</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"staying-in-sync\">Staying in sync</h2>\n<p>You do not have to poll. Two mechanisms, and most integrations want both:</p>\n<ul>\n<li><strong>Webhooks.</strong> We POST the booking to a URL of yours whenever it is confirmed, amended or cancelled, when a greeter is assigned, and when the service is delivered, missed or fails. That includes changes made by GAC operations, which you would otherwise never see. Ask GAC to set one up; there is no self-serve registration. See <strong>12 Webhooks (we call you)</strong>.</li>\n<li><strong><code>updated_since</code> on 08 List bookings.</strong> Pull everything that changed since a timestamp. This is the recovery path when your endpoint has been down, and the belt-and-braces option if you would rather reconcile on a schedule.</li>\n</ul>\n<h2 id=\"not-available-yet\">Not available yet</h2>\n<ul>\n<li><strong>No idempotency key.</strong> A retried create makes a second booking. Send a unique <code>settings.customer_reference</code> every time and use it to detect and recover from duplicates; see <strong>03 Create quote</strong>.</li>\n<li><strong>No created-date filter</strong> on <strong>08 List bookings</strong>. <code>updated_since</code> covers changes, but there is no way to ask for bookings made between two dates.</li>\n</ul>\n<p>Last reviewed against the live API: 2026-09-09. Every example in this collection is a real captured response, including the error ones. The one exception is the sample body in <strong>12.1</strong>, where the passenger and greeter details are placeholders because that collection is shared and a real payload names a customer and an assigned greeter.</p>\n</body></html>","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json","toc":[],"owner":"771129","collectionId":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","publishedId":"2sAYJ4jMHi","public":true,"customColor":{"top-bar":"FFFFFF","right-sidebar":"e6e7e8","highlight":"70c5bc"},"publishDate":"2026-08-24T22:45:59.000Z"},"item":[{"name":"12 Webhooks (we call you)","item":[{"name":"12.1 Send a test delivery to your endpoint","event":[{"script":{"type":"text/javascript","exec":["// Signs the body the same way the GAC sender does, so this request exercises your","// real verification path rather than a stub.","const secret = pm.variables.get('webhook_secret');","","if (!secret || secret === 'ASK_GAC_FOR_YOUR_SIGNING_SECRET') {","    throw new Error('Set webhook_secret to the signing secret GAC gave you.');","}","","const timestamp = Math.floor(Date.now() / 1000);","","// Sign the body exactly as it goes on the wire, after variable substitution.","// Hashing anything else is the single most common reason a receiver rejects us.","const body = pm.variables.replaceIn(pm.request.body.raw);","","const signature = CryptoJS","    .HmacSHA256(timestamp + '.' + body, secret)","    .toString(CryptoJS.enc.Hex);","","pm.variables.set('gac_ts', String(timestamp));","pm.variables.set('gac_sig', 'sha256=' + signature);"]},"listen":"prerequest"}],"id":"84f6b9a9-9f2e-1b2c-1062-c7651c85b142","request":{"auth":{"type":"noauth","isInherited":false},"method":"POST","header":[{"description":"<p>Always sent as JSON.</p>\n","key":"Content-Type","value":"application/json"},{"description":"<p>Which event this delivery is.</p>\n","key":"X-GAC-Event","value":"booking.confirmed"},{"description":"<p>Unique per delivery. Store it to detect a repeat.</p>\n","key":"X-GAC-Delivery","value":"8c1f5e2a-6b04-4a6d-9d21-0f5f4c3a7b19"},{"description":"<p>Unix seconds. Set by the pre-request script. Reject anything more than a few minutes old.</p>\n","key":"X-GAC-Timestamp","value":"{{gac_ts}}"},{"description":"<p>sha256=hex(hmac_sha256(secret, timestamp + '.' + raw_body)). Set by the pre-request script.</p>\n","key":"X-GAC-Signature","value":"{{gac_sig}}"}],"body":{"mode":"raw","raw":"{\"event\":\"booking.confirmed\",\"occurred_at\":\"2026-09-08T20:46:13+00:00\",\"data\":{\"id\":43182,\"expires_on\":\"2026-09-11T21:29:05+00:00\",\"ref_no\":\"GAC-6A9B37AAC935A\",\"status\":\"booking\",\"currency\":{\"id\":3,\"symbol\":\"£\",\"name\":\"British Pound Sterling\",\"symbol_native\":\"£\",\"decimal_digits\":2,\"rounding\":0,\"code\":\"GBP\",\"name_plural\":\"British pounds sterling\",\"multiplier\":0.75},\"journeys\":[{\"flight\":\"KU102\",\"adult\":2,\"child\":0,\"infant\":0,\"bag_small\":0,\"bag_medium\":0,\"bag_large\":0,\"passengers\":{\"adult\":[{\"type\":\"adult\",\"lead\":true,\"pnr\":\"NOPNR\",\"signage\":\"Lead Passenger\",\"class_type\":\"Business Class\",\"title\":\"\",\"first_name\":\"Lead\",\"last_name\":\"Passenger\",\"contacts\":[]},{\"type\":\"adult\",\"lead\":false,\"pnr\":\"NOPNR\",\"signage\":\"Second Passenger\",\"class_type\":\"Business Class\",\"title\":\"\",\"first_name\":\"Second\",\"last_name\":\"Passenger\",\"contacts\":[]}],\"child\":[],\"infant\":[]},\"stops\":{\"arrival\":{\"airport\":{\"id\":14,\"name\":\"KWI Kuwait International Airport\",\"iata\":\"KWI\"},\"services\":[],\"airport_id\":14},\"departure\":{\"airport\":{\"id\":2,\"name\":\"LHR London Heathrow Airport\",\"iata\":\"LHR\"},\"services\":[{\"id\":1,\"value\":110,\"surcharge\":0,\"service_name\":\"Meet & Assist\",\"allocation\":{\"greeter\":{\"id\":33746,\"name\":{\"title\":\"Mr.\",\"forename\":\"Assigned\",\"surname\":\"Greeter\"},\"email\":\"greeter@example.com\",\"contacts\":[{\"type\":\"phone\",\"value\":\"+440000000000\"}],\"assigned_date\":\"2026-09-04T21:34:08.000000Z\"}}}],\"airport_id\":2}}}],\"billing\":{\"status\":0,\"total_discount\":0,\"add_hrs_charge\":0,\"surcharge\":0,\"total_booking_cost\":110,\"grand_total\":110,\"total_paid\":\"0.00\",\"total_refund_amount\":0,\"tax\":0,\"tax_rate\":0},\"settings\":{\"no_surcharge\":true,\"no_additional_hour_charges\":true,\"customer_reference\":null},\"promo_code\":null,\"created_at\":\"2026-09-04T21:27:06+00:00\",\"currency_id\":3,\"booker_id\":19558}}","options":{"raw":{"language":"json"}}},"url":"http://localhost:3000/hooks/gac","description":"<p>Pretends to be us, so you can test your receiver before we send you anything real.</p>\n<p>Set two variables, then hit Send:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Variable</th>\n<th>What to put in it</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>webhook_test_url</code></td>\n<td>Your receiver, for example <code>http://localhost:3000/hooks/gac</code></td>\n</tr>\n<tr>\n<td><code>webhook_secret</code></td>\n<td>The signing secret GAC gave you</td>\n</tr>\n</tbody>\n</table>\n</div><p>The pre-request script signs the body exactly the way our sender does, using the current time, so a correct implementation of the verification in the folder documentation will accept it and a broken one will not. Change a single character of the body and it should start failing: that is the check worth running.</p>\n<h3 id=\"what-to-assert-in-your-handler\">What to assert in your handler</h3>\n<ol>\n<li>The signature verifies.</li>\n<li>You return a <code>2xx</code> in well under 10 seconds.</li>\n<li>Sending the same body twice results in <strong>one</strong> state change, not two. Deliveries are at-least-once.</li>\n<li>An old <code>X-GAC-Timestamp</code> is rejected. Edit the script to subtract an hour and confirm your handler refuses it.</li>\n</ol>\n<h3 id=\"about-this-body\">About this body</h3>\n<p>The structure, field names and amounts are a real captured <code>booking.confirmed</code> payload. <strong>The passenger and greeter details are placeholders</strong>, because a real one carries a customer's name and an assigned greeter's mobile number and this collection is shared. Everything a parser cares about is verbatim.</p>\n<p>Note the shape of <code>journeys[].stops</code>: it is an <strong>object</strong> with <code>arrival</code> and <code>departure</code> keys, either of which may be <code>null</code>, not an array. Services hang off each stop, so a booking with services only on departure has <code>stops.arrival.services</code> empty, as here.</p>\n","urlObject":{"host":["http://localhost:3000/hooks/gac"],"query":[],"variable":[]}},"response":[],"_postman_id":"84f6b9a9-9f2e-1b2c-1062-c7651c85b142"}],"id":"2bace676-5e03-f90f-9836-67100c196ac7","description":"<p>Every other request in this collection is you calling us. This one is us calling you.</p>\n<p>When a booking of yours changes, or something happens to it on the day, we POST it to a URL you give us, so you do not have to poll. This matters most for the things <strong>you did not do</strong>: GAC operations amend a meeting point, a supplier cannot cover a booking, or the passenger does not turn up. Until now the only way to learn about any of that was to page your whole booking history, and some of it was never visible at all.</p>\n<h2 id=\"getting-set-up\">Getting set up</h2>\n<p>There is no self-serve registration endpoint. Ask GAC for a webhook endpoint and give us:</p>\n<ul>\n<li>the <strong>URL</strong> to POST to (must be <code>https</code>, since the payload carries passenger names, flight numbers and contact details)</li>\n<li>which <strong>events</strong> you want</li>\n</ul>\n<p>We give you back a <strong>signing secret</strong>. Keep it somewhere you keep secrets; it is the only thing that proves a delivery came from us.</p>\n<p>You can have more than one endpoint, and each subscribes to its own set of events. A staging endpoint that only wants cancellations is a perfectly normal setup.</p>\n<h2 id=\"events\">Events</h2>\n<h3 id=\"about-the-booking\">About the booking</h3>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Event</th>\n<th>Fires when</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>booking.confirmed</code></td>\n<td>A quote becomes a confirmed booking. Whoever confirmed it, you or GAC.</td>\n</tr>\n<tr>\n<td><code>booking.cancelled</code></td>\n<td>The booking is cancelled. Includes cancellations made by GAC operations.</td>\n</tr>\n<tr>\n<td><code>booking.updated</code></td>\n<td>An existing booking is amended without its status changing. Includes amendments made by GAC operations.</td>\n</tr>\n</tbody>\n</table>\n</div><p>Creating a quote fires nothing. You made it, so you already know.</p>\n<h3 id=\"about-the-service-on-the-day\">About the service on the day</h3>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Event</th>\n<th>Fires when</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>booking.greeter_assigned</code></td>\n<td>A greeter is named for a leg. Their name and contact details are already in the payload, so this is the moment you can tell the passenger who is meeting them.</td>\n</tr>\n<tr>\n<td><code>booking.service_completed</code></td>\n<td>Operations mark the service delivered.</td>\n</tr>\n<tr>\n<td><code>booking.service_no_show</code></td>\n<td>The passenger did not turn up.</td>\n</tr>\n<tr>\n<td><code>booking.service_failed</code></td>\n<td>The service could not be delivered. <strong>Subscribe to this one.</strong> It is the one your customer will contact you about.</td>\n</tr>\n</tbody>\n</table>\n</div><p>These four are about a single leg rather than the whole booking, so they carry a <code>context</code> block. See below.</p>\n<p>Assignment only fires when a greeter is first named. Operations write allocation progress repeatedly as each service on a leg is covered, and you are not told again each time.</p>\n<h2 id=\"what-we-send\">What we send</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>POST https://your-endpoint.example.com/hooks/gac\nContent-Type: application/json\nX-GAC-Event: booking.confirmed\nX-GAC-Delivery: 8c1f5e2a-6b04-4a6d-9d21-0f5f4c3a7b19\nX-GAC-Timestamp: 1788000000\nX-GAC-Signature: sha256=6b8f...\n</code></pre><pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"event\": \"booking.confirmed\",\n  \"occurred_at\": \"2026-09-08T20:31:07+00:00\",\n  \"data\": { }\n}\n</code></pre>\n<p><code>data</code> is <strong>byte-identical to the body of 09 Get booking by ID</strong>. It is built by the same code, so it cannot drift from what that endpoint returns. If your integration already parses a booking, it already parses this.</p>\n<h3 id=\"the-context-block\">The context block</h3>\n<p>The four service events add one, naming the leg they are about:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"event\": \"booking.greeter_assigned\",\n  \"occurred_at\": \"2026-09-08T20:31:07+00:00\",\n  \"context\": {\n    \"stop_type\": \"arrival\",\n    \"airport\": \"LHR\",\n    \"service_date\": \"2026-09-22T14:30:00+00:00\"\n  },\n  \"data\": { }\n}\n</code></pre>\n<p>A booking has up to two legs and the payload alone cannot tell you which one a greeter was assigned to. <code>context</code> is <strong>absent</strong>, not null, on the three booking events, so its presence is the signal that this is about one leg.</p>\n<h3 id=\"confirming-it-afterwards\">Confirming it afterwards</h3>\n<p>Each stop in the payload carries <code>service_status</code>, which is also on every read of the booking:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th><code>service_status</code></th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>scheduled</code></td>\n<td>Nothing has happened yet</td>\n</tr>\n<tr>\n<td><code>completed</code></td>\n<td>Delivered</td>\n</tr>\n<tr>\n<td><code>cancelled</code></td>\n<td>Called off</td>\n</tr>\n<tr>\n<td><code>no_show</code></td>\n<td>Passenger did not turn up</td>\n</tr>\n<tr>\n<td><code>failed</code></td>\n<td>Could not be delivered</td>\n</tr>\n</tbody>\n</table>\n</div><p>So a <code>booking.service_failed</code> webhook is verifiable at any later point through <strong>09 Get booking by ID</strong>, rather than being something you had to catch in the moment.</p>\n<h2 id=\"verifying-the-signature\">Verifying the signature</h2>\n<p>Recompute the HMAC over the timestamp, a dot, and the <strong>raw request body</strong>, keyed with your signing secret:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>signature = \"sha256=\" + hex(hmac_sha256(secret, timestamp + \".\" + raw_body))\n</code></pre><p>Node:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-js\">const crypto = require('crypto');\n\nfunction verify(rawBody, headers, secret) {\n  const timestamp = headers['x-gac-timestamp'];\n  const expected = 'sha256=' + crypto\n    .createHmac('sha256', secret)\n    .update(`${timestamp}.${rawBody}`)\n    .digest('hex');\n\n  // Constant-time, so a wrong signature cannot be guessed a byte at a time.\n  return crypto.timingSafeEqual(\n    Buffer.from(expected),\n    Buffer.from(headers['x-gac-signature']),\n  );\n}\n</code></pre>\n<p>PHP:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-php\">$expected = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $rawBody, $secret);\n\nif (!hash_equals($expected, $signature)) {\n    abort(400);\n}\n</code></pre>\n<p>Three things to get right:</p>\n<ol>\n<li><strong>Hash the raw body</strong>, before any JSON parse and re-encode. Re-serialising changes whitespace and key order, and the signature will not match.</li>\n<li><strong>Compare in constant time.</strong> <code>hash_equals</code> in PHP, <code>crypto.timingSafeEqual</code> in Node.</li>\n<li><strong>Reject an old timestamp.</strong> The timestamp is inside the signed string precisely so a captured delivery cannot be replayed at us later. Five minutes of tolerance is a reasonable window.</li>\n</ol>\n<h2 id=\"responding\">Responding</h2>\n<p>Return any <code>2xx</code> and we consider it delivered. Anything else, or no response at all, counts as a failure.</p>\n<p><strong>Acknowledge first, work afterwards.</strong> We wait 10 seconds and no longer. Write the payload to your own queue, return <code>200</code>, and do the real work outside the request.</p>\n<h2 id=\"retries\">Retries</h2>\n<p>Five attempts, backing off roughly: immediately, then after 1 minute, 5 minutes, 15 minutes, and 1 hour. After that we stop and the delivery is marked failed.</p>\n<p>A GAC staff member can replay any delivery by hand from the admin console. A replay is rebuilt from the booking <strong>as it stands at that moment</strong>, not as it stood when the original fired, which is what you want when catching up after an outage.</p>\n<p>Two consequences worth designing for:</p>\n<ul>\n<li><strong>Deliveries are at-least-once, not exactly-once.</strong> A timeout on your side that we read as a failure, followed by a retry, means you see the same event twice. <code>X-GAC-Delivery</code> is unique per attempt-set; store it and ignore repeats. Or just make your handler idempotent, which is less work.</li>\n<li><strong>Order is not guaranteed.</strong> A retried <code>booking.updated</code> can land after the <code>booking.cancelled</code> that followed it. Treat the payload as the current state, not as a delta, and where it matters compare <code>data.updated_at</code> before overwriting what you hold.</li>\n</ul>\n<h2 id=\"if-your-endpoint-is-down\">If your endpoint is down</h2>\n<p>Nothing is lost from your side: the booking is still there. Once you are back, use <code>updated_since</code> on <strong>08 List bookings</strong> to pull everything that changed while you were away, then carry on with webhooks. That is the intended recovery path, and it is why that filter exists. <code>service_status</code> on each stop means the day-of outcomes are recoverable that way too.</p>\n<h2 id=\"testing-your-receiver\">Testing your receiver</h2>\n<p>The request in this folder POSTs a real webhook body at a URL of your choosing, with the real headers, so you can point it at your development server and check your handler and your signature verification before we send you anything.</p>\n","_postman_id":"2bace676-5e03-f90f-9836-67100c196ac7","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{token}}"}]},"isInherited":true,"source":{"_postman_id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","name":"Global Airport Concierge API v1","type":"collection"}}},{"name":"01 Get access token","event":[{"listen":"test","script":{"id":"ca1763cf-8acb-41fb-b4ad-6fea3d4b3fa6","exec":["pm.environment.set(\"token\", pm.response.json().access_token);"],"type":"text/javascript","packages":{},"requests":{}}}],"id":"b4518fd2-95d9-44a9-be55-32e1e488a8fc","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"auth":{"type":"noauth","isInherited":false},"method":"POST","header":[],"body":{"mode":"formdata","formdata":[{"key":"client_id","value":"{{client_id}}","type":"text"},{"key":"client_secret","value":"{{secret}}","type":"text"}]},"url":"https://api-prod.globalairportconcierge.com/api/v1/auth","description":"<p>Exchanges your OAuth client credentials for a bearer token. Every other request in this collection needs it.</p>\n<p><code>grant_type</code> is forced to <code>client_credentials</code> server-side, so you never send it, and no refresh token is issued. Ask for a new token when the old one expires.</p>\n<p><strong>Request</strong> — send <code>client_id</code> and <code>client_secret</code>. Form encoding, JSON and query parameters all work.</p>\n<p><strong>Response</strong> — this endpoint is the one exception to the standard envelope. It returns the raw OAuth payload with no <code>message</code> / <code>status</code> / <code>responseTime</code> wrapper:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{ \"token_type\": \"Bearer\", \"expires_in\": 31536000, \"access_token\": \"eyJ0eXAi…\" }\n</code></pre>\n<p>Send it on every subsequent call as <code>Authorization: Bearer &lt;access_token&gt;</code>. The collection does this for you via the <code>{{token}}</code> variable, which the test script on this request sets automatically.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th><code>error_code</code></th>\n<th>When</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>200</code></td>\n<td>—</td>\n<td>Credentials accepted. Raw OAuth payload, no envelope.</td>\n</tr>\n<tr>\n<td><code>401</code></td>\n<td><code>invalid_client_credentials</code></td>\n<td><code>client_id</code> or <code>client_secret</code> rejected, client revoked, or client not linked to a company.</td>\n</tr>\n<tr>\n<td><code>429</code></td>\n<td><code>rate_limit_exceeded</code></td>\n<td>More than 300 requests in a minute.</td>\n</tr>\n<tr>\n<td><code>500</code></td>\n<td><code>server_error</code></td>\n<td>Our fault. The message carries a reference to quote to support.</td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>Token lifetime is one year</strong> (<code>expires_in: 31536000</code>). Every call mints an additional token and revokes nothing, so cache the token rather than requesting one per API call.</p>\n","urlObject":{"path":["auth"],"host":["https://api-prod.globalairportconcierge.com/api/v1"],"query":[],"variable":[]}},"response":[{"id":"a62bec81-c1a4-4638-b271-de0c7d96deb6","name":"Error","originalRequest":{"method":"POST","header":[],"body":{"mode":"formdata","formdata":[{"key":"client_id","value":"sample","description":"Client ID","type":"text"},{"key":"client_secret","value":"{{secret}}","description":"Client Secret","type":"text"}]},"url":"https://api-prod.globalairportconcierge.com/api/v1/auth"},"status":"Unauthorized","code":401,"_postman_previewlanguage":"json","header":[{"key":"Server","value":"nginx/1.27.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"X-Powered-By","value":"PHP/8.3.13"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Thu, 26 Dec 2024 02:33:00 GMT"},{"key":"Access-Control-Allow-Origin","value":"*"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Client authentication failed\",\n    \"status\": 401,\n    \"trace\": [],\n    \"responseTime\": \"252ms\",\n    \"data\": {\n        \"errors\": []\n    }\n}"},{"id":"2428d123-1c52-9a9e-4bc3-c098ad1b8b14","name":"200 Token issued","originalRequest":{"auth":{"type":"noauth"},"method":"POST","header":[],"body":{"mode":"formdata","formdata":[{"key":"client_id","value":"{{client_id}}","type":"text"},{"key":"client_secret","value":"{{secret}}","type":"text"}]},"url":"https://api-prod.globalairportconcierge.com/api/v1/auth","description":"Exchanges your OAuth client credentials for a bearer token. Every other request in this collection needs it.\n\n`grant_type` is forced to `client_credentials` server-side, so you never send it, and no refresh token is issued. Ask for a new token when the old one expires.\n\n**Request** — send `client_id` and `client_secret`. Form encoding, JSON and query parameters all work.\n\n**Response** — this endpoint is the one exception to the standard envelope. It returns the raw OAuth payload with no `message` / `status` / `responseTime` wrapper:\n\n```json\n{ \"token_type\": \"Bearer\", \"expires_in\": 31536000, \"access_token\": \"eyJ0eXAi…\" }\n```\n\nSend it on every subsequent call as `Authorization: Bearer <access_token>`. The collection does this for you via the `{{token}}` variable, which the test script on this request sets automatically.\n\n| Status | `error_code` | When |\n| --- | --- | --- |\n| `200` | — | Credentials accepted. Raw OAuth payload, no envelope. |\n| `401` | `invalid_client_credentials` | `client_id` or `client_secret` rejected, client revoked, or client not linked to a company. |\n| `429` | `rate_limit_exceeded` | More than 300 requests in a minute. |\n| `500` | `server_error` | Our fault. The message carries a reference to quote to support. |\n\n**Token lifetime is one year** (`expires_in: 31536000`). Every call mints an additional token and revokes nothing, so cache the token rather than requesting one per API call."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"token_type\": \"Bearer\",\n    \"expires_in\": 31536000,\n    \"access_token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjhmM2E...\"\n}"},{"id":"50b9e1fe-d817-1f78-527f-93fecdab48e1","name":"401 Credentials not accepted","originalRequest":{"auth":{"type":"noauth"},"method":"POST","header":[],"body":{"mode":"formdata","formdata":[{"key":"client_id","value":"{{client_id}}","type":"text"},{"key":"client_secret","value":"{{secret}}","type":"text"}]},"url":"https://api-prod.globalairportconcierge.com/api/v1/auth","description":"Exchanges your OAuth client credentials for a bearer token. Every other request in this collection needs it.\n\n`grant_type` is forced to `client_credentials` server-side, so you never send it, and no refresh token is issued. Ask for a new token when the old one expires.\n\n**Request** — send `client_id` and `client_secret`. Form encoding, JSON and query parameters all work.\n\n**Response** — this endpoint is the one exception to the standard envelope. It returns the raw OAuth payload with no `message` / `status` / `responseTime` wrapper:\n\n```json\n{ \"token_type\": \"Bearer\", \"expires_in\": 31536000, \"access_token\": \"eyJ0eXAi…\" }\n```\n\nSend it on every subsequent call as `Authorization: Bearer <access_token>`. The collection does this for you via the `{{token}}` variable, which the test script on this request sets automatically.\n\n| Status | `error_code` | When |\n| --- | --- | --- |\n| `200` | — | Credentials accepted. Raw OAuth payload, no envelope. |\n| `401` | `invalid_client_credentials` | `client_id` or `client_secret` rejected, client revoked, or client not linked to a company. |\n| `429` | `rate_limit_exceeded` | More than 300 requests in a minute. |\n| `500` | `server_error` | Our fault. The message carries a reference to quote to support. |\n\n**Token lifetime is one year** (`expires_in: 31536000`). Every call mints an additional token and revokes nothing, so cache the token rather than requesting one per API call."},"status":"Unauthorized","code":401,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Those client credentials were not accepted. Check client_id and client_secret, and that your client is still active.\",\n    \"status\": 401,\n    \"responseTime\": \"159ms\",\n    \"error_code\": \"invalid_client_credentials\",\n    \"data\": {\n        \"errors\": []\n    }\n}"}],"_postman_id":"b4518fd2-95d9-44a9-be55-32e1e488a8fc"},{"name":"02 List services at an airport","id":"7707c4c4-bcf8-4362-aad7-e09c25f86204","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/airport-services?page=1&limit=100&country_code=GB&airport_code=MAN&query=Assist","description":"<p>Browses the service catalogue and returns the raw rate variables for each service at each terminal, so you can price locally before creating a quote. It does <strong>not</strong> return a total: send a quote request for that.</p>\n<p>Despite being a <code>POST</code>, all parameters go in the query string.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>Type</th>\n<th>Default</th>\n<th>Notes</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>airport_code</code></td>\n<td>string</td>\n<td>—</td>\n<td>IATA code, e.g. <code>AUH</code>. Must exist.</td>\n</tr>\n<tr>\n<td><code>country_code</code></td>\n<td>string</td>\n<td>—</td>\n<td>ISO country code, e.g. <code>GB</code>. Must exist.</td>\n</tr>\n<tr>\n<td><code>query</code></td>\n<td>string</td>\n<td>—</td>\n<td>Free-text match on the service name.</td>\n</tr>\n<tr>\n<td><code>page</code></td>\n<td>integer</td>\n<td><code>1</code></td>\n<td></td>\n</tr>\n<tr>\n<td><code>limit</code></td>\n<td>integer</td>\n<td><code>25</code></td>\n<td>Maximum <code>100</code>.</td>\n</tr>\n<tr>\n<td><code>sort</code></td>\n<td>string</td>\n<td>—</td>\n<td>Accepted by validation but <strong>not used</strong>.</td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>Response</strong> is the paginated envelope. Each entry carries <code>id</code>, <code>service_name</code>, <code>description</code>, <code>variables[]</code>, <code>terminal</code> and <code>airport</code> (including that airport's <code>charges</code>: surcharge bands, additional-hour rate and tax).</p>\n<p><code>variables[]</code> is the rate card. Which keys appear depends on the service:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Key</th>\n<th>Used by</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>int_arr_dep</code>, <code>int_con</code>, <code>dom_arr_dep</code>, <code>dom_con</code></td>\n<td>Meet &amp; Assist. Nine comma-separated <strong>cumulative totals</strong> indexed by passenger count, so <code>250,500,560,…</code> means 1 pax costs 250 and 2 pax costs 500, not 2 × 250.</td>\n</tr>\n<tr>\n<td><code>ratePerAdult</code>, <code>ratePerChild</code>, <code>ratePerInfant</code></td>\n<td>Lounge Access. Per head, each charged at its own rate.</td>\n</tr>\n<tr>\n<td><code>bandbrk</code>, <code>ratePerRange</code></td>\n<td>Porter Service. Price is <code>ceil(bags / bandbrk) × ratePerRange</code>.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th><code>error_code</code></th>\n<th>When</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>200</code></td>\n<td>—</td>\n<td>Always, even with no matches. <code>message</code> is <code>Successful.</code></td>\n</tr>\n<tr>\n<td><code>422</code></td>\n<td><code>validation_failed</code></td>\n<td>Unknown <code>airport_code</code> or <code>country_code</code>, or <code>limit</code> above 100.</td>\n</tr>\n<tr>\n<td><code>401</code></td>\n<td><code>unauthenticated</code></td>\n<td>Bearer token missing, invalid or expired.</td>\n</tr>\n<tr>\n<td><code>500</code></td>\n<td><code>server_error</code></td>\n<td>Our fault.</td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>Two limits worth knowing.</strong> This endpoint only returns Meet &amp; Assist, Porter Service and Lounge Access; the service list is hardcoded server-side. Booking accepts far more than that, so any other service id has to be given to you out of band.</p>\n<p>And the <code>id</code> returned here is a <strong>service id</strong>, while the <code>services</code> array on a quote is validated against terminal service ids. In practice the service id is what works for pricing, which is what the quote examples use.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{token}}"}]},"isInherited":true,"source":{"_postman_id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","name":"Global Airport Concierge API v1","type":"collection"}},"urlObject":{"path":["airport-services"],"host":["https://api-prod.globalairportconcierge.com/api/v1"],"query":[{"description":{"content":"<p>Page number.</p>\n","type":"text/plain"},"key":"page","value":"1"},{"description":{"content":"<p>Items per page. Maximum 100.</p>\n","type":"text/plain"},"key":"limit","value":"100"},{"description":{"content":"<p>Optional ISO country code filter.</p>\n","type":"text/plain"},"key":"country_code","value":"GB"},{"description":{"content":"<p>Optional airport IATA code filter.</p>\n","type":"text/plain"},"key":"airport_code","value":"MAN"},{"description":{"content":"<p>Optional service search term.</p>\n","type":"text/plain"},"key":"query","value":"Assist"}],"variable":[]}},"response":[{"id":"8585f766-f481-44e9-a4c7-b497fc97d87b","name":"Success","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":{"raw":"https://api-prod.globalairportconcierge.com/api/v1/airport-services?page=1&limit=100&country_code=GB&airport_code=MAN&query=Assist","host":["https://api-prod.globalairportconcierge.com/api/v1"],"path":["airport-services"],"query":[{"key":"page","value":"1","description":"Page number."},{"key":"limit","value":"100","description":"Items per page. Maximum 100."},{"key":"country_code","value":"GB","description":"Optional ISO country code filter."},{"key":"airport_code","value":"MAN","description":"Optional airport IATA code filter."},{"key":"query","value":"Assist","description":"Optional service search term."}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Server","value":"nginx/1.27.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"X-Powered-By","value":"PHP/8.3.13"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Thu, 26 Dec 2024 15:23:39 GMT"},{"key":"Access-Control-Allow-Origin","value":"*"}],"cookie":[],"responseTime":null,"body":"{\n  \"message\": \"Successful.\",\n  \"status\": 200,\n  \"responseTime\": \"123ms\",\n  \"trace\": [],\n  \"data\": {\n    \"current_page\": 1,\n    \"data\": [\n      {\n        \"id\": 1,\n        \"service_name\": \"Meet & Assist\",\n        \"description\": \"Service description\",\n        \"variables\": [\n          {\n            \"key\": \"ratePerAdult\",\n            \"name\": \"Rate per adult\",\n            \"value\": \"175\"\n          }\n        ],\n        \"terminal\": {\n          \"id\": 4,\n          \"terminal_name\": \"LHR Terminal 3\"\n        },\n        \"airport\": {\n          \"name\": \"London Heathrow Airport\",\n          \"iata\": \"LHR\",\n          \"city\": \"London\",\n          \"country\": \"GB\",\n          \"charges\": []\n        }\n      }\n    ],\n    \"first_page_url\": \"...\",\n    \"from\": 1,\n    \"last_page\": 1,\n    \"last_page_url\": \"...\",\n    \"links\": [],\n    \"next_page_url\": null,\n    \"path\": \"...\",\n    \"per_page\": 100,\n    \"prev_page_url\": null,\n    \"to\": 1,\n    \"total\": 1\n  }\n}"},{"id":"220c3855-1902-46f8-92e7-6b59fa0ea022","name":"Invalid IATA code","originalRequest":{"method":"GET","header":[],"body":{"mode":"raw","raw":"{\r\n    \"flights\": [\r\n        {\r\n            \"iata\": \"EW\",\r\n            \"terminal_id\": null,\r\n            \"departure_date\": \"2023-02-24\"\r\n        },\r\n        {\r\n            \"iata\": \"LHR\",\r\n            \"terminal_id\": null,\r\n            \"departure_date\": \"2023-02-25\"\r\n        }\r\n    ],\r\n    \"filters\": {\r\n        \"adult\": 1,\r\n        \"child\": 0,\r\n        \"infant\": 0,\r\n        \"bagMedium\": 1,\r\n        \"bagSmall\": 0,\r\n        \"bagLarge\": 0,\r\n        \"is_connection\": false,\r\n        \"promo\": null,\r\n        \"services\": []\r\n    }\r\n}\r\n","options":{"raw":{"language":"json"}}},"url":{"raw":"https://api-prod.globalairportconcierge.com/api/v1/services?page=1&limit=10","host":["https://api-prod.globalairportconcierge.com/api/v1"],"path":["services"],"query":[{"key":"page","value":"1"},{"key":"limit","value":"10"}]}},"status":"Unprocessable Content","code":422,"_postman_previewlanguage":"json","header":[{"key":"Server","value":"nginx/1.27.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"X-Powered-By","value":"PHP/8.3.13"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Thu, 26 Dec 2024 15:24:00 GMT"},{"key":"Access-Control-Allow-Origin","value":"*"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"The IATA code must be exactly 3 characters.\",\n    \"status\": 422,\n    \"responseTime\": \"300ms\",\n    \"trace\": [],\n    \"errors\": {\n        \"flights.0.iata\": [\n            \"The IATA code must be exactly 3 characters.\"\n        ]\n    },\n    \"data\": []\n}"},{"id":"454682be-516d-4524-8005-a9f2b9de9c43","name":"Maximum Pax Exceeded","originalRequest":{"method":"GET","header":[],"body":{"mode":"raw","raw":"{\r\n    \"flights\": [\r\n        {\r\n            \"iata\": \"EWR\",\r\n            \"terminal_id\": null,\r\n            \"departure_date\": \"2023-02-24\"\r\n        },\r\n        {\r\n            \"iata\": \"LHR\",\r\n            \"terminal_id\": null,\r\n            \"departure_date\": \"2023-02-25\"\r\n        }\r\n    ],\r\n    \"filters\": {\r\n        \"adult\": 10,\r\n        \"child\": 0,\r\n        \"infant\": 0,\r\n        \"bagMedium\": 1,\r\n        \"bagSmall\": 0,\r\n        \"bagLarge\": 0,\r\n        \"is_connection\": false,\r\n        \"promo\": null,\r\n        \"services\": []\r\n    }\r\n}\r\n","options":{"raw":{"language":"json"}}},"url":{"raw":"https://api-prod.globalairportconcierge.com/api/v1/services?page=1&limit=10","host":["https://api-prod.globalairportconcierge.com/api/v1"],"path":["services"],"query":[{"key":"page","value":"1"},{"key":"limit","value":"10"}]}},"status":"Unprocessable Content","code":422,"_postman_previewlanguage":"json","header":[{"key":"Server","value":"nginx/1.27.2"},{"key":"Content-Type","value":"application/json"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"Connection","value":"keep-alive"},{"key":"X-Powered-By","value":"PHP/8.3.13"},{"key":"Cache-Control","value":"no-cache, private"},{"key":"Date","value":"Thu, 26 Dec 2024 15:24:41 GMT"},{"key":"Access-Control-Allow-Origin","value":"*"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"The total number of adults and children cannot exceed 9.\",\n    \"status\": 422,\n    \"responseTime\": \"262ms\",\n    \"trace\": [],\n    \"errors\": {\n        \"filters\": [\n            \"The total number of adults and children cannot exceed 9.\"\n        ]\n    },\n    \"data\": []\n}"},{"id":"f5a63e4c-ee76-1dd0-17cf-4c7918861e83","name":"200 Catalogue at AUH (one entry shown)","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":{"raw":"https://api-prod.globalairportconcierge.com/api/v1/airport-services?page=1&limit=100&country_code=GB&airport_code=MAN&query=Assist","host":["https://api-prod.globalairportconcierge.com/api/v1"],"path":["airport-services"],"query":[{"key":"page","value":"1","description":"Page number."},{"key":"limit","value":"100","description":"Items per page. Maximum 100."},{"key":"country_code","value":"GB","description":"Optional ISO country code filter."},{"key":"airport_code","value":"MAN","description":"Optional airport IATA code filter."},{"key":"query","value":"Assist","description":"Optional service search term."}]},"description":"Browses the service catalogue and returns the raw rate variables for each service at each terminal, so you can price locally before creating a quote. It does **not** return a total: send a quote request for that.\n\nDespite being a `POST`, all parameters go in the query string.\n\n| Parameter | Type | Default | Notes |\n| --- | --- | --- | --- |\n| `airport_code` | string | — | IATA code, e.g. `AUH`. Must exist. |\n| `country_code` | string | — | ISO country code, e.g. `GB`. Must exist. |\n| `query` | string | — | Free-text match on the service name. |\n| `page` | integer | `1` | |\n| `limit` | integer | `25` | Maximum `100`. |\n| `sort` | string | — | Accepted by validation but **not used**. |\n\n**Response** is the paginated envelope. Each entry carries `id`, `service_name`, `description`, `variables[]`, `terminal` and `airport` (including that airport's `charges`: surcharge bands, additional-hour rate and tax).\n\n`variables[]` is the rate card. Which keys appear depends on the service:\n\n| Key | Used by |\n| --- | --- |\n| `int_arr_dep`, `int_con`, `dom_arr_dep`, `dom_con` | Meet & Assist. Nine comma-separated **cumulative totals** indexed by passenger count, so `250,500,560,…` means 1 pax costs 250 and 2 pax costs 500, not 2 × 250. |\n| `ratePerAdult`, `ratePerChild`, `ratePerInfant` | Lounge Access. Per head, each charged at its own rate. |\n| `bandbrk`, `ratePerRange` | Porter Service. Price is `ceil(bags / bandbrk) × ratePerRange`. |\n\n| Status | `error_code` | When |\n| --- | --- | --- |\n| `200` | — | Always, even with no matches. `message` is `Successful.` |\n| `422` | `validation_failed` | Unknown `airport_code` or `country_code`, or `limit` above 100. |\n| `401` | `unauthenticated` | Bearer token missing, invalid or expired. |\n| `500` | `server_error` | Our fault. |\n\n**Two limits worth knowing.** This endpoint only returns Meet & Assist, Porter Service and Lounge Access; the service list is hardcoded server-side. Booking accepts far more than that, so any other service id has to be given to you out of band.\n\nAnd the `id` returned here is a **service id**, while the `services` array on a quote is validated against terminal service ids. In practice the service id is what works for pricing, which is what the quote examples use."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Successful.\",\n    \"status\": 200,\n    \"responseTime\": \"107ms\",\n    \"trace\": [],\n    \"data\": [\n        {\n            \"id\": 1,\n            \"service_name\": \"Meet & Assist\",\n            \"description\": \"***On departure*** - Our Greeter will begin by contacting the Driver prior to your arrival in order to arrange a meeting point at the curbside of the Airport. ***On arrival*** - Our Greeter will be waiting at the end of the Air Bridge or at the gate with a name sign, as the Passengers disembark the plane. ***On connection*** - Our Greeter will be waiting at the end of the Air Bridge with a name sign and will take the Passengers to their Departure Gate.\",\n            \"variables\": [\n                {\n                    \"key\": \"int_arr_dep\",\n                    \"name\": \"International arrival departure\",\n                    \"value\": \"250,500,560,750,935,1125,1225,1400,1575\"\n                },\n                {\n                    \"key\": \"int_con\",\n                    \"name\": \"International connection\",\n                    \"value\": \"250,500,560,750,935,1125,1225,1400,1575\"\n                },\n                {\n                    \"key\": \"dom_arr_dep\",\n                    \"name\": \"Domesic Arrival Departure\",\n                    \"value\": \"250,500,560,750,935,1125,1225,1400,1575\"\n                },\n                {\n                    \"key\": \"dom_con\",\n                    \"name\": \"Domestic connection\",\n                    \"value\": \"250,500,560,750,935,1125,1225,1400,1575\"\n                }\n            ],\n            \"terminal\": {\n                \"id\": 2366,\n                \"terminal_name\": \"AUH Terminal Main\"\n            },\n            \"airport\": {\n                \"name\": \"AUH Abu Dhabi International Airport\",\n                \"iata\": \"AUH\",\n                \"city\": \"Abu Dhabi\",\n                \"country\": {\n                    \"id\": 232,\n                    \"name\": \"United Arab Emirates\",\n                    \"iso_code\": \"AE\"\n                },\n                \"charges\": {\n                    \"surcharge\": [\n                        {\n                            \"below\": 48,\n                            \"percentage\": 50\n                        },\n                        {\n                            \"below\": 24,\n                            \"percentage\": 50\n                        }\n                    ],\n                    \"additional_hour_charge\": {\n                        \"currency\": null,\n                        \"rate\": 0\n                    },\n                    \"tax\": {\n                        \"percentage\": 0,\n                        \"label\": \"VAT\"\n                    }\n                }\n            }\n        }\n    ],\n    \"pagination\": {\n        \"total_count\": 12,\n        \"total_pages\": 6,\n        \"current_page\": 1,\n        \"limit\": 2\n    }\n}"},{"id":"ef16a19c-227b-2308-06da-5fa73eb884e5","name":"422 Unknown airport code","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":{"raw":"https://api-prod.globalairportconcierge.com/api/v1/airport-services?page=1&limit=100&country_code=GB&airport_code=MAN&query=Assist","host":["https://api-prod.globalairportconcierge.com/api/v1"],"path":["airport-services"],"query":[{"key":"page","value":"1","description":"Page number."},{"key":"limit","value":"100","description":"Items per page. Maximum 100."},{"key":"country_code","value":"GB","description":"Optional ISO country code filter."},{"key":"airport_code","value":"MAN","description":"Optional airport IATA code filter."},{"key":"query","value":"Assist","description":"Optional service search term."}]},"description":"Browses the service catalogue and returns the raw rate variables for each service at each terminal, so you can price locally before creating a quote. It does **not** return a total: send a quote request for that.\n\nDespite being a `POST`, all parameters go in the query string.\n\n| Parameter | Type | Default | Notes |\n| --- | --- | --- | --- |\n| `airport_code` | string | — | IATA code, e.g. `AUH`. Must exist. |\n| `country_code` | string | — | ISO country code, e.g. `GB`. Must exist. |\n| `query` | string | — | Free-text match on the service name. |\n| `page` | integer | `1` | |\n| `limit` | integer | `25` | Maximum `100`. |\n| `sort` | string | — | Accepted by validation but **not used**. |\n\n**Response** is the paginated envelope. Each entry carries `id`, `service_name`, `description`, `variables[]`, `terminal` and `airport` (including that airport's `charges`: surcharge bands, additional-hour rate and tax).\n\n`variables[]` is the rate card. Which keys appear depends on the service:\n\n| Key | Used by |\n| --- | --- |\n| `int_arr_dep`, `int_con`, `dom_arr_dep`, `dom_con` | Meet & Assist. Nine comma-separated **cumulative totals** indexed by passenger count, so `250,500,560,…` means 1 pax costs 250 and 2 pax costs 500, not 2 × 250. |\n| `ratePerAdult`, `ratePerChild`, `ratePerInfant` | Lounge Access. Per head, each charged at its own rate. |\n| `bandbrk`, `ratePerRange` | Porter Service. Price is `ceil(bags / bandbrk) × ratePerRange`. |\n\n| Status | `error_code` | When |\n| --- | --- | --- |\n| `200` | — | Always, even with no matches. `message` is `Successful.` |\n| `422` | `validation_failed` | Unknown `airport_code` or `country_code`, or `limit` above 100. |\n| `401` | `unauthenticated` | Bearer token missing, invalid or expired. |\n| `500` | `server_error` | Our fault. |\n\n**Two limits worth knowing.** This endpoint only returns Meet & Assist, Porter Service and Lounge Access; the service list is hardcoded server-side. Booking accepts far more than that, so any other service id has to be given to you out of band.\n\nAnd the `id` returned here is a **service id**, while the `services` array on a quote is validated against terminal service ids. In practice the service id is what works for pricing, which is what the quote examples use."},"status":"Unprocessable Content","code":422,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"The airport code does not exist.\",\n    \"status\": 422,\n    \"responseTime\": \"40ms\",\n    \"error_code\": \"validation_failed\",\n    \"errors\": {\n        \"airport_code\": [\n            \"The airport code does not exist.\"\n        ]\n    },\n    \"data\": []\n}"}],"_postman_id":"7707c4c4-bcf8-4362-aad7-e09c25f86204"},{"name":"02b List service bundles","id":"87b51c3e-d935-64b9-53b4-ebc2b271c593","request":{"method":"GET","header":[],"url":"https://api-prod.globalairportconcierge.com/api/v1/bundles","description":"<p>The named packages you can sell, and what each one takes off.</p>\n<p>A bundle is a set of services with a discount. It applies <strong>automatically</strong>: put every member service on the same stop in <strong>03 Create quote</strong> and the discount comes off. There is no bundle id to send and nothing to opt into.</p>\n<p>This endpoint exists so you can show the package by name and explain the price before the customer commits.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Notes</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>id</code></td>\n<td>Ours. You never send it back.</td>\n</tr>\n<tr>\n<td><code>name</code></td>\n<td>Safe to show a customer. This is what appears on the invoice.</td>\n</tr>\n<tr>\n<td><code>description</code></td>\n<td>Optional, may be <code>null</code>.</td>\n</tr>\n<tr>\n<td><code>discount</code></td>\n<td>Either a percentage like <code>\"15%\"</code> or a flat amount in the booking currency.</td>\n</tr>\n<tr>\n<td><code>valid_from</code></td>\n<td><code>null</code> means no start date. Otherwise the bundle applies only to bookings made on or after this.</td>\n</tr>\n<tr>\n<td><code>valid_to</code></td>\n<td><code>null</code> means it never expires. Otherwise the last moment a booking can be made and still get it.</td>\n</tr>\n<tr>\n<td><code>services[]</code></td>\n<td>Every one of these must be on the same stop for the bundle to apply.</td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>Only bundles you can actually get are returned.</strong> Some bundles are reserved for a single customer, and the ones you see are already filtered to yours and to those open to everyone. Expired and not-yet-open bundles are filtered out too, so anything in this list is bookable right now.</p>\n<p><code>valid_from</code> and <code>valid_to</code> are about <strong>when the booking is made</strong>, not when the passenger travels. A bundle that closes on 31 March still honours a booking made on 30 March for travel in August.</p>\n<h3 id=\"how-the-discount-is-worked-out\">How the discount is worked out</h3>\n<p>Taken off the summed price of the member services on that stop, then spread back across them pro-rata. Each service line keeps showing its own full price; the reduction appears in the booking total.</p>\n<p>Measured against a real booking at LHR Terminal 3, 2 adults:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Meet &amp; Assist alone</td>\n<td><code>148.50</code></td>\n</tr>\n<tr>\n<td>Porter Service alone</td>\n<td><code>45.00</code></td>\n</tr>\n<tr>\n<td>Together</td>\n<td><code>193.50</code></td>\n</tr>\n<tr>\n<td>Arrival Package, 15%</td>\n<td><code>-29.03</code></td>\n</tr>\n<tr>\n<td><strong><code>grand_total</code></strong></td>\n<td><strong><code>164.47</code></strong></td>\n</tr>\n</tbody>\n</table>\n</div><p>The stop in the booking response tells you which bundle was applied:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">\"location_total\": {\n  \"service_bundle_id\": 1,\n  \"bundle_name\": \"Arrival Package\",\n  \"bundle_discount\": \"29.03\"\n}\n</code></pre>\n<p><code>service_bundle_id</code> is <code>null</code> and <code>bundle_discount</code> is <code>\"0.00\"</code> when no bundle matched, which is the normal case.</p>\n<h3 id=\"rules-worth-knowing\">Rules worth knowing</h3>\n<ul>\n<li><strong>All members, one stop.</strong> A bundle whose services are split across the arrival and the departure stop does not apply. Two of three members on a stop does not apply either.</li>\n<li><strong>Best one wins.</strong> If two bundles both match, you get whichever gives the larger discount, not the first one listed. Note that a generous two-service bundle can beat a wider three-service one. Where two are worth exactly the same, one reserved for your company wins.</li>\n<li><strong>Availability follows rates.</strong> A bundle is not restricted to a list of airports. It applies anywhere every member service has a rate loaded, so coverage grows as GAC loads rates.</li>\n<li>A flat discount is capped at the value of the member services, so a stop can never go negative.</li>\n<li><strong>Re-read this list rather than caching it forever.</strong> A bundle can be given an end date, or withdrawn, without notice. Prices you quote from a stale copy will not match what <strong>03 Create quote</strong> returns.</li>\n</ul>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th><code>error_code</code></th>\n<th>When</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>200</code></td>\n<td>—</td>\n<td>Always, including an empty <code>data</code> array when no bundles are available to you.</td>\n</tr>\n<tr>\n<td><code>401</code></td>\n<td><code>unauthenticated</code></td>\n<td>Bearer token missing, invalid or expired.</td>\n</tr>\n<tr>\n<td><code>500</code></td>\n<td><code>server_error</code></td>\n<td>Our fault.</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{token}}"}]},"isInherited":true,"source":{"_postman_id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","name":"Global Airport Concierge API v1","type":"collection"}},"urlObject":{"path":["bundles"],"host":["https://api-prod.globalairportconcierge.com/api/v1"],"query":[],"variable":[]}},"response":[{"id":"7d6db8a9-623e-4b22-6c30-2c58956c4abe","name":"200 Two bundles, both open to everyone","originalRequest":{"method":"GET","header":[],"url":"https://api-prod.globalairportconcierge.com/api/v1/bundles"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":"18","body":"{\"message\":\"Successful.\",\"status\":200,\"responseTime\":\"18ms\",\"trace\":[],\"data\":[{\"id\":1,\"name\":\"Arrival Package\",\"description\":\"Meet & Assist with a porter on arrival\",\"discount\":\"15%\",\"valid_from\":null,\"valid_to\":null,\"services\":[{\"id\":1,\"service_name\":\"Meet & Assist\"},{\"id\":2,\"service_name\":\"Porter Service\"}]},{\"id\":2,\"name\":\"Arrival Package Plus\",\"description\":\"Meet & Assist, porter and lounge access\",\"discount\":\"20%\",\"valid_from\":null,\"valid_to\":null,\"services\":[{\"id\":1,\"service_name\":\"Meet & Assist\"},{\"id\":2,\"service_name\":\"Porter Service\"},{\"id\":4,\"service_name\":\"Lounge Access\"}]}]}"}],"_postman_id":"87b51c3e-d935-64b9-53b4-ebc2b271c593"},{"name":"03 Create quote","event":[{"listen":"prerequest","script":{"type":"text/javascript","exec":["// customer_reference must be unique per tenant, so a fixed value 422s on the\n// second run. Regenerate it here, and leave it in place afterwards so\n// \"11 Get booking by your reference\" can look this booking up.\npm.environment.set(\"customer_reference\", \"PM-\" + Date.now());"]}},{"listen":"test","script":{"type":"text/javascript","exec":["const data = pm.response.json().data;\n\npm.environment.set(\"booking_id\", data.id);\n\n// Keep the reference so \"04 Replace quote\" can echo it back. A replace that omits\n// ref_no generates a brand new one, which strands anything holding the old value.\npm.environment.set(\"booking_ref\", data.ref_no);"]}}],"id":"db543e7c-5155-4ac5-8293-a8cd498dc110","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n    \"booker_id\": {{booker_id}},\n    \"journeys\": [\n        {\n            \"adult\": 1,\n            \"child\": 1,\n            \"infant\": 1,\n            \"bag_large\": 0,\n            \"bag_medium\": 0,\n            \"bag_small\": 0,\n            \"passengers\": {\n                \"adult\": [\n                    {\n                        \"pnr\": \"NOPNR1\",\n                        \"lead\": true,\n                        \"first_name\": \"Haylie\",\n                        \"last_name\": \"Stokes\",\n                        \"class_type\": \"ECONOMY\",\n                        \"signage\": \"Haylie Stokes\",\n                        \"phone\": \"+37062144442\",\n                        \"email\": \"haylie.stokes@example.com\"\n                    }\n                ],\n                \"child\": [\n                    {\n                        \"pnr\": \"NOPNR1\",\n                        \"lead\": false,\n                        \"first_name\": \"Saul\",\n                        \"last_name\": \"Ward\",\n                        \"class_type\": \"ECONOMY\",\n                        \"signage\": \"Saul Ward\",\n                        \"phone\": \"+37062144442\"\n                    }\n                ],\n                \"infant\": [\n                    {\n                        \"pnr\": \"NOPNR1\",\n                        \"lead\": false,\n                        \"first_name\": \"Erin\",\n                        \"last_name\": \"Towne\",\n                        \"class_type\": \"ECONOMY\",\n                        \"signage\": \"Erin Towne\",\n                        \"phone\": \"+37062144442\"\n                    }\n                ]\n            },\n            \"flight\": \"AY1077\",\n            \"stops\": {\n                \"arrival\": {\n                    \"connection\": false,\n                    \"date\": \"2026-10-28T21:10:00.000+02:00\",\n                    \"meeting_date\": \"2026-10-28T21:10:00.000+02:00\",\n                    \"services\": [\n                        1\n                    ],\n                    \"terminal_id\": 2103\n                }\n            }\n        }\n    ],\n    \"currency\": \"GBP\",\n    \"confirm\": false,\n    \"settings\": {\n        \"customer_reference\": \"{{customer_reference}}\"\n    }\n}","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings","description":"<p>Creates a priced quote. Every booking starts here, in status <code>quote</code>, and stays a quote until you confirm it with <strong>06 Confirm quote</strong>.</p>\n<p>Quotes are valid for <strong>one week</strong> from creation. <code>expires_on</code> in the response is authoritative. An expired quote cannot be confirmed; reprice it first with <strong>05 Reprice quote</strong>.</p>\n<h3 id=\"required-fields\">Required fields</h3>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Rules</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>booker_id</code></td>\n<td>Must be a user of the company that owns your client credentials.</td>\n</tr>\n<tr>\n<td><code>currency</code></td>\n<td>ISO code that exists in our currency table, e.g. <code>GBP</code>.</td>\n</tr>\n<tr>\n<td><code>confirm</code></td>\n<td>`required</td>\n</tr>\n<tr>\n<td><code>journeys[]</code></td>\n<td>At least one.</td>\n</tr>\n<tr>\n<td><code>journeys[].flight</code></td>\n<td>Airline code plus number, e.g. <code>EK1</code>. Validated against the allowed-airline list.</td>\n</tr>\n<tr>\n<td><code>journeys[].adult</code> / <code>.child</code> / <code>.infant</code></td>\n<td>Integers, max 1000 each.</td>\n</tr>\n<tr>\n<td><code>journeys[].bag_medium</code></td>\n<td>Integer, max 2000. <code>bag_small</code> and <code>bag_large</code> are optional.</td>\n</tr>\n<tr>\n<td><code>journeys[].stops</code></td>\n<td><code>arrival</code>, <code>departure</code>, or both. <strong>One leg is enough</strong> on this API.</td>\n</tr>\n<tr>\n<td><code>stops.*.date</code> / <code>.meeting_date</code> / <code>.terminal_id</code></td>\n<td>Required once that leg is present.</td>\n</tr>\n</tbody>\n</table>\n</div><p>Optional: <code>comments</code>, <code>website</code>, <code>journeys[].manual</code>, <code>journeys[].passengers</code>, <code>settings.customer_reference</code>, <code>stops.*.connection</code>, <code>stops.*.service_options</code>.</p>\n<p><code>settings.customer_reference</code> is your own reference. Letters, digits and hyphens only, unique across your bookings, and the key you can later look the booking up by with <strong>11 Get booking by your reference</strong>. Worth sending on every booking: it is the only handle you control.</p>\n<p>Set <code>journeys[].manual</code> to <code>true</code> to stop us looking the flight up and adjusting your dates to the published schedule.</p>\n<h3 id=\"passengers\">Passengers</h3>\n<p><code>journeys[].passengers</code> is optional. When you send it, group the passengers under <code>adult</code>, <code>child</code> and <code>infant</code>. Each passenger takes:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Rules</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>pnr</code></td>\n<td>Required. 5 or 6 letters or digits.</td>\n</tr>\n<tr>\n<td><code>lead</code></td>\n<td>Required boolean.</td>\n</tr>\n<tr>\n<td><code>first_name</code> / <code>last_name</code></td>\n<td>Required.</td>\n</tr>\n<tr>\n<td><code>signage</code></td>\n<td>Required. The name on the greeter's sign.</td>\n</tr>\n<tr>\n<td><code>class_type</code></td>\n<td>Required, e.g. <code>ECONOMY</code>.</td>\n</tr>\n<tr>\n<td><code>title</code></td>\n<td>Optional.</td>\n</tr>\n<tr>\n<td><code>phone</code></td>\n<td>Optional. Free text; include the country code.</td>\n</tr>\n<tr>\n<td><code>email</code></td>\n<td>Optional. Must be a valid email address, otherwise the request is rejected with <code>422</code>.</td>\n</tr>\n</tbody>\n</table>\n</div><p><code>phone</code> and <code>email</code> are stored as the passenger's contact details and shown to our operations team.</p>\n<h3 id=\"services-and-how-each-one-is-priced\">Services and how each one is priced</h3>\n<p>Put service ids in <code>stops.*.services</code>. Most services are priced straight from the journey's passenger and bag counts, so send the real numbers.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Service</th>\n<th>id</th>\n<th>Priced on</th>\n<th>Airports with rates</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Baggage Protection</td>\n<td><code>16</code></td>\n<td><code>adult + child</code></td>\n<td>677</td>\n</tr>\n<tr>\n<td>Meet &amp; Assist</td>\n<td><code>1</code></td>\n<td><code>adult + child</code>, from a nine-tier cumulative table. Infants are not counted.</td>\n<td>522</td>\n</tr>\n<tr>\n<td>Porter Service</td>\n<td><code>2</code></td>\n<td><code>bag_small + bag_medium + bag_large</code></td>\n<td>520</td>\n</tr>\n<tr>\n<td>Lounge Access</td>\n<td><code>4</code></td>\n<td><code>adult</code>, <code>child</code> and <code>infant</code>, each at its own rate</td>\n<td>173</td>\n</tr>\n<tr>\n<td>Electric Buggy</td>\n<td><code>84</code></td>\n<td><code>adult + child</code>, in bands</td>\n<td>6</td>\n</tr>\n<tr>\n<td>Fast Track</td>\n<td><code>3</code></td>\n<td><code>adult + child</code></td>\n<td>5</td>\n</tr>\n<tr>\n<td>Tarmac Transfer</td>\n<td><code>85</code></td>\n<td><code>adult + child</code>, in bands</td>\n<td>1</td>\n</tr>\n<tr>\n<td>Airport By Invitation</td>\n<td><code>19</code></td>\n<td>head count, <code>adult + child</code> unless you override it</td>\n<td>9</td>\n</tr>\n<tr>\n<td>Car Transfer</td>\n<td><code>6</code></td>\n<td>vehicle type, radius and number of vehicles</td>\n<td>see the warning below</td>\n</tr>\n</tbody>\n</table>\n</div><p>Lounge Access is the only service that charges infants, and only where the airport has a non-zero infant rate.</p>\n<p><strong>Car Transfer is the only service that needs anything beyond the journey.</strong> Everything else prices from the passenger and bag counts you already send.</p>\n<p><strong>02 List services at an airport</strong> returns only ids <code>1</code>, <code>2</code> and <code>4</code>. The rest are bookable but not discoverable, so use the ids above and ask GAC which airports carry them.</p>\n<p><strong>Car Transfer has no rates loaded yet.</strong> It accepts the booking and returns a line worth <code>0</code>. Talk to GAC before offering it to a customer.</p>\n<h3 id=\"connections\">Connections</h3>\n<p>A passenger changing planes is met on arrival and again on departure, at the same airport. That is <strong>two stops on one journey</strong>, each with <code>connection: true</code>.</p>\n<p>Meet &amp; Assist prices a connection from a separate connection rate table and halves it per stop, so the two legs together come to one connection fare. The example books both legs at DOH: £276.25 on arrival plus £276.25 on departure, £552.50 in total.</p>\n<p><strong>Send both legs.</strong> A single stop with <code>connection: true</code> is accepted and priced at half a fare. Nothing warns you, so a connection sent as one stop is silently charged at half price.</p>\n<p>Other services on a connection stop are priced normally; only Meet &amp; Assist has a connection table.</p>\n<h3 id=\"service-options\">Service options</h3>\n<p>Two services take inputs that do not come from the passenger counts. Send them in <code>service_options</code> on the same stop, keyed by service id:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">\"stops\": {\n  \"arrival\": {\n    \"terminal_id\": 4,\n    \"services\": [6],\n    \"service_options\": {\n      \"6\": {\n        \"vehicle_type\": \"SUV\",\n        \"radius\": \"21-40\",\n        \"vehicles\": 2,\n        \"pickup\": \"Terminal 3 arrivals hall\",\n        \"dropoff\": \"SW1A 1AA\"\n      }\n    }\n  }\n}\n</code></pre>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Option</th>\n<th>Applies to</th>\n<th>Required</th>\n<th>Values</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>vehicle_type</code></td>\n<td>Car Transfer</td>\n<td>no, defaults to Sedan</td>\n<td><code>Sedan</code>, <code>SUV</code>, <code>MPV</code>, <code>Airside Car Transfer</code></td>\n</tr>\n<tr>\n<td><code>radius</code></td>\n<td>Car Transfer</td>\n<td>no, defaults to <code>0-20</code></td>\n<td><code>0-20</code>, <code>21-40</code>, <code>41-60</code></td>\n</tr>\n<tr>\n<td><code>vehicles</code></td>\n<td>Car Transfer</td>\n<td>no, defaults to <code>1</code></td>\n<td>Any positive integer</td>\n</tr>\n<tr>\n<td><code>pickup</code></td>\n<td>Car Transfer</td>\n<td>no</td>\n<td>Free text collection point</td>\n</tr>\n<tr>\n<td><code>dropoff</code></td>\n<td>Car Transfer</td>\n<td><strong>yes</strong></td>\n<td>Free text destination</td>\n</tr>\n<tr>\n<td><code>people</code></td>\n<td>Airport By Invitation</td>\n<td>no, defaults to <code>adult + child</code></td>\n<td>Any positive integer</td>\n</tr>\n</tbody>\n</table>\n</div><p>Anything outside this list is rejected. Values are checked before the booking is priced, so a typo comes back as <code>422</code> rather than a quote for the wrong vehicle. <code>service_options</code> is optional and omitting it changes nothing.</p>\n<h4 id=\"where-these-values-come-from\">Where these values come from</h4>\n<p><code>vehicle_type</code> and <code>radius</code> are picked from a fixed list held in our database, the same list the GAC operations console uses, so the two never drift apart.</p>\n<p><strong>You do not have to send the full stored string.</strong> The stored values are marketing descriptions such as <code>SUV (Max 6pax, 4Bags. BMW X5, Benz GLE-Class, Audi Q7 or simillar)</code>. Any unambiguous prefix resolves to it, so <code>SUV</code> and <code>suv</code> both work. Matching is case-insensitive, and an ambiguous prefix is rejected rather than guessed at.</p>\n<p><strong>An invalid value tells you the valid ones.</strong> The <code>422</code> lists them in full, read from the same rows the check uses, so it is always current:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"errors\": {\n    \"journeys.0.stops.arrival.service_options.6.vehicle_type\": [\n      \"\\\"Limousine\\\" is not a valid value for vehicle_type. Allowed values are: Sedan (Max 4pax, 2Bags. BMW 7Series, Benz E-Class, Audi A7 or simillar) | SUV (Max 6pax, 4Bags. BMW X5, Benz GLE-Class, Audi Q7 or simillar) | MPV (Max 8pax, 6bags. Mercedes-Benz V-Class, Toyota Alphard or similar) | Airside Car Transfer.\"\n    ]\n  }\n}\n</code></pre>\n<p>There is no endpoint that lists these options. <strong>02 List services at an airport</strong> returns rate variables only, and does not cover Car Transfer at all. If the list above is not enough for your integration, ask GAC and we will expose it properly.</p>\n<p><code>radius</code> is your own measurement, in miles from the airport to the drop-off. We do not geocode the addresses, so the band you send is the band you are charged for.</p>\n<p><code>pickup</code> and <code>dropoff</code> are passed to the driver as written. Send something a driver can act on, not a code.</p>\n<h3 id=\"responses\">Responses</h3>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th><code>error_code</code></th>\n<th>When</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>200</code></td>\n<td>—</td>\n<td>Created. <code>message</code> is <code>Booking Created successfully!</code></td>\n</tr>\n<tr>\n<td><code>422</code></td>\n<td><code>validation_failed</code></td>\n<td>Anything wrong with the payload, including a <code>booker_id</code> outside your company, a <code>customer_reference</code> you have already used, and a bad or missing <code>service_options</code> value. Every problem is reported at once in <code>errors</code>.</td>\n</tr>\n<tr>\n<td><code>401</code></td>\n<td><code>unauthenticated</code></td>\n<td>Bearer token missing, invalid or expired.</td>\n</tr>\n<tr>\n<td><code>429</code></td>\n<td><code>rate_limit_exceeded</code></td>\n<td>Over 300 requests a minute.</td>\n</tr>\n<tr>\n<td><code>500</code></td>\n<td><code>server_error</code></td>\n<td>Our fault. Nothing was created.</td>\n</tr>\n</tbody>\n</table>\n</div><h3 id=\"two-things-to-know\">Two things to know</h3>\n<p><strong><code>confirm</code> does not confirm.</strong> It is validated as required, but sending <code>confirm: true</code> leaves the booking in status <code>quote</code>, and the response still says <code>Booking Created successfully!</code> with no error. Measured, in both JSON and query-parameter form. Call <strong>06 Confirm quote</strong> explicitly instead.</p>\n<p><strong>There is no idempotency key.</strong> Retrying a request that timed out creates a second booking with a second reference. Send a unique <code>settings.customer_reference</code> on every attempt. If a retry comes back <code>422</code> with <code>errors[\"settings.customer_reference\"]</code>, that is proof the first attempt succeeded: fetch it with <strong>11 Get booking by your reference</strong> rather than creating another.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{token}}"}]},"isInherited":true,"source":{"_postman_id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","name":"Global Airport Concierge API v1","type":"collection"}},"urlObject":{"path":["bookings"],"host":["https://api-prod.globalairportconcierge.com/api/v1"],"query":[],"variable":[]}},"response":[{"id":"b602f95a-d01e-8b5d-f0d6-8df2435e1e4c","name":"200 Meet and Assist (4 adults, DOH)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"booker_id\": 39083,\n  \"currency\": \"GBP\",\n  \"confirm\": false,\n  \"journeys\": [\n    {\n      \"flight\": \"EK1\",\n      \"manual\": true,\n      \"adult\": 4,\n      \"child\": 0,\n      \"infant\": 0,\n      \"bag_small\": 0,\n      \"bag_medium\": 1,\n      \"bag_large\": 0,\n      \"passengers\": {\n        \"adult\": [\n          {\n            \"pnr\": \"ABC123\",\n            \"lead\": true,\n            \"signage\": \"John Doe\",\n            \"class_type\": \"Economy Class\",\n            \"title\": \"Mr\",\n            \"first_name\": \"John\",\n            \"last_name\": \"Doe\",\n            \"phone\": \"+441234567890\"\n          }\n        ]\n      },\n      \"stops\": {\n        \"arrival\": {\n          \"date\": \"2026-12-31T11:40:00\",\n          \"meeting_date\": \"2026-12-31T11:40:00\",\n          \"terminal_id\": 185,\n          \"connection\": false,\n          \"services\": [1]\n        }\n      }\n    }\n  ],\n  \"settings\": { \"customer_reference\": \"EX-25857000\" }\n}","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Booking Created successfully!\",\n    \"status\": 200,\n    \"responseTime\": \"418ms\",\n    \"trace\": [],\n    \"data\": {\n        \"id\": 34655,\n        \"expires_on\": \"2026-09-01T22:30:15+00:00\",\n        \"ref_no\": \"GAC-6A8E17778D51C\",\n        \"status\": \"quote\",\n        \"currency\": {\n            \"id\": 3,\n            \"symbol\": \"£\",\n            \"name\": \"British Pound Sterling\",\n            \"symbol_native\": \"£\",\n            \"decimal_digits\": 2,\n            \"rounding\": 0,\n            \"code\": \"GBP\",\n            \"name_plural\": \"British pounds sterling\",\n            \"multiplier\": 0.85\n        },\n        \"journeys\": [\n            {\n                \"flight\": \"EK1\",\n                \"adult\": 4,\n                \"child\": 0,\n                \"infant\": 0,\n                \"bag_small\": 0,\n                \"bag_medium\": 1,\n                \"bag_large\": 0,\n                \"passengers\": {\n                    \"adult\": [\n                        {\n                            \"type\": \"adult\",\n                            \"lead\": true,\n                            \"pnr\": \"ABC123\",\n                            \"signage\": \"John Doe\",\n                            \"class_type\": \"Economy Class\",\n                            \"title\": \"Mr\",\n                            \"first_name\": \"John\",\n                            \"last_name\": \"Doe\",\n                            \"contacts\": [\n                                {\n                                    \"type\": \"phone\",\n                                    \"value\": \"+441234567890\",\n                                    \"contact_person\": \"John Doe\"\n                                }\n                            ]\n                        }\n                    ],\n                    \"child\": [],\n                    \"infant\": []\n                },\n                \"stops\": {\n                    \"arrival\": {\n                        \"airport\": {\n                            \"id\": 60,\n                            \"name\": \"DOH Hamad International Airport\",\n                            \"iata\": \"DOH\"\n                        },\n                        \"services\": [\n                            {\n                                \"id\": 1,\n                                \"value\": 552.5,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Meet & Assist\",\n                                \"allocation\": null\n                            }\n                        ],\n                        \"airport_id\": 60\n                    },\n                    \"departure\": null\n                }\n            }\n        ],\n        \"billing\": {\n            \"status\": 0,\n            \"total_discount\": 0,\n            \"add_hrs_charge\": 0,\n            \"surcharge\": 0,\n            \"total_booking_cost\": 552.5,\n            \"grand_total\": 552.5,\n            \"total_paid\": \"0.00\",\n            \"total_refund_amount\": 0,\n            \"tax\": 0,\n            \"tax_rate\": 0\n        },\n        \"settings\": {\n            \"no_surcharge\": false,\n            \"no_additional_hour_charges\": false,\n            \"customer_reference\": \"EX-25857000\"\n        },\n        \"promo_code\": null,\n        \"created_at\": \"2026-08-25T22:30:15+00:00\",\n        \"currency_id\": 3,\n        \"booker_id\": 39083\n    }\n}"},{"id":"5ae390db-3fda-4486-fdf4-34527fa9aa64","name":"200 Porter Service (4 bags, DOH)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"booker_id\": 39083,\n  \"currency\": \"GBP\",\n  \"confirm\": false,\n  \"journeys\": [\n    {\n      \"flight\": \"EK1\",\n      \"manual\": true,\n      \"adult\": 2,\n      \"child\": 0,\n      \"infant\": 0,\n      \"bag_small\": 0,\n      \"bag_medium\": 4,\n      \"bag_large\": 0,\n      \"passengers\": {\n        \"adult\": [\n          {\n            \"pnr\": \"ABC123\",\n            \"lead\": true,\n            \"signage\": \"John Doe\",\n            \"class_type\": \"Economy Class\",\n            \"title\": \"Mr\",\n            \"first_name\": \"John\",\n            \"last_name\": \"Doe\",\n            \"phone\": \"+441234567890\"\n          }\n        ]\n      },\n      \"stops\": {\n        \"arrival\": {\n          \"date\": \"2026-12-31T11:40:00\",\n          \"meeting_date\": \"2026-12-31T11:40:00\",\n          \"terminal_id\": 185,\n          \"connection\": false,\n          \"services\": [2]\n        }\n      }\n    }\n  ],\n  \"settings\": { \"customer_reference\": \"EX-64709000\" }\n}","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Booking Created successfully!\",\n    \"status\": 200,\n    \"responseTime\": \"314ms\",\n    \"trace\": [],\n    \"data\": {\n        \"id\": 34656,\n        \"expires_on\": \"2026-09-01T22:30:16+00:00\",\n        \"ref_no\": \"GAC-6A8E177806574\",\n        \"status\": \"quote\",\n        \"currency\": {\n            \"id\": 3,\n            \"symbol\": \"£\",\n            \"name\": \"British Pound Sterling\",\n            \"symbol_native\": \"£\",\n            \"decimal_digits\": 2,\n            \"rounding\": 0,\n            \"code\": \"GBP\",\n            \"name_plural\": \"British pounds sterling\",\n            \"multiplier\": 0.85\n        },\n        \"journeys\": [\n            {\n                \"flight\": \"EK1\",\n                \"adult\": 2,\n                \"child\": 0,\n                \"infant\": 0,\n                \"bag_small\": 0,\n                \"bag_medium\": 4,\n                \"bag_large\": 0,\n                \"passengers\": {\n                    \"adult\": [\n                        {\n                            \"type\": \"adult\",\n                            \"lead\": true,\n                            \"pnr\": \"ABC123\",\n                            \"signage\": \"John Doe\",\n                            \"class_type\": \"Economy Class\",\n                            \"title\": \"Mr\",\n                            \"first_name\": \"John\",\n                            \"last_name\": \"Doe\",\n                            \"contacts\": [\n                                {\n                                    \"type\": \"phone\",\n                                    \"value\": \"+441234567890\",\n                                    \"contact_person\": \"John Doe\"\n                                }\n                            ]\n                        }\n                    ],\n                    \"child\": [],\n                    \"infant\": []\n                },\n                \"stops\": {\n                    \"arrival\": {\n                        \"airport\": {\n                            \"id\": 60,\n                            \"name\": \"DOH Hamad International Airport\",\n                            \"iata\": \"DOH\"\n                        },\n                        \"services\": [\n                            {\n                                \"id\": 2,\n                                \"value\": 51,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Porter Service\",\n                                \"allocation\": null\n                            }\n                        ],\n                        \"airport_id\": 60\n                    },\n                    \"departure\": null\n                }\n            }\n        ],\n        \"billing\": {\n            \"status\": 0,\n            \"total_discount\": 0,\n            \"add_hrs_charge\": 0,\n            \"surcharge\": 0,\n            \"total_booking_cost\": 51,\n            \"grand_total\": 51,\n            \"total_paid\": \"0.00\",\n            \"total_refund_amount\": 0,\n            \"tax\": 0,\n            \"tax_rate\": 0\n        },\n        \"settings\": {\n            \"no_surcharge\": false,\n            \"no_additional_hour_charges\": false,\n            \"customer_reference\": \"EX-64709000\"\n        },\n        \"promo_code\": null,\n        \"created_at\": \"2026-08-25T22:30:16+00:00\",\n        \"currency_id\": 3,\n        \"booker_id\": 39083\n    }\n}"},{"id":"f1bfeef4-97aa-3c99-2602-4c6827adde1d","name":"200 Lounge Access (2 adults, 1 child, 1 infant, DOH)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"booker_id\": 39083,\n  \"currency\": \"GBP\",\n  \"confirm\": false,\n  \"journeys\": [\n    {\n      \"flight\": \"EK1\",\n      \"manual\": true,\n      \"adult\": 2,\n      \"child\": 1,\n      \"infant\": 1,\n      \"bag_small\": 0,\n      \"bag_medium\": 1,\n      \"bag_large\": 0,\n      \"passengers\": {\n        \"adult\": [\n          {\n            \"pnr\": \"ABC123\",\n            \"lead\": true,\n            \"signage\": \"John Doe\",\n            \"class_type\": \"Economy Class\",\n            \"title\": \"Mr\",\n            \"first_name\": \"John\",\n            \"last_name\": \"Doe\",\n            \"phone\": \"+441234567890\"\n          }\n        ]\n      },\n      \"stops\": {\n        \"arrival\": {\n          \"date\": \"2026-12-31T11:40:00\",\n          \"meeting_date\": \"2026-12-31T11:40:00\",\n          \"terminal_id\": 185,\n          \"connection\": false,\n          \"services\": [4]\n        }\n      }\n    }\n  ],\n  \"settings\": { \"customer_reference\": \"EX-38207000\" }\n}","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Booking Created successfully!\",\n    \"status\": 200,\n    \"responseTime\": \"294ms\",\n    \"trace\": [],\n    \"data\": {\n        \"id\": 34657,\n        \"expires_on\": \"2026-09-01T22:30:16+00:00\",\n        \"ref_no\": \"GAC-6A8E1778607A4\",\n        \"status\": \"quote\",\n        \"currency\": {\n            \"id\": 3,\n            \"symbol\": \"£\",\n            \"name\": \"British Pound Sterling\",\n            \"symbol_native\": \"£\",\n            \"decimal_digits\": 2,\n            \"rounding\": 0,\n            \"code\": \"GBP\",\n            \"name_plural\": \"British pounds sterling\",\n            \"multiplier\": 0.85\n        },\n        \"journeys\": [\n            {\n                \"flight\": \"EK1\",\n                \"adult\": 2,\n                \"child\": 1,\n                \"infant\": 1,\n                \"bag_small\": 0,\n                \"bag_medium\": 1,\n                \"bag_large\": 0,\n                \"passengers\": {\n                    \"adult\": [\n                        {\n                            \"type\": \"adult\",\n                            \"lead\": true,\n                            \"pnr\": \"ABC123\",\n                            \"signage\": \"John Doe\",\n                            \"class_type\": \"Economy Class\",\n                            \"title\": \"Mr\",\n                            \"first_name\": \"John\",\n                            \"last_name\": \"Doe\",\n                            \"contacts\": [\n                                {\n                                    \"type\": \"phone\",\n                                    \"value\": \"+441234567890\",\n                                    \"contact_person\": \"John Doe\"\n                                }\n                            ]\n                        }\n                    ],\n                    \"child\": [],\n                    \"infant\": []\n                },\n                \"stops\": {\n                    \"arrival\": {\n                        \"airport\": {\n                            \"id\": 60,\n                            \"name\": \"DOH Hamad International Airport\",\n                            \"iata\": \"DOH\"\n                        },\n                        \"services\": [\n                            {\n                                \"id\": 4,\n                                \"value\": 325.55,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Lounge Access\",\n                                \"allocation\": null\n                            }\n                        ],\n                        \"airport_id\": 60\n                    },\n                    \"departure\": null\n                }\n            }\n        ],\n        \"billing\": {\n            \"status\": 0,\n            \"total_discount\": 0,\n            \"add_hrs_charge\": 0,\n            \"surcharge\": 0,\n            \"total_booking_cost\": 325.55,\n            \"grand_total\": 325.55,\n            \"total_paid\": \"0.00\",\n            \"total_refund_amount\": 0,\n            \"tax\": 0,\n            \"tax_rate\": 0\n        },\n        \"settings\": {\n            \"no_surcharge\": false,\n            \"no_additional_hour_charges\": false,\n            \"customer_reference\": \"EX-38207000\"\n        },\n        \"promo_code\": null,\n        \"created_at\": \"2026-08-25T22:30:16+00:00\",\n        \"currency_id\": 3,\n        \"booker_id\": 39083\n    }\n}"},{"id":"a8e337b4-f008-2d2f-5789-ed3cdd2364ac","name":"200 Fast Track (4 adults, LGW)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"booker_id\": 39083,\n  \"currency\": \"GBP\",\n  \"confirm\": false,\n  \"journeys\": [\n    {\n      \"flight\": \"EK1\",\n      \"manual\": true,\n      \"adult\": 4,\n      \"child\": 0,\n      \"infant\": 0,\n      \"bag_small\": 0,\n      \"bag_medium\": 1,\n      \"bag_large\": 0,\n      \"passengers\": {\n        \"adult\": [\n          {\n            \"pnr\": \"ABC123\",\n            \"lead\": true,\n            \"signage\": \"John Doe\",\n            \"class_type\": \"Economy Class\",\n            \"title\": \"Mr\",\n            \"first_name\": \"John\",\n            \"last_name\": \"Doe\",\n            \"phone\": \"+441234567890\"\n          }\n        ]\n      },\n      \"stops\": {\n        \"arrival\": {\n          \"date\": \"2026-12-31T11:40:00\",\n          \"meeting_date\": \"2026-12-31T11:40:00\",\n          \"terminal_id\": 284,\n          \"connection\": false,\n          \"services\": [3]\n        }\n      }\n    }\n  ],\n  \"settings\": { \"customer_reference\": \"EX-36871000\" }\n}","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Booking Created successfully!\",\n    \"status\": 200,\n    \"responseTime\": \"280ms\",\n    \"trace\": [],\n    \"data\": {\n        \"id\": 34661,\n        \"expires_on\": \"2026-09-01T22:30:17+00:00\",\n        \"ref_no\": \"GAC-6A8E1779C1DC6\",\n        \"status\": \"quote\",\n        \"currency\": {\n            \"id\": 3,\n            \"symbol\": \"£\",\n            \"name\": \"British Pound Sterling\",\n            \"symbol_native\": \"£\",\n            \"decimal_digits\": 2,\n            \"rounding\": 0,\n            \"code\": \"GBP\",\n            \"name_plural\": \"British pounds sterling\",\n            \"multiplier\": 0.85\n        },\n        \"journeys\": [\n            {\n                \"flight\": \"EK1\",\n                \"adult\": 4,\n                \"child\": 0,\n                \"infant\": 0,\n                \"bag_small\": 0,\n                \"bag_medium\": 1,\n                \"bag_large\": 0,\n                \"passengers\": {\n                    \"adult\": [\n                        {\n                            \"type\": \"adult\",\n                            \"lead\": true,\n                            \"pnr\": \"ABC123\",\n                            \"signage\": \"John Doe\",\n                            \"class_type\": \"Economy Class\",\n                            \"title\": \"Mr\",\n                            \"first_name\": \"John\",\n                            \"last_name\": \"Doe\",\n                            \"contacts\": [\n                                {\n                                    \"type\": \"phone\",\n                                    \"value\": \"+441234567890\",\n                                    \"contact_person\": \"John Doe\"\n                                }\n                            ]\n                        }\n                    ],\n                    \"child\": [],\n                    \"infant\": []\n                },\n                \"stops\": {\n                    \"arrival\": {\n                        \"airport\": {\n                            \"id\": 88,\n                            \"name\": \"LGW Gatwick Airport\",\n                            \"iata\": \"LGW\"\n                        },\n                        \"services\": [\n                            {\n                                \"id\": 3,\n                                \"value\": 119,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Fast Track\",\n                                \"allocation\": null\n                            }\n                        ],\n                        \"airport_id\": 88\n                    },\n                    \"departure\": null\n                }\n            }\n        ],\n        \"billing\": {\n            \"status\": 0,\n            \"total_discount\": 0,\n            \"add_hrs_charge\": 0,\n            \"surcharge\": 0,\n            \"total_booking_cost\": 119,\n            \"grand_total\": 119,\n            \"total_paid\": \"0.00\",\n            \"total_refund_amount\": 0,\n            \"tax\": 0,\n            \"tax_rate\": 0\n        },\n        \"settings\": {\n            \"no_surcharge\": false,\n            \"no_additional_hour_charges\": false,\n            \"customer_reference\": \"EX-36871000\"\n        },\n        \"promo_code\": null,\n        \"created_at\": \"2026-08-25T22:30:17+00:00\",\n        \"currency_id\": 3,\n        \"booker_id\": 39083\n    }\n}"},{"id":"fb6035cc-cfa4-3824-c03b-5ad38ec02bb4","name":"200 Electric Buggy (4 adults, DOH)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"booker_id\": 39083,\n  \"currency\": \"GBP\",\n  \"confirm\": false,\n  \"journeys\": [\n    {\n      \"flight\": \"EK1\",\n      \"manual\": true,\n      \"adult\": 4,\n      \"child\": 0,\n      \"infant\": 0,\n      \"bag_small\": 0,\n      \"bag_medium\": 1,\n      \"bag_large\": 0,\n      \"passengers\": {\n        \"adult\": [\n          {\n            \"pnr\": \"ABC123\",\n            \"lead\": true,\n            \"signage\": \"John Doe\",\n            \"class_type\": \"Economy Class\",\n            \"title\": \"Mr\",\n            \"first_name\": \"John\",\n            \"last_name\": \"Doe\",\n            \"phone\": \"+441234567890\"\n          }\n        ]\n      },\n      \"stops\": {\n        \"arrival\": {\n          \"date\": \"2026-12-31T11:40:00\",\n          \"meeting_date\": \"2026-12-31T11:40:00\",\n          \"terminal_id\": 185,\n          \"connection\": false,\n          \"services\": [84]\n        }\n      }\n    }\n  ],\n  \"settings\": { \"customer_reference\": \"EX-62952000\" }\n}","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Booking Created successfully!\",\n    \"status\": 200,\n    \"responseTime\": \"288ms\",\n    \"trace\": [],\n    \"data\": {\n        \"id\": 34659,\n        \"expires_on\": \"2026-09-01T22:30:17+00:00\",\n        \"ref_no\": \"GAC-6A8E17791BC8B\",\n        \"status\": \"quote\",\n        \"currency\": {\n            \"id\": 3,\n            \"symbol\": \"£\",\n            \"name\": \"British Pound Sterling\",\n            \"symbol_native\": \"£\",\n            \"decimal_digits\": 2,\n            \"rounding\": 0,\n            \"code\": \"GBP\",\n            \"name_plural\": \"British pounds sterling\",\n            \"multiplier\": 0.85\n        },\n        \"journeys\": [\n            {\n                \"flight\": \"EK1\",\n                \"adult\": 4,\n                \"child\": 0,\n                \"infant\": 0,\n                \"bag_small\": 0,\n                \"bag_medium\": 1,\n                \"bag_large\": 0,\n                \"passengers\": {\n                    \"adult\": [\n                        {\n                            \"type\": \"adult\",\n                            \"lead\": true,\n                            \"pnr\": \"ABC123\",\n                            \"signage\": \"John Doe\",\n                            \"class_type\": \"Economy Class\",\n                            \"title\": \"Mr\",\n                            \"first_name\": \"John\",\n                            \"last_name\": \"Doe\",\n                            \"contacts\": [\n                                {\n                                    \"type\": \"phone\",\n                                    \"value\": \"+441234567890\",\n                                    \"contact_person\": \"John Doe\"\n                                }\n                            ]\n                        }\n                    ],\n                    \"child\": [],\n                    \"infant\": []\n                },\n                \"stops\": {\n                    \"arrival\": {\n                        \"airport\": {\n                            \"id\": 60,\n                            \"name\": \"DOH Hamad International Airport\",\n                            \"iata\": \"DOH\"\n                        },\n                        \"services\": [\n                            {\n                                \"id\": 84,\n                                \"value\": 76.5,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Electric Buggy\",\n                                \"allocation\": null\n                            }\n                        ],\n                        \"airport_id\": 60\n                    },\n                    \"departure\": null\n                }\n            }\n        ],\n        \"billing\": {\n            \"status\": 0,\n            \"total_discount\": 0,\n            \"add_hrs_charge\": 0,\n            \"surcharge\": 0,\n            \"total_booking_cost\": 76.5,\n            \"grand_total\": 76.5,\n            \"total_paid\": \"0.00\",\n            \"total_refund_amount\": 0,\n            \"tax\": 0,\n            \"tax_rate\": 0\n        },\n        \"settings\": {\n            \"no_surcharge\": false,\n            \"no_additional_hour_charges\": false,\n            \"customer_reference\": \"EX-62952000\"\n        },\n        \"promo_code\": null,\n        \"created_at\": \"2026-08-25T22:30:17+00:00\",\n        \"currency_id\": 3,\n        \"booker_id\": 39083\n    }\n}"},{"id":"f8933328-e490-0d04-8c68-d5595b901ab5","name":"200 Baggage Protection (4 adults, DOH)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"booker_id\": 39083,\n  \"currency\": \"GBP\",\n  \"confirm\": false,\n  \"journeys\": [\n    {\n      \"flight\": \"EK1\",\n      \"manual\": true,\n      \"adult\": 4,\n      \"child\": 0,\n      \"infant\": 0,\n      \"bag_small\": 0,\n      \"bag_medium\": 1,\n      \"bag_large\": 0,\n      \"passengers\": {\n        \"adult\": [\n          {\n            \"pnr\": \"ABC123\",\n            \"lead\": true,\n            \"signage\": \"John Doe\",\n            \"class_type\": \"Economy Class\",\n            \"title\": \"Mr\",\n            \"first_name\": \"John\",\n            \"last_name\": \"Doe\",\n            \"phone\": \"+441234567890\"\n          }\n        ]\n      },\n      \"stops\": {\n        \"arrival\": {\n          \"date\": \"2026-12-31T11:40:00\",\n          \"meeting_date\": \"2026-12-31T11:40:00\",\n          \"terminal_id\": 185,\n          \"connection\": false,\n          \"services\": [16]\n        }\n      }\n    }\n  ],\n  \"settings\": { \"customer_reference\": \"EX-95821000\" }\n}","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Booking Created successfully!\",\n    \"status\": 200,\n    \"responseTime\": \"311ms\",\n    \"trace\": [],\n    \"data\": {\n        \"id\": 34658,\n        \"expires_on\": \"2026-09-01T22:30:16+00:00\",\n        \"ref_no\": \"GAC-6A8E1778BA4CA\",\n        \"status\": \"quote\",\n        \"currency\": {\n            \"id\": 3,\n            \"symbol\": \"£\",\n            \"name\": \"British Pound Sterling\",\n            \"symbol_native\": \"£\",\n            \"decimal_digits\": 2,\n            \"rounding\": 0,\n            \"code\": \"GBP\",\n            \"name_plural\": \"British pounds sterling\",\n            \"multiplier\": 0.85\n        },\n        \"journeys\": [\n            {\n                \"flight\": \"EK1\",\n                \"adult\": 4,\n                \"child\": 0,\n                \"infant\": 0,\n                \"bag_small\": 0,\n                \"bag_medium\": 1,\n                \"bag_large\": 0,\n                \"passengers\": {\n                    \"adult\": [\n                        {\n                            \"type\": \"adult\",\n                            \"lead\": true,\n                            \"pnr\": \"ABC123\",\n                            \"signage\": \"John Doe\",\n                            \"class_type\": \"Economy Class\",\n                            \"title\": \"Mr\",\n                            \"first_name\": \"John\",\n                            \"last_name\": \"Doe\",\n                            \"contacts\": [\n                                {\n                                    \"type\": \"phone\",\n                                    \"value\": \"+441234567890\",\n                                    \"contact_person\": \"John Doe\"\n                                }\n                            ]\n                        }\n                    ],\n                    \"child\": [],\n                    \"infant\": []\n                },\n                \"stops\": {\n                    \"arrival\": {\n                        \"airport\": {\n                            \"id\": 60,\n                            \"name\": \"DOH Hamad International Airport\",\n                            \"iata\": \"DOH\"\n                        },\n                        \"services\": [\n                            {\n                                \"id\": 16,\n                                \"value\": 17,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Baggage Protection\",\n                                \"allocation\": null\n                            }\n                        ],\n                        \"airport_id\": 60\n                    },\n                    \"departure\": null\n                }\n            }\n        ],\n        \"billing\": {\n            \"status\": 0,\n            \"total_discount\": 0,\n            \"add_hrs_charge\": 0,\n            \"surcharge\": 0,\n            \"total_booking_cost\": 17,\n            \"grand_total\": 17,\n            \"total_paid\": \"0.00\",\n            \"total_refund_amount\": 0,\n            \"tax\": 0,\n            \"tax_rate\": 0\n        },\n        \"settings\": {\n            \"no_surcharge\": false,\n            \"no_additional_hour_charges\": false,\n            \"customer_reference\": \"EX-95821000\"\n        },\n        \"promo_code\": null,\n        \"created_at\": \"2026-08-25T22:30:16+00:00\",\n        \"currency_id\": 3,\n        \"booker_id\": 39083\n    }\n}"},{"id":"285b45bb-b7dc-903f-2587-bef850fbee26","name":"200 Tarmac Transfer (4 adults, DOH)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"booker_id\": 39083,\n  \"currency\": \"GBP\",\n  \"confirm\": false,\n  \"journeys\": [\n    {\n      \"flight\": \"EK1\",\n      \"manual\": true,\n      \"adult\": 4,\n      \"child\": 0,\n      \"infant\": 0,\n      \"bag_small\": 0,\n      \"bag_medium\": 1,\n      \"bag_large\": 0,\n      \"passengers\": {\n        \"adult\": [\n          {\n            \"pnr\": \"ABC123\",\n            \"lead\": true,\n            \"signage\": \"John Doe\",\n            \"class_type\": \"Economy Class\",\n            \"title\": \"Mr\",\n            \"first_name\": \"John\",\n            \"last_name\": \"Doe\",\n            \"phone\": \"+441234567890\"\n          }\n        ]\n      },\n      \"stops\": {\n        \"arrival\": {\n          \"date\": \"2026-12-31T11:40:00\",\n          \"meeting_date\": \"2026-12-31T11:40:00\",\n          \"terminal_id\": 185,\n          \"connection\": false,\n          \"services\": [85]\n        }\n      }\n    }\n  ],\n  \"settings\": { \"customer_reference\": \"EX-07434000\" }\n}","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Booking Created successfully!\",\n    \"status\": 200,\n    \"responseTime\": \"273ms\",\n    \"trace\": [],\n    \"data\": {\n        \"id\": 34660,\n        \"expires_on\": \"2026-09-01T22:30:17+00:00\",\n        \"ref_no\": \"GAC-6A8E17796FCB6\",\n        \"status\": \"quote\",\n        \"currency\": {\n            \"id\": 3,\n            \"symbol\": \"£\",\n            \"name\": \"British Pound Sterling\",\n            \"symbol_native\": \"£\",\n            \"decimal_digits\": 2,\n            \"rounding\": 0,\n            \"code\": \"GBP\",\n            \"name_plural\": \"British pounds sterling\",\n            \"multiplier\": 0.85\n        },\n        \"journeys\": [\n            {\n                \"flight\": \"EK1\",\n                \"adult\": 4,\n                \"child\": 0,\n                \"infant\": 0,\n                \"bag_small\": 0,\n                \"bag_medium\": 1,\n                \"bag_large\": 0,\n                \"passengers\": {\n                    \"adult\": [\n                        {\n                            \"type\": \"adult\",\n                            \"lead\": true,\n                            \"pnr\": \"ABC123\",\n                            \"signage\": \"John Doe\",\n                            \"class_type\": \"Economy Class\",\n                            \"title\": \"Mr\",\n                            \"first_name\": \"John\",\n                            \"last_name\": \"Doe\",\n                            \"contacts\": [\n                                {\n                                    \"type\": \"phone\",\n                                    \"value\": \"+441234567890\",\n                                    \"contact_person\": \"John Doe\"\n                                }\n                            ]\n                        }\n                    ],\n                    \"child\": [],\n                    \"infant\": []\n                },\n                \"stops\": {\n                    \"arrival\": {\n                        \"airport\": {\n                            \"id\": 60,\n                            \"name\": \"DOH Hamad International Airport\",\n                            \"iata\": \"DOH\"\n                        },\n                        \"services\": [\n                            {\n                                \"id\": 85,\n                                \"value\": 170,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Tarmac Transfer\",\n                                \"allocation\": null\n                            }\n                        ],\n                        \"airport_id\": 60\n                    },\n                    \"departure\": null\n                }\n            }\n        ],\n        \"billing\": {\n            \"status\": 0,\n            \"total_discount\": 0,\n            \"add_hrs_charge\": 0,\n            \"surcharge\": 0,\n            \"total_booking_cost\": 170,\n            \"grand_total\": 170,\n            \"total_paid\": \"0.00\",\n            \"total_refund_amount\": 0,\n            \"tax\": 0,\n            \"tax_rate\": 0\n        },\n        \"settings\": {\n            \"no_surcharge\": false,\n            \"no_additional_hour_charges\": false,\n            \"customer_reference\": \"EX-07434000\"\n        },\n        \"promo_code\": null,\n        \"created_at\": \"2026-08-25T22:30:17+00:00\",\n        \"currency_id\": 3,\n        \"booker_id\": 39083\n    }\n}"},{"id":"3d989492-6061-0ecb-bccc-50d179639577","name":"200 Car Transfer with service_options (2 SUVs, LHR)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"booker_id\": 39083,\n  \"currency\": \"GBP\",\n  \"confirm\": false,\n  \"journeys\": [\n    {\n      \"flight\": \"EK1\",\n      \"manual\": true,\n      \"adult\": 2,\n      \"child\": 0,\n      \"infant\": 0,\n      \"bag_small\": 0,\n      \"bag_medium\": 2,\n      \"bag_large\": 0,\n      \"passengers\": {\n        \"adult\": [\n          {\n            \"pnr\": \"ABC123\",\n            \"lead\": true,\n            \"signage\": \"John Doe\",\n            \"class_type\": \"Economy Class\",\n            \"title\": \"Mr\",\n            \"first_name\": \"John\",\n            \"last_name\": \"Doe\",\n            \"phone\": \"+441234567890\"\n          }\n        ]\n      },\n      \"stops\": {\n        \"arrival\": {\n          \"date\": \"2026-12-31T11:40:00\",\n          \"meeting_date\": \"2026-12-31T11:40:00\",\n          \"terminal_id\": 4,\n          \"connection\": false,\n          \"services\": [6],\n          \"service_options\": {\n            \"6\": {\n              \"vehicle_type\": \"SUV\",\n              \"radius\": \"21-40\",\n              \"vehicles\": 2,\n              \"pickup\": \"Terminal 3 arrivals hall\",\n              \"dropoff\": \"SW1A 1AA\"\n            }\n          }\n        }\n      }\n    }\n  ],\n  \"settings\": { \"customer_reference\": \"EX-24737000\" }\n}","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Booking Created successfully!\",\n    \"status\": 200,\n    \"responseTime\": \"317ms\",\n    \"trace\": [],\n    \"data\": {\n        \"id\": 34663,\n        \"expires_on\": \"2026-09-01T22:30:18+00:00\",\n        \"ref_no\": \"GAC-6A8E177A75E6D\",\n        \"status\": \"quote\",\n        \"currency\": {\n            \"id\": 3,\n            \"symbol\": \"£\",\n            \"name\": \"British Pound Sterling\",\n            \"symbol_native\": \"£\",\n            \"decimal_digits\": 2,\n            \"rounding\": 0,\n            \"code\": \"GBP\",\n            \"name_plural\": \"British pounds sterling\",\n            \"multiplier\": 0.85\n        },\n        \"journeys\": [\n            {\n                \"flight\": \"EK1\",\n                \"adult\": 2,\n                \"child\": 0,\n                \"infant\": 0,\n                \"bag_small\": 0,\n                \"bag_medium\": 2,\n                \"bag_large\": 0,\n                \"passengers\": {\n                    \"adult\": [\n                        {\n                            \"type\": \"adult\",\n                            \"lead\": true,\n                            \"pnr\": \"ABC123\",\n                            \"signage\": \"John Doe\",\n                            \"class_type\": \"Economy Class\",\n                            \"title\": \"Mr\",\n                            \"first_name\": \"John\",\n                            \"last_name\": \"Doe\",\n                            \"contacts\": [\n                                {\n                                    \"type\": \"phone\",\n                                    \"value\": \"+441234567890\",\n                                    \"contact_person\": \"John Doe\"\n                                }\n                            ]\n                        }\n                    ],\n                    \"child\": [],\n                    \"infant\": []\n                },\n                \"stops\": {\n                    \"arrival\": {\n                        \"airport\": {\n                            \"id\": 2,\n                            \"name\": \"LHR London Heathrow Airport\",\n                            \"iata\": \"LHR\"\n                        },\n                        \"services\": [\n                            {\n                                \"id\": 6,\n                                \"value\": 510,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Car Transfer\",\n                                \"allocation\": null\n                            }\n                        ],\n                        \"airport_id\": 2\n                    },\n                    \"departure\": null\n                }\n            }\n        ],\n        \"billing\": {\n            \"status\": 0,\n            \"total_discount\": 0,\n            \"add_hrs_charge\": 0,\n            \"surcharge\": 0,\n            \"total_booking_cost\": 510,\n            \"grand_total\": 510,\n            \"total_paid\": \"0.00\",\n            \"total_refund_amount\": 0,\n            \"tax\": 0,\n            \"tax_rate\": 0\n        },\n        \"settings\": {\n            \"no_surcharge\": false,\n            \"no_additional_hour_charges\": false,\n            \"customer_reference\": \"EX-24737000\"\n        },\n        \"promo_code\": null,\n        \"created_at\": \"2026-08-25T22:30:18+00:00\",\n        \"currency_id\": 3,\n        \"booker_id\": 39083\n    }\n}"},{"id":"74b5fab4-d6b3-c9b2-2190-d5020f8c884d","name":"200 Airport By Invitation (4 people, LGW)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"booker_id\": 39083,\n  \"currency\": \"GBP\",\n  \"confirm\": false,\n  \"journeys\": [\n    {\n      \"flight\": \"EK1\",\n      \"manual\": true,\n      \"adult\": 4,\n      \"child\": 0,\n      \"infant\": 0,\n      \"bag_small\": 0,\n      \"bag_medium\": 1,\n      \"bag_large\": 0,\n      \"passengers\": {\n        \"adult\": [\n          {\n            \"pnr\": \"ABC123\",\n            \"lead\": true,\n            \"signage\": \"John Doe\",\n            \"class_type\": \"Economy Class\",\n            \"title\": \"Mr\",\n            \"first_name\": \"John\",\n            \"last_name\": \"Doe\",\n            \"phone\": \"+441234567890\"\n          }\n        ]\n      },\n      \"stops\": {\n        \"arrival\": {\n          \"date\": \"2026-12-31T11:40:00\",\n          \"meeting_date\": \"2026-12-31T11:40:00\",\n          \"terminal_id\": 284,\n          \"connection\": false,\n          \"services\": [19]\n        }\n      }\n    }\n  ],\n  \"settings\": { \"customer_reference\": \"EX-73263000\" }\n}","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Booking Created successfully!\",\n    \"status\": 200,\n    \"responseTime\": \"289ms\",\n    \"trace\": [],\n    \"data\": {\n        \"id\": 34662,\n        \"expires_on\": \"2026-09-01T22:30:18+00:00\",\n        \"ref_no\": \"GAC-6A8E177A1FE29\",\n        \"status\": \"quote\",\n        \"currency\": {\n            \"id\": 3,\n            \"symbol\": \"£\",\n            \"name\": \"British Pound Sterling\",\n            \"symbol_native\": \"£\",\n            \"decimal_digits\": 2,\n            \"rounding\": 0,\n            \"code\": \"GBP\",\n            \"name_plural\": \"British pounds sterling\",\n            \"multiplier\": 0.85\n        },\n        \"journeys\": [\n            {\n                \"flight\": \"EK1\",\n                \"adult\": 4,\n                \"child\": 0,\n                \"infant\": 0,\n                \"bag_small\": 0,\n                \"bag_medium\": 1,\n                \"bag_large\": 0,\n                \"passengers\": {\n                    \"adult\": [\n                        {\n                            \"type\": \"adult\",\n                            \"lead\": true,\n                            \"pnr\": \"ABC123\",\n                            \"signage\": \"John Doe\",\n                            \"class_type\": \"Economy Class\",\n                            \"title\": \"Mr\",\n                            \"first_name\": \"John\",\n                            \"last_name\": \"Doe\",\n                            \"contacts\": [\n                                {\n                                    \"type\": \"phone\",\n                                    \"value\": \"+441234567890\",\n                                    \"contact_person\": \"John Doe\"\n                                }\n                            ]\n                        }\n                    ],\n                    \"child\": [],\n                    \"infant\": []\n                },\n                \"stops\": {\n                    \"arrival\": {\n                        \"airport\": {\n                            \"id\": 88,\n                            \"name\": \"LGW Gatwick Airport\",\n                            \"iata\": \"LGW\"\n                        },\n                        \"services\": [\n                            {\n                                \"id\": 19,\n                                \"value\": 2694.5,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Airport By Invitation\",\n                                \"allocation\": null\n                            }\n                        ],\n                        \"airport_id\": 88\n                    },\n                    \"departure\": null\n                }\n            }\n        ],\n        \"billing\": {\n            \"status\": 0,\n            \"total_discount\": 0,\n            \"add_hrs_charge\": 0,\n            \"surcharge\": 0,\n            \"total_booking_cost\": 2694.5,\n            \"grand_total\": 2694.5,\n            \"total_paid\": \"0.00\",\n            \"total_refund_amount\": 0,\n            \"tax\": 0,\n            \"tax_rate\": 0\n        },\n        \"settings\": {\n            \"no_surcharge\": false,\n            \"no_additional_hour_charges\": false,\n            \"customer_reference\": \"EX-73263000\"\n        },\n        \"promo_code\": null,\n        \"created_at\": \"2026-08-25T22:30:18+00:00\",\n        \"currency_id\": 3,\n        \"booker_id\": 39083\n    }\n}"},{"id":"da8e38e7-e720-4933-6471-966819662fc9","name":"200 Several services in one booking (DOH)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"booker_id\": 39083,\n  \"currency\": \"GBP\",\n  \"confirm\": false,\n  \"journeys\": [\n    {\n      \"flight\": \"EK1\",\n      \"manual\": true,\n      \"adult\": 2,\n      \"child\": 1,\n      \"infant\": 0,\n      \"bag_small\": 0,\n      \"bag_medium\": 3,\n      \"bag_large\": 0,\n      \"passengers\": {\n        \"adult\": [\n          {\n            \"pnr\": \"ABC123\",\n            \"lead\": true,\n            \"signage\": \"John Doe\",\n            \"class_type\": \"Economy Class\",\n            \"title\": \"Mr\",\n            \"first_name\": \"John\",\n            \"last_name\": \"Doe\",\n            \"phone\": \"+441234567890\"\n          }\n        ]\n      },\n      \"stops\": {\n        \"arrival\": {\n          \"date\": \"2026-12-31T11:40:00\",\n          \"meeting_date\": \"2026-12-31T11:40:00\",\n          \"terminal_id\": 185,\n          \"connection\": false,\n          \"services\": [1, 2, 4]\n        }\n      }\n    }\n  ],\n  \"settings\": { \"customer_reference\": \"EX-03438000\" }\n}","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Booking Created successfully!\",\n    \"status\": 200,\n    \"responseTime\": \"476ms\",\n    \"trace\": [],\n    \"data\": {\n        \"id\": 34664,\n        \"expires_on\": \"2026-09-01T22:30:18+00:00\",\n        \"ref_no\": \"GAC-6A8E177AD79D2\",\n        \"status\": \"quote\",\n        \"currency\": {\n            \"id\": 3,\n            \"symbol\": \"£\",\n            \"name\": \"British Pound Sterling\",\n            \"symbol_native\": \"£\",\n            \"decimal_digits\": 2,\n            \"rounding\": 0,\n            \"code\": \"GBP\",\n            \"name_plural\": \"British pounds sterling\",\n            \"multiplier\": 0.85\n        },\n        \"journeys\": [\n            {\n                \"flight\": \"EK1\",\n                \"adult\": 2,\n                \"child\": 1,\n                \"infant\": 0,\n                \"bag_small\": 0,\n                \"bag_medium\": 3,\n                \"bag_large\": 0,\n                \"passengers\": {\n                    \"adult\": [\n                        {\n                            \"type\": \"adult\",\n                            \"lead\": true,\n                            \"pnr\": \"ABC123\",\n                            \"signage\": \"John Doe\",\n                            \"class_type\": \"Economy Class\",\n                            \"title\": \"Mr\",\n                            \"first_name\": \"John\",\n                            \"last_name\": \"Doe\",\n                            \"contacts\": [\n                                {\n                                    \"type\": \"phone\",\n                                    \"value\": \"+441234567890\",\n                                    \"contact_person\": \"John Doe\"\n                                }\n                            ]\n                        }\n                    ],\n                    \"child\": [],\n                    \"infant\": []\n                },\n                \"stops\": {\n                    \"arrival\": {\n                        \"airport\": {\n                            \"id\": 60,\n                            \"name\": \"DOH Hamad International Airport\",\n                            \"iata\": \"DOH\"\n                        },\n                        \"services\": [\n                            {\n                                \"id\": 1,\n                                \"value\": 425,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Meet & Assist\",\n                                \"allocation\": null\n                            },\n                            {\n                                \"id\": 2,\n                                \"value\": 51,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Porter Service\",\n                                \"allocation\": null\n                            },\n                            {\n                                \"id\": 4,\n                                \"value\": 325.55,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Lounge Access\",\n                                \"allocation\": null\n                            }\n                        ],\n                        \"airport_id\": 60\n                    },\n                    \"departure\": null\n                }\n            }\n        ],\n        \"billing\": {\n            \"status\": 0,\n            \"total_discount\": 0,\n            \"add_hrs_charge\": 0,\n            \"surcharge\": 0,\n            \"total_booking_cost\": 801.55,\n            \"grand_total\": 801.55,\n            \"total_paid\": \"0.00\",\n            \"total_refund_amount\": 0,\n            \"tax\": 0,\n            \"tax_rate\": 0\n        },\n        \"settings\": {\n            \"no_surcharge\": false,\n            \"no_additional_hour_charges\": false,\n            \"customer_reference\": \"EX-03438000\"\n        },\n        \"promo_code\": null,\n        \"created_at\": \"2026-08-25T22:30:18+00:00\",\n        \"currency_id\": 3,\n        \"booker_id\": 39083\n    }\n}"},{"id":"9292cc18-7e08-b987-cf10-54d67d964ef1","name":"200 Connection, both legs at the hub (DOH)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"booker_id\": 39083,\n  \"currency\": \"GBP\",\n  \"confirm\": false,\n  \"journeys\": [\n    {\n      \"flight\": \"EK1\",\n      \"manual\": true,\n      \"adult\": 4,\n      \"child\": 0,\n      \"infant\": 0,\n      \"bag_small\": 0,\n      \"bag_medium\": 1,\n      \"bag_large\": 0,\n      \"passengers\": {\n        \"adult\": [\n          {\n            \"pnr\": \"ABC123\",\n            \"lead\": true,\n            \"signage\": \"John Doe\",\n            \"class_type\": \"Economy Class\",\n            \"title\": \"Mr\",\n            \"first_name\": \"John\",\n            \"last_name\": \"Doe\",\n            \"phone\": \"+441234567890\"\n          }\n        ]\n      },\n      \"stops\": {\n        \"arrival\": {\n          \"date\": \"2026-12-31T11:40:00\",\n          \"meeting_date\": \"2026-12-31T11:40:00\",\n          \"terminal_id\": 185,\n          \"connection\": true,\n          \"services\": [1]\n        },\n        \"departure\": {\n          \"date\": \"2026-12-31T15:10:00\",\n          \"meeting_date\": \"2026-12-31T15:10:00\",\n          \"terminal_id\": 185,\n          \"connection\": true,\n          \"services\": [1]\n        }\n      }\n    }\n  ],\n  \"settings\": { \"customer_reference\": \"EX-CONN-0001\" }\n}","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Booking Created successfully!\",\n    \"status\": 200,\n    \"responseTime\": \"687ms\",\n    \"trace\": [],\n    \"data\": {\n        \"id\": 34672,\n        \"expires_on\": \"2026-09-01T23:30:01+00:00\",\n        \"ref_no\": \"GAC-6A8E25791B555\",\n        \"status\": \"quote\",\n        \"currency\": {\n            \"id\": 3,\n            \"symbol\": \"£\",\n            \"name\": \"British Pound Sterling\",\n            \"symbol_native\": \"£\",\n            \"decimal_digits\": 2,\n            \"rounding\": 0,\n            \"code\": \"GBP\",\n            \"name_plural\": \"British pounds sterling\",\n            \"multiplier\": 0.85\n        },\n        \"journeys\": [\n            {\n                \"flight\": \"EK1\",\n                \"adult\": 4,\n                \"child\": 0,\n                \"infant\": 0,\n                \"bag_small\": 0,\n                \"bag_medium\": 1,\n                \"bag_large\": 0,\n                \"passengers\": {\n                    \"adult\": [\n                        {\n                            \"type\": \"adult\",\n                            \"lead\": true,\n                            \"pnr\": \"ABC123\",\n                            \"signage\": \"John Doe\",\n                            \"class_type\": \"Economy Class\",\n                            \"title\": \"Mr\",\n                            \"first_name\": \"John\",\n                            \"last_name\": \"Doe\",\n                            \"contacts\": [\n                                {\n                                    \"type\": \"phone\",\n                                    \"value\": \"+441234567890\",\n                                    \"contact_person\": \"John Doe\"\n                                }\n                            ]\n                        }\n                    ],\n                    \"child\": [],\n                    \"infant\": []\n                },\n                \"stops\": {\n                    \"arrival\": {\n                        \"airport\": {\n                            \"id\": 60,\n                            \"name\": \"DOH Hamad International Airport\",\n                            \"iata\": \"DOH\"\n                        },\n                        \"services\": [\n                            {\n                                \"id\": 1,\n                                \"value\": 276.25,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Meet & Assist\",\n                                \"allocation\": null\n                            }\n                        ],\n                        \"airport_id\": 60\n                    },\n                    \"departure\": {\n                        \"airport\": {\n                            \"id\": 60,\n                            \"name\": \"DOH Hamad International Airport\",\n                            \"iata\": \"DOH\"\n                        },\n                        \"services\": [\n                            {\n                                \"id\": 1,\n                                \"value\": 276.25,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Meet & Assist\",\n                                \"allocation\": null\n                            }\n                        ],\n                        \"airport_id\": 60\n                    }\n                }\n            }\n        ],\n        \"billing\": {\n            \"status\": 0,\n            \"total_discount\": 0,\n            \"add_hrs_charge\": 0,\n            \"surcharge\": 0,\n            \"total_booking_cost\": 552.5,\n            \"grand_total\": 552.5,\n            \"total_paid\": \"0.00\",\n            \"total_refund_amount\": 0,\n            \"tax\": 0,\n            \"tax_rate\": 0\n        },\n        \"settings\": {\n            \"no_surcharge\": false,\n            \"no_additional_hour_charges\": false,\n            \"customer_reference\": \"EX-CONN-0001\"\n        },\n        \"promo_code\": null,\n        \"created_at\": \"2026-08-25T23:30:01+00:00\",\n        \"currency_id\": 3,\n        \"booker_id\": 39083\n    }\n}"},{"id":"d9d67601-d488-5689-6d2d-ea0b58c8f84c","name":"422 Bad service_options","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"booker_id\": 39083,\n  \"currency\": \"GBP\",\n  \"confirm\": false,\n  \"journeys\": [\n    {\n      \"flight\": \"EK1\",\n      \"manual\": true,\n      \"adult\": 2,\n      \"child\": 0,\n      \"infant\": 0,\n      \"bag_small\": 0,\n      \"bag_medium\": 2,\n      \"bag_large\": 0,\n      \"stops\": {\n        \"arrival\": {\n          \"date\": \"2026-12-31T11:40:00\",\n          \"meeting_date\": \"2026-12-31T11:40:00\",\n          \"terminal_id\": 4,\n          \"connection\": false,\n          \"services\": [6],\n          \"service_options\": {\n            \"6\": { \"vehicle_type\": \"Limousine\" }\n          }\n        }\n      }\n    }\n  ],\n  \"settings\": { \"customer_reference\": \"EX-OPTERR-1\" }\n}","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings"},"status":"Unprocessable Content","code":422,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"\\\"Limousine\\\" is not a valid value for vehicle_type. Allowed values are: Sedan (Max 4pax, 2Bags. BMW 7Series, Benz E-Class, Audi A7 or simillar) | SUV (Max 6pax, 4Bags. BMW X5, Benz GLE-Class, Audi Q7 or simillar) | MPV (Max 8pax, 6bags. Mercedes-Benz V-Class, Toyota Alphard or similar) | Airside Car Transfer. (and 1 more error)\",\n    \"status\": 422,\n    \"responseTime\": \"69ms\",\n    \"error_code\": \"validation_failed\",\n    \"errors\": {\n        \"journeys.0.stops.arrival.service_options.6.vehicle_type\": [\n            \"\\\"Limousine\\\" is not a valid value for vehicle_type. Allowed values are: Sedan (Max 4pax, 2Bags. BMW 7Series, Benz E-Class, Audi A7 or simillar) | SUV (Max 6pax, 4Bags. BMW X5, Benz GLE-Class, Audi Q7 or simillar) | MPV (Max 8pax, 6bags. Mercedes-Benz V-Class, Toyota Alphard or similar) | Airside Car Transfer.\"\n        ],\n        \"journeys.0.stops.arrival.service_options.6.dropoff\": [\n            \"Car Transfer requires \\\"dropoff\\\". Send it in service_options for service 6.\"\n        ]\n    },\n    \"data\": []\n}"},{"id":"9eebca90-803e-d47b-9ab0-0ae963e4a3e7","name":"422 Validation failed","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"booker_id\": 39083,\n  \"journeys\": []\n}","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings"},"status":"Unprocessable Content","code":422,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"The currency field is required. (and 2 more errors)\",\n    \"status\": 422,\n    \"responseTime\": \"63ms\",\n    \"error_code\": \"validation_failed\",\n    \"errors\": {\n        \"currency\": [\n            \"The currency field is required.\"\n        ],\n        \"confirm\": [\n            \"The confirm field is required.\"\n        ],\n        \"journeys\": [\n            \"At least one journey is required.\"\n        ]\n    },\n    \"data\": []\n}"},{"id":"e94c84fc-2d5f-d10b-61f4-d93ff16228ff","name":"422 Booker is not in your company","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"booker_id\": 1,\n  \"currency\": \"GBP\",\n  \"confirm\": false,\n  \"journeys\": [\n    {\n      \"flight\": \"EK1\",\n      \"manual\": true,\n      \"adult\": 1,\n      \"child\": 0,\n      \"infant\": 0,\n      \"bag_small\": 0,\n      \"bag_medium\": 1,\n      \"bag_large\": 0,\n      \"stops\": {\n        \"arrival\": {\n          \"date\": \"2026-12-31T11:40:00\",\n          \"meeting_date\": \"2026-12-31T11:40:00\",\n          \"terminal_id\": 361,\n          \"connection\": false,\n          \"services\": [1, 4]\n        }\n      }\n    }\n  ],\n  \"settings\": { \"customer_reference\": \"PM-booker-1787600291\" }\n}","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings"},"status":"Unprocessable Content","code":422,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Booker 1 is not a user of your company. Use a booker_id from your own account.\",\n    \"status\": 422,\n    \"responseTime\": \"44ms\",\n    \"error_code\": \"validation_failed\",\n    \"errors\": {\n        \"booker_id\": [\n            \"Booker 1 is not a user of your company. Use a booker_id from your own account.\"\n        ]\n    },\n    \"data\": []\n}"},{"id":"9db3edf6-2501-23f7-ed79-0990aa3511a5","name":"422 Customer reference already used (retry signal)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"booker_id\": 39083,\n  \"currency\": \"GBP\",\n  \"confirm\": false,\n  \"journeys\": [\n    {\n      \"flight\": \"EK1\",\n      \"manual\": true,\n      \"adult\": 1,\n      \"child\": 0,\n      \"infant\": 0,\n      \"bag_small\": 0,\n      \"bag_medium\": 1,\n      \"bag_large\": 0,\n      \"stops\": {\n        \"arrival\": {\n          \"date\": \"2026-12-31T11:40:00\",\n          \"meeting_date\": \"2026-12-31T11:40:00\",\n          \"terminal_id\": 361,\n          \"connection\": false,\n          \"services\": [1, 4]\n        }\n      }\n    }\n  ],\n  \"settings\": { \"customer_reference\": \"PM-1787600290\" }\n}","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings"},"status":"Unprocessable Content","code":422,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"You have already used this customer reference on another booking. References must be unique.\",\n    \"status\": 422,\n    \"responseTime\": \"31ms\",\n    \"error_code\": \"validation_failed\",\n    \"errors\": {\n        \"settings.customer_reference\": [\n            \"You have already used this customer reference on another booking. References must be unique.\"\n        ]\n    },\n    \"data\": []\n}"}],"_postman_id":"db543e7c-5155-4ac5-8293-a8cd498dc110"},{"name":"04 Replace quote","id":"04389b1d-1617-41b3-a7f2-f848f32b2f2f","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\n  \"ref_no\": \"{{booking_ref}}\",\n  \"booker_id\": {{booker_id}},\n  \"journeys\": [\n    {\n      \"adult\": 2,\n      \"child\": 0,\n      \"infant\": 0,\n      \"bag_large\": 0,\n      \"bag_medium\": 2,\n      \"bag_small\": 1,\n      \"passengers\": {\n        \"adult\": [\n          {\n            \"pnr\": \"ABC123\",\n            \"lead\": true,\n            \"signage\": \"John Doe\",\n            \"class_type\": \"Business Class\",\n            \"title\": \"Mr\",\n            \"first_name\": \"John\",\n            \"last_name\": \"Doe\",\n            \"phone\": \"+441234567890\",\n            \"email\": \"john.doe@example.com\"\n          }\n        ],\n        \"child\": [],\n        \"infant\": []\n      },\n      \"flight\": \"EK1\",\n      \"stops\": {\n        \"departure\": {\n          \"meeting_date\": \"2026-12-31T07:45:00\",\n          \"date\": \"2026-12-31T07:45:00\",\n          \"terminal_id\": 127,\n          \"connection\": false,\n          \"services\": [1, 4]\n        },\n        \"arrival\": {\n          \"meeting_date\": \"2026-12-31T11:40:00\",\n          \"date\": \"2026-12-31T11:40:00\",\n          \"terminal_id\": 4,\n          \"connection\": false,\n          \"services\": [1, 2]\n        }\n      }\n    }\n  ],\n  \"currency\": \"GBP\",\n  \"confirm\": false,\n  \"settings\": {\n    \"customer_reference\": \"{{customer_reference}}\"\n  }\n}","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings/{{booking_id}}","description":"<p>Replaces an existing quote and reprices it. Same validation shape as <strong>03 Create quote</strong>.</p>\n<p><strong>This is a full replace, not a partial update.</strong> Everything you omit is dropped, not preserved. Send the complete booking every time.</p>\n<h3 id=\"what-a-replace-resets\">What a replace resets</h3>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Effect</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>ref_no</code></td>\n<td><strong>Regenerated unless you send the existing one back.</strong> The example echoes <code>{{booking_ref}}</code>, which <code>03 Create quote</code> captures for you.</td>\n</tr>\n<tr>\n<td><code>status</code></td>\n<td>Forced back to <code>quote</code>, even for a booking you already confirmed.</td>\n</tr>\n<tr>\n<td><code>billing.status</code></td>\n<td>Reset to <code>0</code> (unpaid), even if it was invoiced.</td>\n</tr>\n<tr>\n<td><code>expires_on</code></td>\n<td>Reset to one week from now.</td>\n</tr>\n<tr>\n<td>journeys, stops, services, passengers</td>\n<td>Rewritten from the payload.</td>\n</tr>\n<tr>\n<td>price</td>\n<td>Recalculated from current rates, not carried over.</td>\n</tr>\n</tbody>\n</table>\n</div><p>Because a confirmed booking silently drops back to <code>quote</code> with its billing cleared, do not replace one after checkout unless you intend exactly that. Nothing is refunded and no email is sent.</p>\n<p><code>confirm</code> is still <code>required|boolean</code> here, and is ignored outright on this endpoint.</p>\n<h3 id=\"responses\">Responses</h3>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th><code>error_code</code></th>\n<th>When</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>200</code></td>\n<td>—</td>\n<td>Replaced. <code>message</code> is <code>Booking Updated successfully!</code></td>\n</tr>\n<tr>\n<td><code>422</code></td>\n<td><code>validation_failed</code></td>\n<td>Payload problems, including an unknown booking id or one belonging to another company, which reports as <code>errors.id</code>.</td>\n</tr>\n<tr>\n<td><code>409</code></td>\n<td><code>booking_cancelled</code></td>\n<td>The booking is cancelled. Terminal, do not retry.</td>\n</tr>\n<tr>\n<td><code>401</code></td>\n<td><code>unauthenticated</code></td>\n<td>Bearer token missing, invalid or expired.</td>\n</tr>\n<tr>\n<td><code>500</code></td>\n<td><code>server_error</code></td>\n<td>Our fault. Nothing was changed.</td>\n</tr>\n</tbody>\n</table>\n</div><p>Another company's booking is deliberately indistinguishable from one that does not exist.</p>\n<p>Ids you send for <code>journeys[].id</code> and <code>stops[].id</code> are honoured only when they already belong to this booking. Anything else is treated as a new row rather than being adopted.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{token}}"}]},"isInherited":true,"source":{"_postman_id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","name":"Global Airport Concierge API v1","type":"collection"}},"urlObject":{"path":["bookings","{{booking_id}}"],"host":["https://api-prod.globalairportconcierge.com/api/v1"],"query":[],"variable":[]}},"response":[{"id":"2ee8c88d-5e98-5952-b237-c10658298d53","name":"200 Replaced (dropped to 2 adults, repriced)","originalRequest":{"method":"PATCH","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"ref_no\": \"GAC-6A8C9DA2A683B\",\n  \"booker_id\": 39083,\n  \"currency\": \"GBP\",\n  \"confirm\": false,\n  \"journeys\": [\n    {\n      \"flight\": \"EK1\",\n      \"manual\": true,\n      \"adult\": 2,\n      \"child\": 0,\n      \"infant\": 0,\n      \"bag_small\": 0,\n      \"bag_medium\": 1,\n      \"bag_large\": 0,\n      \"passengers\": {\n        \"adult\": [\n          {\n            \"pnr\": \"ABC123\",\n            \"lead\": true,\n            \"signage\": \"John Doe\",\n            \"class_type\": \"Economy Class\",\n            \"title\": \"Mr\",\n            \"first_name\": \"John\",\n            \"last_name\": \"Doe\",\n            \"phone\": \"+441234567890\"\n          }\n        ]\n      },\n      \"stops\": {\n        \"arrival\": {\n          \"date\": \"2026-12-31T11:40:00\",\n          \"meeting_date\": \"2026-12-31T11:40:00\",\n          \"terminal_id\": 361,\n          \"connection\": false,\n          \"services\": [1, 4]\n        }\n      }\n    }\n  ],\n  \"settings\": { \"customer_reference\": \"PM-1787600290\" }\n}","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings/34604"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Booking Updated successfully!\",\n    \"status\": 200,\n    \"responseTime\": \"406ms\",\n    \"trace\": [],\n    \"data\": {\n        \"id\": 34604,\n        \"expires_on\": \"2026-08-31T19:38:12+00:00\",\n        \"ref_no\": \"GAC-6A8C9DA2A683B\",\n        \"status\": \"quote\",\n        \"currency\": {\n            \"id\": 3,\n            \"symbol\": \"£\",\n            \"name\": \"British Pound Sterling\",\n            \"symbol_native\": \"£\",\n            \"decimal_digits\": 2,\n            \"rounding\": 0,\n            \"code\": \"GBP\",\n            \"name_plural\": \"British pounds sterling\",\n            \"multiplier\": 0.85\n        },\n        \"journeys\": [\n            {\n                \"flight\": \"EK1\",\n                \"adult\": 2,\n                \"child\": 0,\n                \"infant\": 0,\n                \"bag_small\": 0,\n                \"bag_medium\": 1,\n                \"bag_large\": 0,\n                \"passengers\": {\n                    \"adult\": [\n                        {\n                            \"type\": \"adult\",\n                            \"lead\": true,\n                            \"pnr\": \"ABC123\",\n                            \"signage\": \"John Doe\",\n                            \"class_type\": \"Economy Class\",\n                            \"title\": \"Mr\",\n                            \"first_name\": \"John\",\n                            \"last_name\": \"Doe\",\n                            \"contacts\": [\n                                {\n                                    \"type\": \"phone\",\n                                    \"value\": \"+441234567890\",\n                                    \"contact_person\": \"John Doe\"\n                                }\n                            ]\n                        }\n                    ],\n                    \"child\": [],\n                    \"infant\": []\n                },\n                \"stops\": {\n                    \"arrival\": {\n                        \"airport\": {\n                            \"id\": 113,\n                            \"name\": \"AUH Abu Dhabi International Airport\",\n                            \"iata\": \"AUH\"\n                        },\n                        \"services\": [\n                            {\n                                \"id\": 1,\n                                \"value\": 425,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Meet & Assist\",\n                                \"allocation\": null\n                            },\n                            {\n                                \"id\": 4,\n                                \"value\": 197.2,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Lounge Access\",\n                                \"allocation\": null\n                            }\n                        ],\n                        \"airport_id\": 113\n                    },\n                    \"departure\": null\n                }\n            }\n        ],\n        \"billing\": {\n            \"status\": 0,\n            \"total_discount\": 0,\n            \"add_hrs_charge\": 0,\n            \"surcharge\": 0,\n            \"total_booking_cost\": 622.2,\n            \"grand_total\": 622.2,\n            \"total_paid\": \"0.00\",\n            \"total_refund_amount\": 0,\n            \"tax\": 0,\n            \"tax_rate\": 0\n        },\n        \"settings\": {\n            \"no_surcharge\": false,\n            \"no_additional_hour_charges\": false,\n            \"customer_reference\": \"PM-1787600290\"\n        },\n        \"promo_code\": null,\n        \"created_at\": \"2026-08-24T19:38:10+00:00\",\n        \"currency_id\": 3,\n        \"booker_id\": 39083\n    }\n}"},{"id":"1eae43d5-55f1-d687-a741-d2de181ab529","name":"422 Unknown id, or not your booking","originalRequest":{"method":"PATCH","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"booker_id\": 39083,\n  \"currency\": \"GBP\",\n  \"confirm\": false,\n  \"journeys\": [\n    {\n      \"flight\": \"EK1\",\n      \"manual\": true,\n      \"adult\": 1,\n      \"child\": 0,\n      \"infant\": 0,\n      \"bag_small\": 0,\n      \"bag_medium\": 1,\n      \"bag_large\": 0,\n      \"stops\": {\n        \"arrival\": {\n          \"date\": \"2026-12-31T11:40:00\",\n          \"meeting_date\": \"2026-12-31T11:40:00\",\n          \"terminal_id\": 361,\n          \"connection\": false,\n          \"services\": [1, 4]\n        }\n      }\n    }\n  ],\n  \"settings\": { \"customer_reference\": \"PM-foreign-1787600292\" }\n}","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings/99999999"},"status":"Unprocessable Content","code":422,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"No booking found with that id. It may not exist, or it may belong to another company.\",\n    \"status\": 422,\n    \"responseTime\": \"33ms\",\n    \"error_code\": \"validation_failed\",\n    \"errors\": {\n        \"id\": [\n            \"No booking found with that id. It may not exist, or it may belong to another company.\"\n        ]\n    },\n    \"data\": []\n}"}],"_postman_id":"04389b1d-1617-41b3-a7f2-f848f32b2f2f"},{"name":"07 Cancel booking","id":"4485e5c2-9630-47bf-8d04-8ff8f97b4261","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"DELETE","header":[],"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings/{{booking_id}}","description":"<p>Cancels a quote or a confirmed booking. No request body.</p>\n<p>The booking is <strong>not</strong> deleted. Its status becomes <code>cancelled</code> and it stays readable through all three lookup endpoints. The response is the full cancelled booking.</p>\n<h3 id=\"side-effects\">Side effects</h3>\n<ul>\n<li>A cancellation email goes to the booker.</li>\n<li>Our operations team is notified.</li>\n<li><strong>No refund is issued and no invoice is voided.</strong> Cancelling a confirmed, invoiced booking leaves the money side untouched, so raise anything financial with GAC separately.</li>\n</ul>\n<h3 id=\"responses\">Responses</h3>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th><code>error_code</code></th>\n<th>When</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>200</code></td>\n<td>—</td>\n<td>Cancelled. <code>message</code> is <code>Booking has been canceled!</code></td>\n</tr>\n<tr>\n<td><code>404</code></td>\n<td><code>booking_not_found</code></td>\n<td>Unknown id, or a booking that is not yours.</td>\n</tr>\n<tr>\n<td><code>401</code></td>\n<td><code>unauthenticated</code></td>\n<td>Bearer token missing, invalid or expired.</td>\n</tr>\n<tr>\n<td><code>500</code></td>\n<td><code>server_error</code></td>\n<td>Our fault. Nothing was changed.</td>\n</tr>\n</tbody>\n</table>\n</div><p>Works from any status, including one already cancelled. A second cancel returns <code>200</code> again and the booking is unchanged, <strong>but the cancellation email is sent again</strong>, so do not retry blindly. Check <code>status</code> first with <strong>09 Get booking by ID</strong> if you are not sure.</p>\n<p>Cancelling is final as far as this API is concerned. There is no un-cancel; every other endpoint then answers <code>409 booking_cancelled</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{token}}"}]},"isInherited":true,"source":{"_postman_id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","name":"Global Airport Concierge API v1","type":"collection"}},"urlObject":{"path":["bookings","{{booking_id}}"],"host":["https://api-prod.globalairportconcierge.com/api/v1"],"query":[],"variable":[]}},"response":[{"id":"90b2c59d-a461-11f1-6a32-bc33e7338ec2","name":"200 Cancelled","originalRequest":{"method":"DELETE","header":[],"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings/{{booking_id}}","description":"Cancels a quote or a confirmed booking. No request body.\n\nThe booking is **not** deleted. Its status becomes `cancelled` and it stays readable through all three lookup endpoints. The response is the full cancelled booking.\n\n### Side effects\n\n- A cancellation email goes to the booker.\n- Our operations team is notified.\n- **No refund is issued and no invoice is voided.** Cancelling a confirmed, invoiced booking leaves the money side untouched, so raise anything financial with GAC separately.\n\n### Responses\n\n| Status | `error_code` | When |\n| --- | --- | --- |\n| `200` | — | Cancelled. `message` is `Booking has been canceled!` |\n| `404` | `booking_not_found` | Unknown id, or a booking that is not yours. |\n| `401` | `unauthenticated` | Bearer token missing, invalid or expired. |\n| `500` | `server_error` | Our fault. Nothing was changed. |\n\nWorks from any status, including one already cancelled. A second cancel returns `200` again and the booking is unchanged, **but the cancellation email is sent again**, so do not retry blindly. Check `status` first with **09 Get booking by ID** if you are not sure.\n\nCancelling is final as far as this API is concerned. There is no un-cancel; every other endpoint then answers `409 booking_cancelled`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Booking has been canceled!\",\n    \"status\": 200,\n    \"responseTime\": \"315ms\",\n    \"trace\": [],\n    \"data\": {\n        \"id\": 34605,\n        \"expires_on\": \"2026-08-31T19:38:11+00:00\",\n        \"ref_no\": \"GAC-6A8C9DA39E4A8\",\n        \"status\": \"cancelled\",\n        \"currency\": {\n            \"id\": 3,\n            \"symbol\": \"£\",\n            \"name\": \"British Pound Sterling\",\n            \"symbol_native\": \"£\",\n            \"decimal_digits\": 2,\n            \"rounding\": 0,\n            \"code\": \"GBP\",\n            \"name_plural\": \"British pounds sterling\",\n            \"multiplier\": 0.85\n        },\n        \"journeys\": [\n            {\n                \"flight\": \"EK1\",\n                \"adult\": 2,\n                \"child\": 0,\n                \"infant\": 0,\n                \"bag_small\": 0,\n                \"bag_medium\": 1,\n                \"bag_large\": 0,\n                \"passengers\": {\n                    \"adult\": [\n                        {\n                            \"type\": \"adult\",\n                            \"lead\": true,\n                            \"pnr\": \"ABC123\",\n                            \"signage\": \"John Doe\",\n                            \"class_type\": \"Economy Class\",\n                            \"title\": \"Mr\",\n                            \"first_name\": \"John\",\n                            \"last_name\": \"Doe\",\n                            \"contacts\": [\n                                {\n                                    \"type\": \"phone\",\n                                    \"value\": \"+441234567890\",\n                                    \"contact_person\": \"John Doe\"\n                                }\n                            ]\n                        }\n                    ],\n                    \"child\": [],\n                    \"infant\": []\n                },\n                \"stops\": {\n                    \"arrival\": {\n                        \"airport\": {\n                            \"id\": 113,\n                            \"name\": \"AUH Abu Dhabi International Airport\",\n                            \"iata\": \"AUH\"\n                        },\n                        \"services\": [\n                            {\n                                \"id\": 1,\n                                \"value\": 425,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Meet & Assist\",\n                                \"allocation\": null\n                            },\n                            {\n                                \"id\": 4,\n                                \"value\": 197.2,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Lounge Access\",\n                                \"allocation\": null\n                            }\n                        ],\n                        \"airport_id\": 113\n                    },\n                    \"departure\": null\n                }\n            }\n        ],\n        \"billing\": {\n            \"status\": 0,\n            \"total_discount\": 0,\n            \"add_hrs_charge\": 0,\n            \"surcharge\": 0,\n            \"total_booking_cost\": 622.2,\n            \"grand_total\": 622.2,\n            \"total_paid\": \"0.00\",\n            \"total_refund_amount\": 0,\n            \"tax\": 0,\n            \"tax_rate\": 0\n        },\n        \"settings\": {\n            \"no_surcharge\": false,\n            \"no_additional_hour_charges\": false,\n            \"customer_reference\": \"PM-1787600291-b\"\n        },\n        \"promo_code\": null,\n        \"created_at\": \"2026-08-24T19:38:11+00:00\",\n        \"currency_id\": 3,\n        \"booker_id\": 39083\n    }\n}"},{"id":"d2e3e062-671f-2695-ed1a-6de98594b181","name":"404 Unknown id, or not your booking","originalRequest":{"method":"DELETE","header":[],"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings/{{booking_id}}","description":"Cancels a quote or a confirmed booking. No request body.\n\nThe booking is **not** deleted. Its status becomes `cancelled` and it stays readable through all three lookup endpoints. The response is the full cancelled booking.\n\n### Side effects\n\n- A cancellation email goes to the booker.\n- Our operations team is notified.\n- **No refund is issued and no invoice is voided.** Cancelling a confirmed, invoiced booking leaves the money side untouched, so raise anything financial with GAC separately.\n\n### Responses\n\n| Status | `error_code` | When |\n| --- | --- | --- |\n| `200` | — | Cancelled. `message` is `Booking has been canceled!` |\n| `404` | `booking_not_found` | Unknown id, or a booking that is not yours. |\n| `401` | `unauthenticated` | Bearer token missing, invalid or expired. |\n| `500` | `server_error` | Our fault. Nothing was changed. |\n\nWorks from any status, including one already cancelled. A second cancel returns `200` again and the booking is unchanged, **but the cancellation email is sent again**, so do not retry blindly. Check `status` first with **09 Get booking by ID** if you are not sure.\n\nCancelling is final as far as this API is concerned. There is no un-cancel; every other endpoint then answers `409 booking_cancelled`."},"status":"Not Found","code":404,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"No booking found with id 99999999. It may not exist, or it may belong to another company.\",\n    \"status\": 404,\n    \"responseTime\": \"24ms\",\n    \"error_code\": \"booking_not_found\",\n    \"data\": {\n        \"errors\": []\n    }\n}"}],"_postman_id":"4485e5c2-9630-47bf-8d04-8ff8f97b4261"},{"name":"05 Reprice quote","id":"0abfb0db-abae-4b8b-8d5d-1fb5d6958fc2","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings/{{booking_id}}/recalculate","description":"<p>Reprices a booking against current rates and extends <code>expires_on</code> by another week. No request body.</p>\n<p>Use it when a quote has expired and you want to confirm it, or when you want a fresh price without changing anything about the itinerary.</p>\n<p>The itinerary is untouched: journeys, stops, services and passengers stay exactly as they are. Only the prices, the totals and <code>expires_on</code> move.</p>\n<h3 id=\"responses\">Responses</h3>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th><code>error_code</code></th>\n<th>When</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>200</code></td>\n<td>—</td>\n<td>Repriced. <code>message</code> is <code>Booking has been recalculated!</code></td>\n</tr>\n<tr>\n<td><code>404</code></td>\n<td><code>booking_not_found</code></td>\n<td>Unknown id, or a booking that is not yours.</td>\n</tr>\n<tr>\n<td><code>404</code></td>\n<td><code>endpoint_not_found</code></td>\n<td>A non-numeric id never reaches this endpoint; the route only matches digits.</td>\n</tr>\n<tr>\n<td><code>409</code></td>\n<td><code>booking_cancelled</code></td>\n<td>The booking is cancelled. Terminal, do not retry.</td>\n</tr>\n<tr>\n<td><code>401</code></td>\n<td><code>unauthenticated</code></td>\n<td>Bearer token missing, invalid or expired.</td>\n</tr>\n<tr>\n<td><code>500</code></td>\n<td><code>server_error</code></td>\n<td>Our fault. Nothing was changed.</td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>Do not reprice a confirmed booking.</strong> There is no guard against it. The status stays <code>booking</code>, but <code>billing.status</code> resets to <code>0</code> and <code>grand_total</code> is rewritten, so an already-invoiced booking ends up looking unpaid at a possibly different price. Reprice quotes only.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{token}}"}]},"isInherited":true,"source":{"_postman_id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","name":"Global Airport Concierge API v1","type":"collection"}},"urlObject":{"path":["bookings","{{booking_id}}","recalculate"],"host":["https://api-prod.globalairportconcierge.com/api/v1"],"query":[],"variable":[]}},"response":[{"id":"c8da2895-3470-b590-a995-c2d23310abf9","name":"200 Repriced, expiry extended","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings/{{booking_id}}/recalculate","description":"Reprices a booking against current rates and extends `expires_on` by another week. No request body.\n\nUse it when a quote has expired and you want to confirm it, or when you want a fresh price without changing anything about the itinerary.\n\nThe itinerary is untouched: journeys, stops, services and passengers stay exactly as they are. Only the prices, the totals and `expires_on` move.\n\n### Responses\n\n| Status | `error_code` | When |\n| --- | --- | --- |\n| `200` | — | Repriced. `message` is `Booking has been recalculated!` |\n| `404` | `booking_not_found` | Unknown id, or a booking that is not yours. |\n| `404` | `endpoint_not_found` | A non-numeric id never reaches this endpoint; the route only matches digits. |\n| `409` | `booking_cancelled` | The booking is cancelled. Terminal, do not retry. |\n| `401` | `unauthenticated` | Bearer token missing, invalid or expired. |\n| `500` | `server_error` | Our fault. Nothing was changed. |\n\n**Do not reprice a confirmed booking.** There is no guard against it. The status stays `booking`, but `billing.status` resets to `0` and `grand_total` is rewritten, so an already-invoiced booking ends up looking unpaid at a possibly different price. Reprice quotes only."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Booking has been recalculated!\",\n    \"status\": 200,\n    \"responseTime\": \"495ms\",\n    \"trace\": [],\n    \"data\": {\n        \"id\": 34604,\n        \"expires_on\": \"2026-08-31T19:38:12+00:00\",\n        \"ref_no\": \"GAC-6A8C9DA2A683B\",\n        \"status\": \"quote\",\n        \"currency\": {\n            \"id\": 3,\n            \"symbol\": \"£\",\n            \"name\": \"British Pound Sterling\",\n            \"symbol_native\": \"£\",\n            \"decimal_digits\": 2,\n            \"rounding\": 0,\n            \"code\": \"GBP\",\n            \"name_plural\": \"British pounds sterling\",\n            \"multiplier\": 0.85\n        },\n        \"journeys\": [\n            {\n                \"flight\": \"EK1\",\n                \"adult\": 4,\n                \"child\": 0,\n                \"infant\": 0,\n                \"bag_small\": 0,\n                \"bag_medium\": 1,\n                \"bag_large\": 0,\n                \"passengers\": {\n                    \"adult\": [\n                        {\n                            \"type\": \"adult\",\n                            \"lead\": true,\n                            \"pnr\": \"ABC123\",\n                            \"signage\": \"John Doe\",\n                            \"class_type\": \"Economy Class\",\n                            \"title\": \"Mr\",\n                            \"first_name\": \"John\",\n                            \"last_name\": \"Doe\",\n                            \"contacts\": [\n                                {\n                                    \"type\": \"phone\",\n                                    \"value\": \"+441234567890\",\n                                    \"contact_person\": \"John Doe\"\n                                }\n                            ]\n                        }\n                    ],\n                    \"child\": [],\n                    \"infant\": []\n                },\n                \"stops\": {\n                    \"arrival\": {\n                        \"airport\": {\n                            \"id\": 113,\n                            \"name\": \"AUH Abu Dhabi International Airport\",\n                            \"iata\": \"AUH\"\n                        },\n                        \"services\": [\n                            {\n                                \"id\": 1,\n                                \"value\": 637.5,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Meet & Assist\",\n                                \"allocation\": null\n                            },\n                            {\n                                \"id\": 4,\n                                \"value\": 393.55,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Lounge Access\",\n                                \"allocation\": null\n                            }\n                        ],\n                        \"airport_id\": 113\n                    },\n                    \"departure\": null\n                }\n            }\n        ],\n        \"billing\": {\n            \"status\": 0,\n            \"total_discount\": 0,\n            \"add_hrs_charge\": 0,\n            \"surcharge\": 0,\n            \"total_booking_cost\": 1031.05,\n            \"grand_total\": 1031.05,\n            \"total_paid\": \"0.00\",\n            \"total_refund_amount\": 0,\n            \"tax\": 0,\n            \"tax_rate\": 0\n        },\n        \"settings\": {\n            \"no_surcharge\": false,\n            \"no_additional_hour_charges\": false,\n            \"customer_reference\": \"PM-1787600290\"\n        },\n        \"promo_code\": null,\n        \"created_at\": \"2026-08-24T19:38:10+00:00\",\n        \"currency_id\": 3,\n        \"booker_id\": 39083\n    }\n}"},{"id":"a1408006-e936-d9f3-415b-d7277c1760de","name":"404 Unknown id, or not your booking","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings/{{booking_id}}/recalculate","description":"Reprices a booking against current rates and extends `expires_on` by another week. No request body.\n\nUse it when a quote has expired and you want to confirm it, or when you want a fresh price without changing anything about the itinerary.\n\nThe itinerary is untouched: journeys, stops, services and passengers stay exactly as they are. Only the prices, the totals and `expires_on` move.\n\n### Responses\n\n| Status | `error_code` | When |\n| --- | --- | --- |\n| `200` | — | Repriced. `message` is `Booking has been recalculated!` |\n| `404` | `booking_not_found` | Unknown id, or a booking that is not yours. |\n| `404` | `endpoint_not_found` | A non-numeric id never reaches this endpoint; the route only matches digits. |\n| `409` | `booking_cancelled` | The booking is cancelled. Terminal, do not retry. |\n| `401` | `unauthenticated` | Bearer token missing, invalid or expired. |\n| `500` | `server_error` | Our fault. Nothing was changed. |\n\n**Do not reprice a confirmed booking.** There is no guard against it. The status stays `booking`, but `billing.status` resets to `0` and `grand_total` is rewritten, so an already-invoiced booking ends up looking unpaid at a possibly different price. Reprice quotes only."},"status":"Not Found","code":404,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"No booking found with id 99999999. It may not exist, or it may belong to another company.\",\n    \"status\": 404,\n    \"responseTime\": \"22ms\",\n    \"error_code\": \"booking_not_found\",\n    \"data\": {\n        \"errors\": []\n    }\n}"},{"id":"05533163-b1a4-3a75-3bf9-2ea2055eb5b7","name":"409 Booking is cancelled","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings/{{booking_id}}/recalculate","description":"Reprices a booking against current rates and extends `expires_on` by another week. No request body.\n\nUse it when a quote has expired and you want to confirm it, or when you want a fresh price without changing anything about the itinerary.\n\nThe itinerary is untouched: journeys, stops, services and passengers stay exactly as they are. Only the prices, the totals and `expires_on` move.\n\n### Responses\n\n| Status | `error_code` | When |\n| --- | --- | --- |\n| `200` | — | Repriced. `message` is `Booking has been recalculated!` |\n| `404` | `booking_not_found` | Unknown id, or a booking that is not yours. |\n| `404` | `endpoint_not_found` | A non-numeric id never reaches this endpoint; the route only matches digits. |\n| `409` | `booking_cancelled` | The booking is cancelled. Terminal, do not retry. |\n| `401` | `unauthenticated` | Bearer token missing, invalid or expired. |\n| `500` | `server_error` | Our fault. Nothing was changed. |\n\n**Do not reprice a confirmed booking.** There is no guard against it. The status stays `booking`, but `billing.status` resets to `0` and `grand_total` is rewritten, so an already-invoiced booking ends up looking unpaid at a possibly different price. Reprice quotes only."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"This booking has been cancelled and can no longer be modified.\",\n    \"status\": 409,\n    \"responseTime\": \"89ms\",\n    \"error_code\": \"booking_cancelled\",\n    \"data\": {\n        \"errors\": []\n    }\n}"}],"_postman_id":"0abfb0db-abae-4b8b-8d5d-1fb5d6958fc2"},{"name":"06 Confirm quote","id":"9d4a223c-7e23-4042-985b-200cc6cdf818","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings/{{booking_id}}/checkout","description":"<p>Turns a quote into a confirmed booking. This is the step that commits the sale. No request body.</p>\n<p>On success the booking moves from <code>quote</code> to <code>booking</code>, <code>billing.status</code> becomes <code>3</code> (invoiced), and a confirmation email goes to the booker. Where the booking carries tax, a numbered VAT invoice is issued at this moment.</p>\n<p>This is the only endpoint that confirms. The <code>confirm</code> flag on <strong>03 Create quote</strong> does not do it.</p>\n<h3 id=\"requirements\">Requirements</h3>\n<p>All of these must hold:</p>\n<ul>\n<li>status is <code>quote</code>, not already <code>booking</code> and not <code>cancelled</code></li>\n<li><code>expires_on</code> is in the future; reprice with <strong>05 Reprice quote</strong> if not</li>\n<li><code>grand_total</code> is at least 1</li>\n<li>your company is set up for invoice terms</li>\n</ul>\n<h3 id=\"responses\">Responses</h3>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th><code>error_code</code></th>\n<th>When</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>200</code></td>\n<td>—</td>\n<td>Confirmed. <code>message</code> is <code>Booking has been confirmed!</code></td>\n</tr>\n<tr>\n<td><code>409</code></td>\n<td><code>booking_already_confirmed</code></td>\n<td>Already a <code>booking</code>. Read it back rather than confirming again.</td>\n</tr>\n<tr>\n<td><code>409</code></td>\n<td><code>quote_expired</code></td>\n<td>Reprice with <strong>05 Reprice quote</strong>, then confirm.</td>\n</tr>\n<tr>\n<td><code>409</code></td>\n<td><code>booking_cancelled</code></td>\n<td>Cancelled. Terminal, do not retry.</td>\n</tr>\n<tr>\n<td><code>409</code></td>\n<td><code>payment_incomplete</code></td>\n<td>A card payment has not settled. Retry later.</td>\n</tr>\n<tr>\n<td><code>409</code></td>\n<td><code>booking_not_confirmable</code></td>\n<td>Some other state blocks it. Read the booking to see why.</td>\n</tr>\n<tr>\n<td><code>422</code></td>\n<td><code>booking_total_too_low</code></td>\n<td>No chargeable total. Check a service is attached and priced.</td>\n</tr>\n<tr>\n<td><code>403</code></td>\n<td><code>invoice_terms_required</code></td>\n<td>Your company is not on invoice terms. Contact GAC customer service.</td>\n</tr>\n<tr>\n<td><code>404</code></td>\n<td><code>booking_not_found</code></td>\n<td>Unknown id, or a booking that is not yours.</td>\n</tr>\n<tr>\n<td><code>500</code></td>\n<td><code>server_error</code></td>\n<td>Our fault.</td>\n</tr>\n</tbody>\n</table>\n</div><p>Note that <code>data</code> here is <strong>not</strong> the booking. It is a small acknowledgement:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{ \"success\": true, \"message\": \"Booking is Confirmed.\" }\n</code></pre>\n<p>Fetch the booking with <strong>09 Get booking by ID</strong> if you need the confirmed record back.</p>\n<p>Confirming is not reversible through this API. <strong>07 Cancel booking</strong> will cancel a confirmed booking, but nothing is refunded and no invoice is voided.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{token}}"}]},"isInherited":true,"source":{"_postman_id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","name":"Global Airport Concierge API v1","type":"collection"}},"urlObject":{"path":["bookings","{{booking_id}}","checkout"],"host":["https://api-prod.globalairportconcierge.com/api/v1"],"query":[],"variable":[]}},"response":[{"id":"e446196b-34ce-69fa-c459-000a5334b0f8","name":"200 Confirmed","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings/{{booking_id}}/checkout","description":"Turns a quote into a confirmed booking. This is the step that commits the sale. No request body.\n\nOn success the booking moves from `quote` to `booking`, `billing.status` becomes `3` (invoiced), and a confirmation email goes to the booker. Where the booking carries tax, a numbered VAT invoice is issued at this moment.\n\nThis is the only endpoint that confirms. The `confirm` flag on **03 Create quote** does not do it.\n\n### Requirements\n\nAll of these must hold:\n\n- status is `quote`, not already `booking` and not `cancelled`\n- `expires_on` is in the future; reprice with **05 Reprice quote** if not\n- `grand_total` is at least 1\n- your company is set up for invoice terms\n\n### Responses\n\n| Status | `error_code` | When |\n| --- | --- | --- |\n| `200` | — | Confirmed. `message` is `Booking has been confirmed!` |\n| `409` | `booking_already_confirmed` | Already a `booking`. Read it back rather than confirming again. |\n| `409` | `quote_expired` | Reprice with **05 Reprice quote**, then confirm. |\n| `409` | `booking_cancelled` | Cancelled. Terminal, do not retry. |\n| `409` | `payment_incomplete` | A card payment has not settled. Retry later. |\n| `409` | `booking_not_confirmable` | Some other state blocks it. Read the booking to see why. |\n| `422` | `booking_total_too_low` | No chargeable total. Check a service is attached and priced. |\n| `403` | `invoice_terms_required` | Your company is not on invoice terms. Contact GAC customer service. |\n| `404` | `booking_not_found` | Unknown id, or a booking that is not yours. |\n| `500` | `server_error` | Our fault. |\n\nNote that `data` here is **not** the booking. It is a small acknowledgement:\n\n```json\n{ \"success\": true, \"message\": \"Booking is Confirmed.\" }\n```\n\nFetch the booking with **09 Get booking by ID** if you need the confirmed record back.\n\nConfirming is not reversible through this API. **07 Cancel booking** will cancel a confirmed booking, but nothing is refunded and no invoice is voided."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Booking has been confirmed!\",\n    \"status\": 200,\n    \"responseTime\": \"804ms\",\n    \"trace\": [],\n    \"data\": {\n        \"success\": true,\n        \"message\": \"Booking is Confirmed.\"\n    }\n}"},{"id":"f2fa6ab5-d270-2bc8-eb95-912e85c9e147","name":"409 Already confirmed","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings/{{booking_id}}/checkout","description":"Turns a quote into a confirmed booking. This is the step that commits the sale. No request body.\n\nOn success the booking moves from `quote` to `booking`, `billing.status` becomes `3` (invoiced), and a confirmation email goes to the booker. Where the booking carries tax, a numbered VAT invoice is issued at this moment.\n\nThis is the only endpoint that confirms. The `confirm` flag on **03 Create quote** does not do it.\n\n### Requirements\n\nAll of these must hold:\n\n- status is `quote`, not already `booking` and not `cancelled`\n- `expires_on` is in the future; reprice with **05 Reprice quote** if not\n- `grand_total` is at least 1\n- your company is set up for invoice terms\n\n### Responses\n\n| Status | `error_code` | When |\n| --- | --- | --- |\n| `200` | — | Confirmed. `message` is `Booking has been confirmed!` |\n| `409` | `booking_already_confirmed` | Already a `booking`. Read it back rather than confirming again. |\n| `409` | `quote_expired` | Reprice with **05 Reprice quote**, then confirm. |\n| `409` | `booking_cancelled` | Cancelled. Terminal, do not retry. |\n| `409` | `payment_incomplete` | A card payment has not settled. Retry later. |\n| `409` | `booking_not_confirmable` | Some other state blocks it. Read the booking to see why. |\n| `422` | `booking_total_too_low` | No chargeable total. Check a service is attached and priced. |\n| `403` | `invoice_terms_required` | Your company is not on invoice terms. Contact GAC customer service. |\n| `404` | `booking_not_found` | Unknown id, or a booking that is not yours. |\n| `500` | `server_error` | Our fault. |\n\nNote that `data` here is **not** the booking. It is a small acknowledgement:\n\n```json\n{ \"success\": true, \"message\": \"Booking is Confirmed.\" }\n```\n\nFetch the booking with **09 Get booking by ID** if you need the confirmed record back.\n\nConfirming is not reversible through this API. **07 Cancel booking** will cancel a confirmed booking, but nothing is refunded and no invoice is voided."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"This booking has already been confirmed. Fetch it with GET /bookings/{id} to see its current state.\",\n    \"status\": 409,\n    \"responseTime\": \"183ms\",\n    \"error_code\": \"booking_already_confirmed\",\n    \"data\": {\n        \"errors\": []\n    }\n}"},{"id":"fbff63bd-b6d7-d22a-1ed8-00374082cc0b","name":"409 Quote expired","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings/{{booking_id}}/checkout","description":"Turns a quote into a confirmed booking. This is the step that commits the sale. No request body.\n\nOn success the booking moves from `quote` to `booking`, `billing.status` becomes `3` (invoiced), and a confirmation email goes to the booker. Where the booking carries tax, a numbered VAT invoice is issued at this moment.\n\nThis is the only endpoint that confirms. The `confirm` flag on **03 Create quote** does not do it.\n\n### Requirements\n\nAll of these must hold:\n\n- status is `quote`, not already `booking` and not `cancelled`\n- `expires_on` is in the future; reprice with **05 Reprice quote** if not\n- `grand_total` is at least 1\n- your company is set up for invoice terms\n\n### Responses\n\n| Status | `error_code` | When |\n| --- | --- | --- |\n| `200` | — | Confirmed. `message` is `Booking has been confirmed!` |\n| `409` | `booking_already_confirmed` | Already a `booking`. Read it back rather than confirming again. |\n| `409` | `quote_expired` | Reprice with **05 Reprice quote**, then confirm. |\n| `409` | `booking_cancelled` | Cancelled. Terminal, do not retry. |\n| `409` | `payment_incomplete` | A card payment has not settled. Retry later. |\n| `409` | `booking_not_confirmable` | Some other state blocks it. Read the booking to see why. |\n| `422` | `booking_total_too_low` | No chargeable total. Check a service is attached and priced. |\n| `403` | `invoice_terms_required` | Your company is not on invoice terms. Contact GAC customer service. |\n| `404` | `booking_not_found` | Unknown id, or a booking that is not yours. |\n| `500` | `server_error` | Our fault. |\n\nNote that `data` here is **not** the booking. It is a small acknowledgement:\n\n```json\n{ \"success\": true, \"message\": \"Booking is Confirmed.\" }\n```\n\nFetch the booking with **09 Get booking by ID** if you need the confirmed record back.\n\nConfirming is not reversible through this API. **07 Cancel booking** will cancel a confirmed booking, but nothing is refunded and no invoice is voided."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"This quote has expired. Call POST /bookings/{id}/recalculate to reprice it, then confirm again.\",\n    \"status\": 409,\n    \"responseTime\": \"165ms\",\n    \"error_code\": \"quote_expired\",\n    \"data\": {\n        \"errors\": []\n    }\n}"}],"_postman_id":"9d4a223c-7e23-4042-985b-200cc6cdf818"},{"name":"08 List bookings","id":"7d19bb2b-922d-4a1b-8835-4ad2ca73c955","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings?page=1&limit=25","description":"<p>Lists your bookings, newest first. Only your own company's bookings are ever returned.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>Type</th>\n<th>Default</th>\n<th>Notes</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>integer</td>\n<td><code>1</code></td>\n<td></td>\n</tr>\n<tr>\n<td><code>limit</code></td>\n<td>integer</td>\n<td><code>25</code></td>\n<td>Maximum <code>100</code>.</td>\n</tr>\n<tr>\n<td><code>query</code></td>\n<td>string</td>\n<td>—</td>\n<td>A <strong>JSON-encoded object</strong>, not a plain search term. Max 5000 characters.</td>\n</tr>\n<tr>\n<td><code>updated_since</code></td>\n<td>ISO-8601 datetime</td>\n<td>—</td>\n<td>Only bookings changed at or after this moment.</td>\n</tr>\n</tbody>\n</table>\n</div><h3 id=\"the-query-parameter\">The query parameter</h3>\n<p><code>query</code> must be JSON. Send it URL-encoded, for example <code>query={\"text\":\"GAC-6A8C\"}</code>.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Key</th>\n<th>Type</th>\n<th>Matches</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>text</code></td>\n<td>string</td>\n<td>Booking reference, passenger PNR, passenger name, booker name, booker email, or flight number. Partial matches count.</td>\n</tr>\n<tr>\n<td><code>airports</code></td>\n<td>array of ids</td>\n<td>Bookings touching those airports.</td>\n</tr>\n<tr>\n<td><code>services</code></td>\n<td>array of ids</td>\n<td>Bookings containing those services.</td>\n</tr>\n<tr>\n<td><code>booking_status</code></td>\n<td>array of strings</td>\n<td><code>quote</code>, <code>booking</code>, <code>cancelled</code>.</td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>If <code>query</code> is not valid JSON it is ignored silently</strong> and you get everything back, which looks like a filter that matched broadly rather than one that failed. Check your encoding if the count looks wrong.</p>\n<h3 id=\"catching-up-with-updated_since\">Catching up with updated_since</h3>\n<p><code>updated_since</code> filters on when the booking last changed, not when it was created, so it picks up amendments and cancellations as well as new bookings. Pass the timestamp of your last successful sync:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>GET /bookings?updated_since=2026-09-08T09:00:00Z&amp;limit=100\n</code></pre><p>Use the server's own <code>updated_at</code> from the last row you processed as the next watermark rather than your own clock, so a difference between your clock and ours cannot skip a booking. Overlapping by a minute is cheap and safe: results are stable, so re-reading a booking you already have costs one comparison.</p>\n<p>This endpoint has <strong>no created-date filter</strong>, only <code>updated_since</code>. If you want to know about changes as they happen rather than on a schedule, ask GAC to register a webhook endpoint for you instead: see <strong>Webhooks</strong> in the collection overview.</p>\n<h3 id=\"response\">Response</h3>\n<p>The paginated envelope. Note that <code>trace</code> is omitted entirely on this endpoint, unlike every other one.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">\"pagination\": { \"total_count\": 7, \"total_pages\": 4, \"current_page\": 1, \"limit\": 2 }\n</code></pre>\n<p>Each row is a summary, not the full booking: <code>id</code>, <code>ref_no</code>, <code>status</code>, <code>grand_total</code>, <code>currency</code>, <code>booker</code>, <code>services[]</code>, <code>lead_passenger</code>, <code>bags</code>, <code>pax</code>. Fetch the full record with <strong>09 Get booking by ID</strong>.</p>\n<p>Two details that catch people. <code>bags</code> and <code>pax</code> come from the <strong>first journey only</strong>, so a multi-journey booking under-reports here. And <code>services[].id</code> in this response is a line-item id, not the service id you send when creating a quote; match on <code>service_name</code> instead.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th><code>error_code</code></th>\n<th>When</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>200</code></td>\n<td>—</td>\n<td>Always, even with no matches. <code>message</code> is <code>Successful.</code></td>\n</tr>\n<tr>\n<td><code>422</code></td>\n<td><code>validation_failed</code></td>\n<td><code>limit</code> above 100, <code>page</code> below 1, <code>query</code> over 5000 characters, or <code>updated_since</code> not a parseable date.</td>\n</tr>\n<tr>\n<td><code>401</code></td>\n<td><code>unauthenticated</code></td>\n<td>Bearer token missing, invalid or expired.</td>\n</tr>\n<tr>\n<td><code>500</code></td>\n<td><code>server_error</code></td>\n<td>Our fault.</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{token}}"}]},"isInherited":true,"source":{"_postman_id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","name":"Global Airport Concierge API v1","type":"collection"}},"urlObject":{"path":["bookings"],"host":["https://api-prod.globalairportconcierge.com/api/v1"],"query":[{"description":{"content":"<p>Page number. Defaults to 1.</p>\n","type":"text/plain"},"key":"page","value":"1"},{"description":{"content":"<p>Results per page. Defaults to 25, maximum 100.</p>\n","type":"text/plain"},"key":"limit","value":"25"},{"disabled":true,"description":{"content":"<p>JSON-encoded filter object. See the documentation for the supported keys.</p>\n","type":"text/plain"},"key":"query","value":"{\"text\":\"GAC-\"}"},{"disabled":true,"description":{"content":"<p>ISO-8601. Only bookings changed at or after this moment, including amendments and cancellations.</p>\n","type":"text/plain"},"key":"updated_since","value":"2026-09-08T09:00:00Z"}],"variable":[]}},"response":[{"id":"b9f9ae45-ecfb-690b-ac06-30e5572e7831","name":"200 Page of bookings","originalRequest":{"method":"GET","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":{"raw":"https://api-prod.globalairportconcierge.com/api/v1/bookings?page=1&limit=25","host":["https://api-prod.globalairportconcierge.com/api/v1"],"path":["bookings"],"query":[{"value":"1","key":"page","description":"Page number. Defaults to 1."},{"value":"25","key":"limit","description":"Results per page. Defaults to 25, maximum 100."},{"value":"{\"text\":\"GAC-\"}","key":"query","description":"JSON-encoded filter object. See the documentation for the supported keys.","disabled":true},{"value":"2026-09-08T09:00:00Z","key":"updated_since","description":"ISO-8601. Only bookings changed at or after this moment, including amendments and cancellations.","disabled":true}]},"description":"Lists your bookings, newest first. Only your own company's bookings are ever returned.\n\n| Parameter | Type | Default | Notes |\n| --- | --- | --- | --- |\n| `page` | integer | `1` | |\n| `limit` | integer | `25` | Maximum `100`. |\n| `query` | string | — | A **JSON-encoded object**, not a plain search term. Max 5000 characters. |\n| `updated_since` | ISO-8601 datetime | — | Only bookings changed at or after this moment. |\n\n### The query parameter\n\n`query` must be JSON. Send it URL-encoded, for example `query={\"text\":\"GAC-6A8C\"}`.\n\n| Key | Type | Matches |\n| --- | --- | --- |\n| `text` | string | Booking reference, passenger PNR, passenger name, booker name, booker email, or flight number. Partial matches count. |\n| `airports` | array of ids | Bookings touching those airports. |\n| `services` | array of ids | Bookings containing those services. |\n| `booking_status` | array of strings | `quote`, `booking`, `cancelled`. |\n\n**If `query` is not valid JSON it is ignored silently** and you get everything back, which looks like a filter that matched broadly rather than one that failed. Check your encoding if the count looks wrong.\n\n### Catching up with updated_since\n\n`updated_since` filters on when the booking last changed, not when it was created, so it picks up amendments and cancellations as well as new bookings. Pass the timestamp of your last successful sync:\n\n```\nGET /bookings?updated_since=2026-09-08T09:00:00Z&limit=100\n```\n\nUse the server's own `updated_at` from the last row you processed as the next watermark rather than your own clock, so a difference between your clock and ours cannot skip a booking. Overlapping by a minute is cheap and safe: results are stable, so re-reading a booking you already have costs one comparison.\n\nThis endpoint has **no created-date filter**, only `updated_since`. If you want to know about changes as they happen rather than on a schedule, ask GAC to register a webhook endpoint for you instead: see **Webhooks** in the collection overview.\n\n### Response\n\nThe paginated envelope. Note that `trace` is omitted entirely on this endpoint, unlike every other one.\n\n```json\n\"pagination\": { \"total_count\": 7, \"total_pages\": 4, \"current_page\": 1, \"limit\": 2 }\n```\n\nEach row is a summary, not the full booking: `id`, `ref_no`, `status`, `grand_total`, `currency`, `booker`, `services[]`, `lead_passenger`, `bags`, `pax`. Fetch the full record with **09 Get booking by ID**.\n\nTwo details that catch people. `bags` and `pax` come from the **first journey only**, so a multi-journey booking under-reports here. And `services[].id` in this response is a line-item id, not the service id you send when creating a quote; match on `service_name` instead.\n\n| Status | `error_code` | When |\n| --- | --- | --- |\n| `200` | — | Always, even with no matches. `message` is `Successful.` |\n| `422` | `validation_failed` | `limit` above 100, `page` below 1, `query` over 5000 characters, or `updated_since` not a parseable date. |\n| `401` | `unauthenticated` | Bearer token missing, invalid or expired. |\n| `500` | `server_error` | Our fault. |"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Successful.\",\n    \"status\": 200,\n    \"responseTime\": \"69ms\",\n    \"data\": [\n        {\n            \"id\": 34605,\n            \"ref_no\": \"GAC-6A8C9DA39E4A8\",\n            \"status\": \"quote\",\n            \"grand_total\": \"622.2\",\n            \"currency\": {\n                \"name\": \"British Pound Sterling\",\n                \"symbol\": \"£\",\n                \"code\": \"GBP\"\n            },\n            \"booker\": {\n                \"forename\": \"Team\",\n                \"email\": \"tech@tripadd.com\"\n            },\n            \"services\": [\n                {\n                    \"id\": 205570,\n                    \"service_name\": \"Meet & Assist\"\n                },\n                {\n                    \"id\": 205571,\n                    \"service_name\": \"Lounge Access\"\n                }\n            ],\n            \"lead_passenger\": {\n                \"name\": \"Mr John Doe\",\n                \"surname\": \"Doe\",\n                \"pnr\": \"ABC123\",\n                \"class\": \"Economy Class\",\n                \"email\": null\n            },\n            \"bags\": {\n                \"small\": 0,\n                \"medium\": 1,\n                \"large\": 0\n            },\n            \"pax\": {\n                \"adult\": 2,\n                \"child\": 0,\n                \"infant\": 0\n            }\n        },\n        {\n            \"id\": 34604,\n            \"ref_no\": \"GAC-6A8C9DA2A683B\",\n            \"status\": \"quote\",\n            \"grand_total\": \"622.2\",\n            \"currency\": {\n                \"name\": \"British Pound Sterling\",\n                \"symbol\": \"£\",\n                \"code\": \"GBP\"\n            },\n            \"booker\": {\n                \"forename\": \"Team\",\n                \"email\": \"tech@tripadd.com\"\n            },\n            \"services\": [\n                {\n                    \"id\": 205574,\n                    \"service_name\": \"Meet & Assist\"\n                },\n                {\n                    \"id\": 205575,\n                    \"service_name\": \"Lounge Access\"\n                }\n            ],\n            \"lead_passenger\": {\n                \"name\": \"Mr John Doe\",\n                \"surname\": \"Doe\",\n                \"pnr\": \"ABC123\",\n                \"class\": \"Economy Class\",\n                \"email\": null\n            },\n            \"bags\": {\n                \"small\": 0,\n                \"medium\": 1,\n                \"large\": 0\n            },\n            \"pax\": {\n                \"adult\": 2,\n                \"child\": 0,\n                \"infant\": 0\n            }\n        }\n    ],\n    \"pagination\": {\n        \"total_count\": 7,\n        \"total_pages\": 4,\n        \"current_page\": 1,\n        \"limit\": 2\n    }\n}"},{"id":"3793a47d-3988-42be-33be-46d3074324da","name":"200 Filtered by reference via query","originalRequest":{"method":"GET","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":{"raw":"https://api-prod.globalairportconcierge.com/api/v1/bookings?page=1&limit=25","host":["https://api-prod.globalairportconcierge.com/api/v1"],"path":["bookings"],"query":[{"value":"1","key":"page","description":"Page number. Defaults to 1."},{"value":"25","key":"limit","description":"Results per page. Defaults to 25, maximum 100."},{"value":"{\"text\":\"GAC-\"}","key":"query","description":"JSON-encoded filter object. See the documentation for the supported keys.","disabled":true},{"value":"2026-09-08T09:00:00Z","key":"updated_since","description":"ISO-8601. Only bookings changed at or after this moment, including amendments and cancellations.","disabled":true}]},"description":"Lists your bookings, newest first. Only your own company's bookings are ever returned.\n\n| Parameter | Type | Default | Notes |\n| --- | --- | --- | --- |\n| `page` | integer | `1` | |\n| `limit` | integer | `25` | Maximum `100`. |\n| `query` | string | — | A **JSON-encoded object**, not a plain search term. Max 5000 characters. |\n| `updated_since` | ISO-8601 datetime | — | Only bookings changed at or after this moment. |\n\n### The query parameter\n\n`query` must be JSON. Send it URL-encoded, for example `query={\"text\":\"GAC-6A8C\"}`.\n\n| Key | Type | Matches |\n| --- | --- | --- |\n| `text` | string | Booking reference, passenger PNR, passenger name, booker name, booker email, or flight number. Partial matches count. |\n| `airports` | array of ids | Bookings touching those airports. |\n| `services` | array of ids | Bookings containing those services. |\n| `booking_status` | array of strings | `quote`, `booking`, `cancelled`. |\n\n**If `query` is not valid JSON it is ignored silently** and you get everything back, which looks like a filter that matched broadly rather than one that failed. Check your encoding if the count looks wrong.\n\n### Catching up with updated_since\n\n`updated_since` filters on when the booking last changed, not when it was created, so it picks up amendments and cancellations as well as new bookings. Pass the timestamp of your last successful sync:\n\n```\nGET /bookings?updated_since=2026-09-08T09:00:00Z&limit=100\n```\n\nUse the server's own `updated_at` from the last row you processed as the next watermark rather than your own clock, so a difference between your clock and ours cannot skip a booking. Overlapping by a minute is cheap and safe: results are stable, so re-reading a booking you already have costs one comparison.\n\nThis endpoint has **no created-date filter**, only `updated_since`. If you want to know about changes as they happen rather than on a schedule, ask GAC to register a webhook endpoint for you instead: see **Webhooks** in the collection overview.\n\n### Response\n\nThe paginated envelope. Note that `trace` is omitted entirely on this endpoint, unlike every other one.\n\n```json\n\"pagination\": { \"total_count\": 7, \"total_pages\": 4, \"current_page\": 1, \"limit\": 2 }\n```\n\nEach row is a summary, not the full booking: `id`, `ref_no`, `status`, `grand_total`, `currency`, `booker`, `services[]`, `lead_passenger`, `bags`, `pax`. Fetch the full record with **09 Get booking by ID**.\n\nTwo details that catch people. `bags` and `pax` come from the **first journey only**, so a multi-journey booking under-reports here. And `services[].id` in this response is a line-item id, not the service id you send when creating a quote; match on `service_name` instead.\n\n| Status | `error_code` | When |\n| --- | --- | --- |\n| `200` | — | Always, even with no matches. `message` is `Successful.` |\n| `422` | `validation_failed` | `limit` above 100, `page` below 1, `query` over 5000 characters, or `updated_since` not a parseable date. |\n| `401` | `unauthenticated` | Bearer token missing, invalid or expired. |\n| `500` | `server_error` | Our fault. |"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Successful.\",\n    \"status\": 200,\n    \"responseTime\": \"69ms\",\n    \"data\": [\n        {\n            \"id\": 34604,\n            \"ref_no\": \"GAC-6A8C9DA2A683B\",\n            \"status\": \"quote\",\n            \"grand_total\": \"622.2\",\n            \"currency\": {\n                \"name\": \"British Pound Sterling\",\n                \"symbol\": \"£\",\n                \"code\": \"GBP\"\n            },\n            \"booker\": {\n                \"forename\": \"Team\",\n                \"email\": \"tech@tripadd.com\"\n            },\n            \"services\": [\n                {\n                    \"id\": 205574,\n                    \"service_name\": \"Meet & Assist\"\n                },\n                {\n                    \"id\": 205575,\n                    \"service_name\": \"Lounge Access\"\n                }\n            ],\n            \"lead_passenger\": {\n                \"name\": \"Mr John Doe\",\n                \"surname\": \"Doe\",\n                \"pnr\": \"ABC123\",\n                \"class\": \"Economy Class\",\n                \"email\": null\n            },\n            \"bags\": {\n                \"small\": 0,\n                \"medium\": 1,\n                \"large\": 0\n            },\n            \"pax\": {\n                \"adult\": 2,\n                \"child\": 0,\n                \"infant\": 0\n            }\n        }\n    ],\n    \"pagination\": {\n        \"total_count\": 1,\n        \"total_pages\": 1,\n        \"current_page\": 1,\n        \"limit\": 2\n    }\n}"}],"_postman_id":"7d19bb2b-922d-4a1b-8835-4ad2ca73c955"},{"name":"09 Get booking by ID","id":"8c973cc3-2457-4d81-bdbc-2db3bfe96531","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings/{{booking_id}}","description":"<p>Fetches one booking in full by our numeric id, the <code>data.id</code> returned when you created it.</p>\n<p>Works at any status, including cancelled. Read-only, no side effects.</p>\n<h3 id=\"responses\">Responses</h3>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th><code>error_code</code></th>\n<th>When</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>200</code></td>\n<td>—</td>\n<td>Found. <code>message</code> is <code>Successfully!</code></td>\n</tr>\n<tr>\n<td><code>404</code></td>\n<td><code>booking_not_found</code></td>\n<td>Unknown id, or a booking that is not yours. The two are deliberately indistinguishable.</td>\n</tr>\n<tr>\n<td><code>404</code></td>\n<td><code>endpoint_not_found</code></td>\n<td>The id was not numeric, so no route matched. Use <strong>10 Get booking by GAC reference</strong> for <code>GAC-…</code> strings.</td>\n</tr>\n<tr>\n<td><code>401</code></td>\n<td><code>unauthenticated</code></td>\n<td>Bearer token missing, invalid or expired.</td>\n</tr>\n<tr>\n<td><code>500</code></td>\n<td><code>server_error</code></td>\n<td>Our fault.</td>\n</tr>\n</tbody>\n</table>\n</div><h3 id=\"what-comes-back\">What comes back</h3>\n<p>Root: <code>id</code>, <code>ref_no</code>, <code>status</code>, <code>expires_on</code>, <code>created_at</code>, <code>currency</code>, <code>currency_id</code>, <code>booker_id</code>, <code>promo_code</code>, <code>settings</code>, <code>journeys[]</code>, <code>billing</code>.</p>\n<p>Each journey carries <code>flight</code>, the passenger counts, <code>passengers</code> grouped by type, and <code>stops.arrival</code> / <code>stops.departure</code> (either may be <code>null</code>). Each stop carries its <code>airport</code> and its <code>services[]</code>, and each service line has <code>id</code> (the service id), <code>value</code>, <code>surcharge</code> and <code>service_name</code>.</p>\n<p><code>billing.status</code> is an integer: <code>0</code> unpaid, <code>1</code> payment intent created, <code>2</code> paid by card, <code>3</code> invoiced.</p>\n<p>Where a greeter has been assigned, <code>services[].allocation</code> carries their name, email and phone so you can coordinate on the day. It is <code>null</code> until then.</p>\n<p><strong>This is the only way to learn about a change.</strong> There are no webhooks, so if GAC operations cancel or amend a booking, polling here is how you find out.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{token}}"}]},"isInherited":true,"source":{"_postman_id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","name":"Global Airport Concierge API v1","type":"collection"}},"urlObject":{"path":["bookings","{{booking_id}}"],"host":["https://api-prod.globalairportconcierge.com/api/v1"],"query":[],"variable":[]}},"response":[{"id":"2b6ab1b7-3d9e-99ff-fb66-88288834d542","name":"200 Full booking","originalRequest":{"method":"GET","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings/{{booking_id}}","description":"Fetches one booking in full by our numeric id, the `data.id` returned when you created it.\n\nWorks at any status, including cancelled. Read-only, no side effects.\n\n### Responses\n\n| Status | `error_code` | When |\n| --- | --- | --- |\n| `200` | — | Found. `message` is `Successfully!` |\n| `404` | `booking_not_found` | Unknown id, or a booking that is not yours. The two are deliberately indistinguishable. |\n| `404` | `endpoint_not_found` | The id was not numeric, so no route matched. Use **10 Get booking by GAC reference** for `GAC-…` strings. |\n| `401` | `unauthenticated` | Bearer token missing, invalid or expired. |\n| `500` | `server_error` | Our fault. |\n\n### What comes back\n\nRoot: `id`, `ref_no`, `status`, `expires_on`, `created_at`, `currency`, `currency_id`, `booker_id`, `promo_code`, `settings`, `journeys[]`, `billing`.\n\nEach journey carries `flight`, the passenger counts, `passengers` grouped by type, and `stops.arrival` / `stops.departure` (either may be `null`). Each stop carries its `airport` and its `services[]`, and each service line has `id` (the service id), `value`, `surcharge` and `service_name`.\n\n`billing.status` is an integer: `0` unpaid, `1` payment intent created, `2` paid by card, `3` invoiced.\n\nWhere a greeter has been assigned, `services[].allocation` carries their name, email and phone so you can coordinate on the day. It is `null` until then.\n\n**This is the only way to learn about a change.** There are no webhooks, so if GAC operations cancel or amend a booking, polling here is how you find out."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Successfully!\",\n    \"status\": 200,\n    \"responseTime\": \"125ms\",\n    \"trace\": [],\n    \"data\": {\n        \"id\": 34604,\n        \"expires_on\": \"2026-08-31T19:38:12+00:00\",\n        \"ref_no\": \"GAC-6A8C9DA2A683B\",\n        \"status\": \"quote\",\n        \"currency\": {\n            \"id\": 3,\n            \"symbol\": \"£\",\n            \"name\": \"British Pound Sterling\",\n            \"symbol_native\": \"£\",\n            \"decimal_digits\": 2,\n            \"rounding\": 0,\n            \"code\": \"GBP\",\n            \"name_plural\": \"British pounds sterling\",\n            \"multiplier\": 0.85\n        },\n        \"journeys\": [\n            {\n                \"flight\": \"EK1\",\n                \"adult\": 2,\n                \"child\": 0,\n                \"infant\": 0,\n                \"bag_small\": 0,\n                \"bag_medium\": 1,\n                \"bag_large\": 0,\n                \"passengers\": {\n                    \"adult\": [\n                        {\n                            \"type\": \"adult\",\n                            \"lead\": true,\n                            \"pnr\": \"ABC123\",\n                            \"signage\": \"John Doe\",\n                            \"class_type\": \"Economy Class\",\n                            \"title\": \"Mr\",\n                            \"first_name\": \"John\",\n                            \"last_name\": \"Doe\",\n                            \"contacts\": [\n                                {\n                                    \"type\": \"phone\",\n                                    \"value\": \"+441234567890\",\n                                    \"contact_person\": \"John Doe\"\n                                }\n                            ]\n                        }\n                    ],\n                    \"child\": [],\n                    \"infant\": []\n                },\n                \"stops\": {\n                    \"arrival\": {\n                        \"airport\": {\n                            \"id\": 113,\n                            \"name\": \"AUH Abu Dhabi International Airport\",\n                            \"iata\": \"AUH\"\n                        },\n                        \"services\": [\n                            {\n                                \"id\": 1,\n                                \"value\": 425,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Meet & Assist\",\n                                \"allocation\": null\n                            },\n                            {\n                                \"id\": 4,\n                                \"value\": 197.2,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Lounge Access\",\n                                \"allocation\": null\n                            }\n                        ],\n                        \"airport_id\": 113\n                    },\n                    \"departure\": null\n                }\n            }\n        ],\n        \"billing\": {\n            \"status\": 0,\n            \"total_discount\": 0,\n            \"add_hrs_charge\": 0,\n            \"surcharge\": 0,\n            \"total_booking_cost\": 622.2,\n            \"grand_total\": 622.2,\n            \"total_paid\": \"0.00\",\n            \"total_refund_amount\": 0,\n            \"tax\": 0,\n            \"tax_rate\": 0\n        },\n        \"settings\": {\n            \"no_surcharge\": false,\n            \"no_additional_hour_charges\": false,\n            \"customer_reference\": \"PM-1787600290\"\n        },\n        \"promo_code\": null,\n        \"created_at\": \"2026-08-24T19:38:10+00:00\",\n        \"currency_id\": 3,\n        \"booker_id\": 39083\n    }\n}"},{"id":"b3621e15-5e6a-89c4-199d-1256c9533583","name":"404 Unknown id, or not your booking","originalRequest":{"method":"GET","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings/{{booking_id}}","description":"Fetches one booking in full by our numeric id, the `data.id` returned when you created it.\n\nWorks at any status, including cancelled. Read-only, no side effects.\n\n### Responses\n\n| Status | `error_code` | When |\n| --- | --- | --- |\n| `200` | — | Found. `message` is `Successfully!` |\n| `404` | `booking_not_found` | Unknown id, or a booking that is not yours. The two are deliberately indistinguishable. |\n| `404` | `endpoint_not_found` | The id was not numeric, so no route matched. Use **10 Get booking by GAC reference** for `GAC-…` strings. |\n| `401` | `unauthenticated` | Bearer token missing, invalid or expired. |\n| `500` | `server_error` | Our fault. |\n\n### What comes back\n\nRoot: `id`, `ref_no`, `status`, `expires_on`, `created_at`, `currency`, `currency_id`, `booker_id`, `promo_code`, `settings`, `journeys[]`, `billing`.\n\nEach journey carries `flight`, the passenger counts, `passengers` grouped by type, and `stops.arrival` / `stops.departure` (either may be `null`). Each stop carries its `airport` and its `services[]`, and each service line has `id` (the service id), `value`, `surcharge` and `service_name`.\n\n`billing.status` is an integer: `0` unpaid, `1` payment intent created, `2` paid by card, `3` invoiced.\n\nWhere a greeter has been assigned, `services[].allocation` carries their name, email and phone so you can coordinate on the day. It is `null` until then.\n\n**This is the only way to learn about a change.** There are no webhooks, so if GAC operations cancel or amend a booking, polling here is how you find out."},"status":"Not Found","code":404,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"No booking found with id 99999999. It may not exist, or it may belong to another company.\",\n    \"status\": 404,\n    \"responseTime\": \"22ms\",\n    \"error_code\": \"booking_not_found\",\n    \"data\": {\n        \"errors\": []\n    }\n}"}],"_postman_id":"8c973cc3-2457-4d81-bdbc-2db3bfe96531"},{"name":"11 Get booking by your reference","id":"9bad5f9e-02ec-4452-8855-33897815999b","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings/customer-reference/{{customer_reference}}","description":"<p>Fetches one booking in full by the <code>settings.customer_reference</code> you supplied when you created it. Same response as <strong>09 Get booking by ID</strong>.</p>\n<p>This is the most useful lookup for an integration, because the reference is yours: you know it before we reply, it never changes, and it survives a replace. Send one on every quote.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th><code>error_code</code></th>\n<th>When</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>200</code></td>\n<td>—</td>\n<td>Found. <code>message</code> is <code>Successfully!</code></td>\n</tr>\n<tr>\n<td><code>404</code></td>\n<td><code>booking_not_found</code></td>\n<td>Unknown reference, or a booking that is not yours.</td>\n</tr>\n<tr>\n<td><code>401</code></td>\n<td><code>unauthenticated</code></td>\n<td>Bearer token missing, invalid or expired.</td>\n</tr>\n<tr>\n<td><code>500</code></td>\n<td><code>server_error</code></td>\n<td>Our fault.</td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>Use it to recover from a failed create.</strong> There is no idempotency on quote creation, so if a request times out you cannot tell whether the booking was made. Retry with the same <code>customer_reference</code>: a <code>422</code> with <code>errors[\"settings.customer_reference\"]</code> proves the first attempt landed, and this endpoint then hands you that booking. That is the safest retry pattern available today.</p>\n<p>References are unique per company, so yours cannot collide with another partner's.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{token}}"}]},"isInherited":true,"source":{"_postman_id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","name":"Global Airport Concierge API v1","type":"collection"}},"urlObject":{"path":["bookings","customer-reference","{{customer_reference}}"],"host":["https://api-prod.globalairportconcierge.com/api/v1"],"query":[],"variable":[]}},"response":[{"id":"d5c4dfb8-147c-aa83-5416-45643a6b57b8","name":"404 Unknown customer reference","originalRequest":{"method":"GET","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings/customer-reference/{{customer_reference}}","description":"Fetches one booking in full by the `settings.customer_reference` you supplied when you created it. Same response as **09 Get booking by ID**.\n\nThis is the most useful lookup for an integration, because the reference is yours: you know it before we reply, it never changes, and it survives a replace. Send one on every quote.\n\n| Status | `error_code` | When |\n| --- | --- | --- |\n| `200` | — | Found. `message` is `Successfully!` |\n| `404` | `booking_not_found` | Unknown reference, or a booking that is not yours. |\n| `401` | `unauthenticated` | Bearer token missing, invalid or expired. |\n| `500` | `server_error` | Our fault. |\n\n**Use it to recover from a failed create.** There is no idempotency on quote creation, so if a request times out you cannot tell whether the booking was made. Retry with the same `customer_reference`: a `422` with `errors[\"settings.customer_reference\"]` proves the first attempt landed, and this endpoint then hands you that booking. That is the safest retry pattern available today.\n\nReferences are unique per company, so yours cannot collide with another partner's."},"status":"Not Found","code":404,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"No booking found with your reference PM-NOPE-0000.\",\n    \"status\": 404,\n    \"responseTime\": \"19ms\",\n    \"error_code\": \"booking_not_found\",\n    \"data\": {\n        \"errors\": []\n    }\n}"},{"id":"6776fd2e-2a96-9f04-847a-0505fa20b784","name":"200 Full booking","originalRequest":{"method":"GET","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings/customer-reference/{{customer_reference}}","description":"Fetches one booking in full by the `settings.customer_reference` you supplied when you created it. Same response as **09 Get booking by ID**.\n\nThis is the most useful lookup for an integration, because the reference is yours: you know it before we reply, it never changes, and it survives a replace. Send one on every quote.\n\n| Status | `error_code` | When |\n| --- | --- | --- |\n| `200` | — | Found. `message` is `Successfully!` |\n| `404` | `booking_not_found` | Unknown reference, or a booking that is not yours. |\n| `401` | `unauthenticated` | Bearer token missing, invalid or expired. |\n| `500` | `server_error` | Our fault. |\n\n**Use it to recover from a failed create.** There is no idempotency on quote creation, so if a request times out you cannot tell whether the booking was made. Retry with the same `customer_reference`: a `422` with `errors[\"settings.customer_reference\"]` proves the first attempt landed, and this endpoint then hands you that booking. That is the safest retry pattern available today.\n\nReferences are unique per company, so yours cannot collide with another partner's."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Successfully!\",\n    \"status\": 200,\n    \"responseTime\": \"119ms\",\n    \"trace\": [],\n    \"data\": {\n        \"id\": 34604,\n        \"expires_on\": \"2026-08-31T19:38:12+00:00\",\n        \"ref_no\": \"GAC-6A8C9DA2A683B\",\n        \"status\": \"quote\",\n        \"currency\": {\n            \"id\": 3,\n            \"symbol\": \"£\",\n            \"name\": \"British Pound Sterling\",\n            \"symbol_native\": \"£\",\n            \"decimal_digits\": 2,\n            \"rounding\": 0,\n            \"code\": \"GBP\",\n            \"name_plural\": \"British pounds sterling\",\n            \"multiplier\": 0.85\n        },\n        \"journeys\": [\n            {\n                \"flight\": \"EK1\",\n                \"adult\": 2,\n                \"child\": 0,\n                \"infant\": 0,\n                \"bag_small\": 0,\n                \"bag_medium\": 1,\n                \"bag_large\": 0,\n                \"passengers\": {\n                    \"adult\": [\n                        {\n                            \"type\": \"adult\",\n                            \"lead\": true,\n                            \"pnr\": \"ABC123\",\n                            \"signage\": \"John Doe\",\n                            \"class_type\": \"Economy Class\",\n                            \"title\": \"Mr\",\n                            \"first_name\": \"John\",\n                            \"last_name\": \"Doe\",\n                            \"contacts\": [\n                                {\n                                    \"type\": \"phone\",\n                                    \"value\": \"+441234567890\",\n                                    \"contact_person\": \"John Doe\"\n                                }\n                            ]\n                        }\n                    ],\n                    \"child\": [],\n                    \"infant\": []\n                },\n                \"stops\": {\n                    \"arrival\": {\n                        \"airport\": {\n                            \"id\": 113,\n                            \"name\": \"AUH Abu Dhabi International Airport\",\n                            \"iata\": \"AUH\"\n                        },\n                        \"services\": [\n                            {\n                                \"id\": 1,\n                                \"value\": 425,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Meet & Assist\",\n                                \"allocation\": null\n                            },\n                            {\n                                \"id\": 4,\n                                \"value\": 197.2,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Lounge Access\",\n                                \"allocation\": null\n                            }\n                        ],\n                        \"airport_id\": 113\n                    },\n                    \"departure\": null\n                }\n            }\n        ],\n        \"billing\": {\n            \"status\": 0,\n            \"total_discount\": 0,\n            \"add_hrs_charge\": 0,\n            \"surcharge\": 0,\n            \"total_booking_cost\": 622.2,\n            \"grand_total\": 622.2,\n            \"total_paid\": \"0.00\",\n            \"total_refund_amount\": 0,\n            \"tax\": 0,\n            \"tax_rate\": 0\n        },\n        \"settings\": {\n            \"no_surcharge\": false,\n            \"no_additional_hour_charges\": false,\n            \"customer_reference\": \"PM-1787600290\"\n        },\n        \"promo_code\": null,\n        \"created_at\": \"2026-08-24T19:38:10+00:00\",\n        \"currency_id\": 3,\n        \"booker_id\": 39083\n    }\n}"}],"_postman_id":"9bad5f9e-02ec-4452-8855-33897815999b"},{"name":"10 Get booking by GAC reference","id":"ee063ddc-d8a8-dec7-5d6d-98aef15ce503","request":{"method":"GET","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings/reference/{{booking_ref}}","description":"<p>Fetches one booking in full by the <code>ref_no</code> we generate, for example <code>GAC-6A8C9DA2A683B</code>. Same response as <strong>09 Get booking by ID</strong>.</p>\n<p>Useful when a customer quotes the reference from their confirmation email and you do not have our numeric id to hand.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th><code>error_code</code></th>\n<th>When</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>200</code></td>\n<td>—</td>\n<td>Found. <code>message</code> is <code>Successfully!</code></td>\n</tr>\n<tr>\n<td><code>404</code></td>\n<td><code>booking_not_found</code></td>\n<td>Unknown reference, or a booking that is not yours.</td>\n</tr>\n<tr>\n<td><code>401</code></td>\n<td><code>unauthenticated</code></td>\n<td>Bearer token missing, invalid or expired.</td>\n</tr>\n<tr>\n<td><code>500</code></td>\n<td><code>server_error</code></td>\n<td>Our fault.</td>\n</tr>\n</tbody>\n</table>\n</div><p>Remember that <code>ref_no</code> changes if you replace the booking without echoing it back. Your own <code>customer_reference</code> is the more stable handle, so <strong>11 Get booking by your reference</strong> is usually the better lookup to build against.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{token}}"}]},"isInherited":true,"source":{"_postman_id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","name":"Global Airport Concierge API v1","type":"collection"}},"urlObject":{"path":["bookings","reference","{{booking_ref}}"],"host":["https://api-prod.globalairportconcierge.com/api/v1"],"query":[],"variable":[]}},"response":[{"id":"0910ffa5-71b2-ca8e-0870-d842a4ade26a","name":"404 Unknown reference","originalRequest":{"method":"GET","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings/reference/{{booking_ref}}","description":"Fetches one booking in full by the `ref_no` we generate, for example `GAC-6A8C9DA2A683B`. Same response as **09 Get booking by ID**.\n\nUseful when a customer quotes the reference from their confirmation email and you do not have our numeric id to hand.\n\n| Status | `error_code` | When |\n| --- | --- | --- |\n| `200` | — | Found. `message` is `Successfully!` |\n| `404` | `booking_not_found` | Unknown reference, or a booking that is not yours. |\n| `401` | `unauthenticated` | Bearer token missing, invalid or expired. |\n| `500` | `server_error` | Our fault. |\n\nRemember that `ref_no` changes if you replace the booking without echoing it back. Your own `customer_reference` is the more stable handle, so **11 Get booking by your reference** is usually the better lookup to build against."},"status":"Not Found","code":404,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"No booking found with reference GAC-DOES-NOT-EXIST. It may not exist, or it may belong to another company.\",\n    \"status\": 404,\n    \"responseTime\": \"19ms\",\n    \"error_code\": \"booking_not_found\",\n    \"data\": {\n        \"errors\": []\n    }\n}"},{"id":"07c98dc3-d8f8-45b8-39d7-1e0768affcea","name":"200 Full booking","originalRequest":{"method":"GET","header":[],"body":{"mode":"raw","raw":"","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/bookings/reference/{{booking_ref}}","description":"Fetches one booking in full by the `ref_no` we generate, for example `GAC-6A8C9DA2A683B`. Same response as **09 Get booking by ID**.\n\nUseful when a customer quotes the reference from their confirmation email and you do not have our numeric id to hand.\n\n| Status | `error_code` | When |\n| --- | --- | --- |\n| `200` | — | Found. `message` is `Successfully!` |\n| `404` | `booking_not_found` | Unknown reference, or a booking that is not yours. |\n| `401` | `unauthenticated` | Bearer token missing, invalid or expired. |\n| `500` | `server_error` | Our fault. |\n\nRemember that `ref_no` changes if you replace the booking without echoing it back. Your own `customer_reference` is the more stable handle, so **11 Get booking by your reference** is usually the better lookup to build against."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n    \"message\": \"Successfully!\",\n    \"status\": 200,\n    \"responseTime\": \"121ms\",\n    \"trace\": [],\n    \"data\": {\n        \"id\": 34604,\n        \"expires_on\": \"2026-08-31T19:38:12+00:00\",\n        \"ref_no\": \"GAC-6A8C9DA2A683B\",\n        \"status\": \"quote\",\n        \"currency\": {\n            \"id\": 3,\n            \"symbol\": \"£\",\n            \"name\": \"British Pound Sterling\",\n            \"symbol_native\": \"£\",\n            \"decimal_digits\": 2,\n            \"rounding\": 0,\n            \"code\": \"GBP\",\n            \"name_plural\": \"British pounds sterling\",\n            \"multiplier\": 0.85\n        },\n        \"journeys\": [\n            {\n                \"flight\": \"EK1\",\n                \"adult\": 2,\n                \"child\": 0,\n                \"infant\": 0,\n                \"bag_small\": 0,\n                \"bag_medium\": 1,\n                \"bag_large\": 0,\n                \"passengers\": {\n                    \"adult\": [\n                        {\n                            \"type\": \"adult\",\n                            \"lead\": true,\n                            \"pnr\": \"ABC123\",\n                            \"signage\": \"John Doe\",\n                            \"class_type\": \"Economy Class\",\n                            \"title\": \"Mr\",\n                            \"first_name\": \"John\",\n                            \"last_name\": \"Doe\",\n                            \"contacts\": [\n                                {\n                                    \"type\": \"phone\",\n                                    \"value\": \"+441234567890\",\n                                    \"contact_person\": \"John Doe\"\n                                }\n                            ]\n                        }\n                    ],\n                    \"child\": [],\n                    \"infant\": []\n                },\n                \"stops\": {\n                    \"arrival\": {\n                        \"airport\": {\n                            \"id\": 113,\n                            \"name\": \"AUH Abu Dhabi International Airport\",\n                            \"iata\": \"AUH\"\n                        },\n                        \"services\": [\n                            {\n                                \"id\": 1,\n                                \"value\": 425,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Meet & Assist\",\n                                \"allocation\": null\n                            },\n                            {\n                                \"id\": 4,\n                                \"value\": 197.2,\n                                \"surcharge\": 0,\n                                \"service_name\": \"Lounge Access\",\n                                \"allocation\": null\n                            }\n                        ],\n                        \"airport_id\": 113\n                    },\n                    \"departure\": null\n                }\n            }\n        ],\n        \"billing\": {\n            \"status\": 0,\n            \"total_discount\": 0,\n            \"add_hrs_charge\": 0,\n            \"surcharge\": 0,\n            \"total_booking_cost\": 622.2,\n            \"grand_total\": 622.2,\n            \"total_paid\": \"0.00\",\n            \"total_refund_amount\": 0,\n            \"tax\": 0,\n            \"tax_rate\": 0\n        },\n        \"settings\": {\n            \"no_surcharge\": false,\n            \"no_additional_hour_charges\": false,\n            \"customer_reference\": \"PM-1787600290\"\n        },\n        \"promo_code\": null,\n        \"created_at\": \"2026-08-24T19:38:10+00:00\",\n        \"currency_id\": 3,\n        \"booker_id\": 39083\n    }\n}"}],"_postman_id":"ee063ddc-d8a8-dec7-5d6d-98aef15ce503"},{"name":"13 Manage your agents","id":"fa517969-4d8f-0afb-afdc-472db9e57da1","request":{"method":"GET","header":[],"url":"https://api-prod.globalairportconcierge.com/api/v1/agents?page=1&limit=25","description":"<p>The people who book on your account.</p>\n<p>Every booking carries a <code>booker_id</code>, and <strong>03 Create quote</strong> refuses one that is not an agent of your company. So an agent record has to exist before that person can book anything. This is how you create them yourself instead of asking GAC to add people one at a time.</p>\n<p><strong>These are booking records, not logins.</strong> Nobody gets a GAC password. Your own portal signs the agent in at your end and tells us who it was, by putting their <code>id</code> in <code>booker_id</code>.</p>\n<h2 id=\"what-it-is-for\">What it is for</h2>\n<ul>\n<li>Attributing a booking to the agent who made it, which is what commission is calculated from</li>\n<li>Putting the right name on the confirmation email</li>\n<li>Removing someone the day they leave, without a support request</li>\n</ul>\n<h2 id=\"the-endpoints\">The endpoints</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Method</th>\n<th>Path</th>\n<th>Does</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>GET</code></td>\n<td><code>/agents</code></td>\n<td>List yours, paginated</td>\n</tr>\n<tr>\n<td><code>POST</code></td>\n<td><code>/agents</code></td>\n<td>Create one. The <code>id</code> it returns is what you send as <code>booker_id</code></td>\n</tr>\n<tr>\n<td><code>GET</code></td>\n<td><code>/agents/{id}</code></td>\n<td>Read one</td>\n</tr>\n<tr>\n<td><code>GET</code></td>\n<td><code>/agents/reference/{reference}</code></td>\n<td>Read one by <strong>your</strong> identifier</td>\n</tr>\n<tr>\n<td><code>PATCH</code></td>\n<td><code>/agents/{id}</code></td>\n<td>Change name, email or reference</td>\n</tr>\n<tr>\n<td><code>DELETE</code></td>\n<td><code>/agents/{id}</code></td>\n<td>Remove from your account</td>\n</tr>\n</tbody>\n</table>\n</div><p>Only your own agents are ever visible or editable. Another partner's agent returns <code>404</code> on every one of these, exactly as if it did not exist.</p>\n<h2 id=\"creating-one\">Creating one</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"title\": \"Ms\",\n  \"forename\": \"Layla\",\n  \"surname\": \"Hassan\",\n  \"email\": \"layla.hassan@broker.example\",\n  \"reference\": \"BROKER-0042\"\n}\n</code></pre>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Required</th>\n<th>Notes</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>forename</code></td>\n<td><strong>yes</strong></td>\n<td></td>\n</tr>\n<tr>\n<td><code>surname</code></td>\n<td><strong>yes</strong></td>\n<td></td>\n</tr>\n<tr>\n<td><code>email</code></td>\n<td><strong>yes</strong></td>\n<td>Booking confirmations go here</td>\n</tr>\n<tr>\n<td><code>title</code></td>\n<td>no</td>\n<td><code>Mr</code>, <code>Ms</code> and so on</td>\n</tr>\n<tr>\n<td><code>reference</code></td>\n<td>no</td>\n<td><strong>Your</strong> id for this person. Send it and you never have to store ours</td>\n</tr>\n</tbody>\n</table>\n</div><p>The response gives you back an <code>id</code>. That is the value for <code>booker_id</code>.</p>\n<h2 id=\"removing-one\">Removing one</h2>\n<p><code>DELETE</code> removes the agent from your account. It does <strong>not</strong> delete the person, and their past bookings are untouched and still readable through <strong>08 List bookings</strong>. They simply cannot make new ones. That is what you want when someone leaves: deleting them outright would break every booking they ever made.</p>\n<p>Send the same <code>DELETE</code> twice and the second returns <code>404</code>, since they are already gone from your account.</p>\n<h2 id=\"onboarding-in-bulk\">Onboarding in bulk</h2>\n<p>There is no bulk endpoint. Create them in a loop, one call each, and mind the rate limit: 300 requests a minute per API key. 600 agents is two minutes of calling, or one minute if you pace it.</p>\n<p>Send your own <code>reference</code> on each so you can reconcile without storing our ids, and so a partial run is safe to repeat: look each one up by reference first and skip the ones that already exist.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th><code>error_code</code></th>\n<th>When</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>200</code></td>\n<td>—</td>\n<td>Read, update or delete succeeded</td>\n</tr>\n<tr>\n<td><code>201</code></td>\n<td>—</td>\n<td>Created</td>\n</tr>\n<tr>\n<td><code>404</code></td>\n<td><code>agent_not_found</code></td>\n<td>No agent with that id or reference <strong>on your account</strong></td>\n</tr>\n<tr>\n<td><code>422</code></td>\n<td><code>validation_failed</code></td>\n<td>Missing name or email, or an email that is not valid</td>\n</tr>\n<tr>\n<td><code>401</code></td>\n<td><code>unauthenticated</code></td>\n<td>Bearer token missing, invalid or expired</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{token}}"}]},"isInherited":true,"source":{"_postman_id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","id":"d4ec1598-6624-4bc0-86ea-f9c6f6160e9a","name":"Global Airport Concierge API v1","type":"collection"}},"urlObject":{"path":["agents"],"host":["https://api-prod.globalairportconcierge.com/api/v1"],"query":[{"description":{"content":"<p>Page number. Defaults to 1.</p>\n","type":"text/plain"},"key":"page","value":"1"},{"description":{"content":"<p>Results per page. Defaults to 25, maximum 100.</p>\n","type":"text/plain"},"key":"limit","value":"25"},{"disabled":true,"description":{"content":"<p>Matches on first name, last name, email or your own reference.</p>\n","type":"text/plain"},"key":"query","value":"hassan"},{"disabled":true,"description":{"content":"<p>Exact match on your own reference.</p>\n","type":"text/plain"},"key":"reference","value":"BROKER-0042"}],"variable":[]}},"response":[{"id":"db11553f-9931-a127-a5d9-22096fdc473e","name":"201 Agent created","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"title\": \"Ms\",\n  \"forename\": \"Layla\",\n  \"surname\": \"Hassan\",\n  \"email\": \"layla.hassan@broker.example\",\n  \"reference\": \"BROKER-0042\"\n}","options":{"raw":{"language":"json"}}},"url":"https://api-prod.globalairportconcierge.com/api/v1/agents"},"status":"Created","code":201,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":"58","body":"{\"message\":\"Agent created successfully.\",\"status\":201,\"responseTime\":\"58ms\",\"trace\":[],\"data\":{\"id\":41181,\"title\":\"Ms\",\"forename\":\"Layla\",\"surname\":\"Hassan\",\"email\":\"layla.hassan@broker.example\",\"reference\":\"BROKER-0042\",\"created_at\":\"2026-09-09T00:21:11+00:00\"}}"}],"_postman_id":"fa517969-4d8f-0afb-afdc-472db9e57da1"}],"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{token}}"}]}},"event":[{"listen":"prerequest","script":{"id":"02cc49a1-4d89-42a1-9082-6e527d4d7666","type":"text/javascript","packages":{},"exec":[""]}},{"listen":"test","script":{"id":"454367f6-1815-4238-832a-2ae976df8729","type":"text/javascript","packages":{},"exec":[""]}}],"variable":[{"key":"base_url","value":"https://api-prod.globalairportconcierge.com/api/v1"},{"key":"docs_site","value":"https://api-docs.globalairportconcierge.com"},{"key":"docs_repo","value":"https://github.com/globalairportconcierge/api-docs"},{"key":"webhook_test_url","value":"http://localhost:3000/hooks/gac"},{"key":"webhook_secret","value":"ASK_GAC_FOR_YOUR_SIGNING_SECRET"}]}