{
  "info": {
    "name": "JetWize Partner API",
    "description": "B2B flight Partner API. Set the `apiKey` collection variable to your sandbox key (jwz_test_…) and run the requests top to bottom for a full sandbox flow: search → book → pay (auto-issues in sandbox) → e-ticket. All requests send the `X-API-Key` header automatically.\n\nBase URL: https://api.jetwize.com/api/v1/partner/v1",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "variable": [
    { "key": "baseUrl", "value": "https://api.jetwize.com/api/v1/partner/v1", "type": "string" },
    { "key": "apiKey", "value": "jwz_test_REPLACE_WITH_YOUR_SANDBOX_KEY", "type": "string" },
    { "key": "offerId", "value": "", "type": "string" },
    { "key": "bookingId", "value": "", "type": "string" }
  ],
  "auth": { "type": "apikey", "apikey": [
    { "key": "key", "value": "X-API-Key", "type": "string" },
    { "key": "value", "value": "{{apiKey}}", "type": "string" },
    { "key": "in", "value": "header", "type": "string" }
  ] },
  "item": [
    {
      "name": "1. Account — GET /me",
      "request": { "method": "GET", "header": [], "url": { "raw": "{{baseUrl}}/me", "host": ["{{baseUrl}}"], "path": ["me"] },
        "description": "Verify your key. Returns environment (SANDBOX/PRODUCTION), agency, and wallet/credit." }
    },
    {
      "name": "2. Wallet — GET /wallet",
      "request": { "method": "GET", "header": [], "url": { "raw": "{{baseUrl}}/wallet", "host": ["{{baseUrl}}"], "path": ["wallet"] } }
    },
    {
      "name": "3. Airports — GET /airports?q=DPS",
      "request": { "method": "GET", "header": [], "url": { "raw": "{{baseUrl}}/airports?q=DPS&limit=10", "host": ["{{baseUrl}}"], "path": ["airports"], "query": [ { "key": "q", "value": "DPS" }, { "key": "limit", "value": "10" } ] } }
    },
    {
      "name": "4. Search — POST /flights/search",
      "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [
        "// Save the first offerId for the next requests.",
        "const r = pm.response.json();",
        "if (r.results && r.results.length) { pm.collectionVariables.set('offerId', r.results[0].offerId); }",
        "pm.test('has results', () => pm.expect(r.results.length).to.be.above(0));"
      ] } } ],
      "request": { "method": "POST",
        "header": [ { "key": "Content-Type", "value": "application/json" } ],
        "body": { "mode": "raw", "raw": "{\n  \"origin\": \"CGK\",\n  \"destination\": \"DPS\",\n  \"departDate\": \"2026-07-15\",\n  \"passengers\": { \"adult\": 1, \"child\": 0, \"infant\": 0 },\n  \"cabinClass\": \"ECONOMY\"\n}" },
        "url": { "raw": "{{baseUrl}}/flights/search", "host": ["{{baseUrl}}"], "path": ["flights", "search"] },
        "description": "In SANDBOX this returns deterministic mock offers. The test script saves results[0].offerId into the `offerId` variable." }
    },
    {
      "name": "5. Price check — POST /flights/price-check",
      "request": { "method": "POST",
        "header": [ { "key": "Content-Type", "value": "application/json" } ],
        "body": { "mode": "raw", "raw": "{\n  \"offerId\": \"{{offerId}}\"\n}" },
        "url": { "raw": "{{baseUrl}}/flights/price-check", "host": ["{{baseUrl}}"], "path": ["flights", "price-check"] } }
    },
    {
      "name": "6. Fare rules — GET /flights/:offerId/fare-rules",
      "request": { "method": "GET", "header": [], "url": { "raw": "{{baseUrl}}/flights/{{offerId}}/fare-rules", "host": ["{{baseUrl}}"], "path": ["flights", "{{offerId}}", "fare-rules"] } }
    },
    {
      "name": "7. Create booking — POST /bookings",
      "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [
        "const r = pm.response.json();",
        "if (r.id) { pm.collectionVariables.set('bookingId', r.id); }",
        "pm.test('booking created', () => pm.expect(r.id).to.be.a('string'));"
      ] } } ],
      "request": { "method": "POST",
        "header": [ { "key": "Content-Type", "value": "application/json" }, { "key": "Idempotency-Key", "value": "{{$guid}}" } ],
        "body": { "mode": "raw", "raw": "{\n  \"offerId\": \"{{offerId}}\",\n  \"contactEmail\": \"partner@example.com\",\n  \"contactPhone\": \"+628123456789\",\n  \"passengers\": [\n    { \"title\": \"MR\", \"firstName\": \"Budi\", \"lastName\": \"Santoso\", \"dateOfBirth\": \"1990-01-15\", \"nationality\": \"ID\", \"type\": \"ADULT\" }\n  ]\n}" },
        "url": { "raw": "{{baseUrl}}/bookings", "host": ["{{baseUrl}}"], "path": ["bookings"] },
        "description": "Sandbox keys may only book offers from a sandbox search. Idempotency-Key is recommended for create/pay/refund." }
    },
    {
      "name": "8. Pay (wallet) — POST /bookings/:id/pay",
      "request": { "method": "POST",
        "header": [ { "key": "Content-Type", "value": "application/json" }, { "key": "Idempotency-Key", "value": "{{$guid}}" } ],
        "body": { "mode": "raw", "raw": "{}" },
        "url": { "raw": "{{baseUrl}}/bookings/{{bookingId}}/pay", "host": ["{{baseUrl}}"], "path": ["bookings", "{{bookingId}}", "pay"] },
        "description": "SANDBOX: payment is simulated and the ticket is issued immediately (no real debit)." }
    },
    {
      "name": "9. Booking detail — GET /bookings/:id",
      "request": { "method": "GET", "header": [], "url": { "raw": "{{baseUrl}}/bookings/{{bookingId}}", "host": ["{{baseUrl}}"], "path": ["bookings", "{{bookingId}}"] } }
    },
    {
      "name": "10. E-ticket — GET /bookings/:id/ticket",
      "request": { "method": "GET", "header": [], "url": { "raw": "{{baseUrl}}/bookings/{{bookingId}}/ticket", "host": ["{{baseUrl}}"], "path": ["bookings", "{{bookingId}}", "ticket"] } }
    },
    {
      "name": "List bookings — GET /bookings",
      "request": { "method": "GET", "header": [], "url": { "raw": "{{baseUrl}}/bookings?limit=20", "host": ["{{baseUrl}}"], "path": ["bookings"], "query": [ { "key": "limit", "value": "20" } ] } }
    },
    {
      "name": "Cancel (pre-issue) — POST /bookings/:id/cancel",
      "request": { "method": "POST", "header": [], "body": { "mode": "raw", "raw": "{}" }, "url": { "raw": "{{baseUrl}}/bookings/{{bookingId}}/cancel", "host": ["{{baseUrl}}"], "path": ["bookings", "{{bookingId}}", "cancel"] } }
    },
    {
      "name": "Refund quote — GET /bookings/:id/refund-quote",
      "request": { "method": "GET", "header": [], "url": { "raw": "{{baseUrl}}/bookings/{{bookingId}}/refund-quote", "host": ["{{baseUrl}}"], "path": ["bookings", "{{bookingId}}", "refund-quote"] } }
    },
    {
      "name": "Refund — POST /bookings/:id/refund",
      "request": { "method": "POST",
        "header": [ { "key": "Content-Type", "value": "application/json" } ],
        "body": { "mode": "raw", "raw": "{\n  \"reason\": \"Pembatalan oleh penumpang\"\n}" },
        "url": { "raw": "{{baseUrl}}/bookings/{{bookingId}}/refund", "host": ["{{baseUrl}}"], "path": ["bookings", "{{bookingId}}", "refund"] } }
    },
    {
      "name": "Ancillary catalog — GET /bookings/:id/ancillaries/catalog",
      "request": { "method": "GET", "header": [], "url": { "raw": "{{baseUrl}}/bookings/{{bookingId}}/ancillaries/catalog?kind=SEAT", "host": ["{{baseUrl}}"], "path": ["bookings", "{{bookingId}}", "ancillaries", "catalog"], "query": [{ "key": "kind", "value": "SEAT", "description": "BAGGAGE | MEAL | SEAT (omit for all)" }] } }
    },
    {
      "name": "Seat map — GET /bookings/:id/seatmap",
      "request": { "method": "GET", "header": [], "url": { "raw": "{{baseUrl}}/bookings/{{bookingId}}/seatmap", "host": ["{{baseUrl}}"], "path": ["bookings", "{{bookingId}}", "seatmap"] } }
    },
    {
      "name": "Book seat — POST /bookings/:id/ancillaries",
      "request": { "method": "POST", "header": [{ "key": "Content-Type", "value": "application/json" }, { "key": "Idempotency-Key", "value": "{{$guid}}" }], "body": { "mode": "raw", "raw": "{\n  \"payment\": \"WALLET\",\n  \"items\": [\n    { \"optionId\": \"SEAT-12A\", \"kind\": \"SEAT\", \"passengerId\": \"{{passengerId}}\" }\n  ]\n}" }, "url": { "raw": "{{baseUrl}}/bookings/{{bookingId}}/ancillaries", "host": ["{{baseUrl}}"], "path": ["bookings", "{{bookingId}}", "ancillaries"] } }
    },
    {
      "name": "Reschedule options — GET /bookings/:id/reschedule/options",
      "request": { "method": "GET", "header": [], "url": { "raw": "{{baseUrl}}/bookings/{{bookingId}}/reschedule/options", "host": ["{{baseUrl}}"], "path": ["bookings", "{{bookingId}}", "reschedule", "options"] } }
    },
    {
      "name": "Auto-rebook: enable — POST /bookings/:id/auto-rebook/enable",
      "request": { "method": "POST", "header": [{ "key": "Content-Type", "value": "application/json" }], "body": { "mode": "raw", "raw": "{\n  \"maxHoldMinutes\": 1440,\n  \"priceThresholdPct\": 10\n}" }, "url": { "raw": "{{baseUrl}}/bookings/{{bookingId}}/auto-rebook/enable", "host": ["{{baseUrl}}"], "path": ["bookings", "{{bookingId}}", "auto-rebook", "enable"] }, "description": "Auto-renew the hold before it expires (held/PENDING_PAYMENT bookings only; supplier must be gated on; sandbox runs on mock). Does not issue the ticket or take payment." }
    },
    {
      "name": "Auto-rebook: history — GET /bookings/:id/auto-rebook/history",
      "request": { "method": "GET", "header": [], "url": { "raw": "{{baseUrl}}/bookings/{{bookingId}}/auto-rebook/history", "host": ["{{baseUrl}}"], "path": ["bookings", "{{bookingId}}", "auto-rebook", "history"] } }
    },
    {
      "name": "Auto-rebook: approve (paused) — POST /bookings/:id/auto-rebook/approve",
      "request": { "method": "POST", "header": [], "body": { "mode": "raw", "raw": "{}" }, "url": { "raw": "{{baseUrl}}/bookings/{{bookingId}}/auto-rebook/approve", "host": ["{{baseUrl}}"], "path": ["bookings", "{{bookingId}}", "auto-rebook", "approve"] }, "description": "Resume a cycle that PAUSED because the renewal price rose above price_threshold_pct." }
    },
    {
      "name": "Auto-rebook: disable — POST /bookings/:id/auto-rebook/disable",
      "request": { "method": "POST", "header": [], "body": { "mode": "raw", "raw": "{}" }, "url": { "raw": "{{baseUrl}}/bookings/{{bookingId}}/auto-rebook/disable", "host": ["{{baseUrl}}"], "path": ["bookings", "{{bookingId}}", "auto-rebook", "disable"] }, "description": "Stop the cycle. The current hold is preserved." }
    }
  ]
}
