{
  "info": {
    "name": "Rimo Transfers - Token FULL (stagingapi, Bearer JWT)",
    "description": "Full transfer flow on stagingapi.rimoglobal.com using your Kong JWT (api-group). No cookies. Set the collection variable 'token' to the JWT issued by the TH admin panel for your API agent (Rimo B2C = agent 'Rimo Tours B2C', RG-034, ClientId 37; Kong consumer client-rimob2c with api-group + apiout-group). No minting needed. Set it once, then run steps 1..9 in order (step 9 is the mandatory cancellation check). Suppliers: Mozio / Talixo / Transferz. Default test route: Cairo Airport -> Safir Hotel Cairo, 2026-12-19 19:00 (free cancellation). agtMkp = your agent markup (0 = none). VERIFIED end-to-end 2026-11-07 (booking RIMO2026110008 created + cancelled OK). Step 4 prebook = ShoppingCart/PriceCheck (returns bookingToken). Step 5 Book body is FLAT (no 'payload' wrapper). Step 8 Cancel may return HTTP 400 INTERNAL_ERROR even when it SUCCEEDS - confirm by re-running step 6 (bookingStatus becomes 'Cancelled').",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{token}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://stagingapi.rimoglobal.com"
    },
    {
      "key": "token",
      "value": "PASTE_RIMOB2C_ADMIN_JWT_HERE"
    },
    {
      "key": "searchKey",
      "value": ""
    },
    {
      "key": "uniqueKey",
      "value": ""
    },
    {
      "key": "shoppingCartId",
      "value": ""
    },
    {
      "key": "shoppingCartToken",
      "value": ""
    },
    {
      "key": "cartId",
      "value": ""
    },
    {
      "key": "cartDetailId",
      "value": ""
    },
    {
      "key": "bookingToken",
      "value": ""
    },
    {
      "key": "referenceNo",
      "value": ""
    },
    {
      "key": "referenceNoPlain",
      "value": ""
    },
    {
      "key": "bookingId",
      "value": ""
    },
    {
      "key": "detailId",
      "value": ""
    }
  ],
  "item": [
    {
      "name": "1. Search (TransferList)",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('200', ()=>pm.response.to.have.status(200));",
              "try{ var j=pm.response.json(); var res=(j&&j.result)||[]; if(res.length){ pm.collectionVariables.set('searchKey', res[0].searchKey); pm.collectionVariables.set('uniqueKey', res[0].uniqueKey); console.log('OK results=',res.length,'| pick:',res[0].vehicleName,res[0].totalPrice,res[0].supplierName); console.log('searchKey=',res[0].searchKey); } else { console.log('NO RESULTS', JSON.stringify(j).slice(0,300)); } }catch(e){console.log('parse err',e);}"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/api/transferservices/TransferList",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "transferservices",
            "TransferList"
          ]
        },
        "body": {
          "mode": "raw",
          "raw": "{\n  \"fromLatitude\": 30.1095011,\n  \"fromLongitude\": 31.389179,\n  \"toLatitude\": 30.0352247,\n  \"toLongitude\": 31.2137474,\n  \"departureDate\": \"2026-12-19T19:00:00\",\n  \"departureTime\": \"19:00:00\",\n  \"fromType\": \"A\",\n  \"toType\": \"H\",\n  \"fromPlaceId\": \"ChIJUdjd5XEXWBQRBeLwBHq31Bg\",\n  \"toPlaceId\": \"ChIJcyOeoGJAWBQRjA64QUTDT04\",\n  \"fromLocationName\": \"Cairo Airport\",\n  \"toLocationName\": \"Safir Hotel Cairo\",\n  \"isRoundTrip\": 0,\n  \"luggageCapacity\": 3,\n  \"passengers\": 1,\n  \"transferRateTypes\": [ { \"transferRateTypeId\": 1, \"count\": 1, \"transferRateTypeName\": \"Adult\" } ]\n}"
        }
      }
    },
    {
      "name": "1b. Indexing info (required passenger fields for this vehicle)",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "var j={}; try{j=pm.response.json();}catch(e){}",
              "var opts=((j.result&&j.result[0]&&j.result[0].options)||[]);",
              "console.log('Required/optional passenger fields for this uniqueKey:');",
              "opts.forEach(function(o){ console.log('  -', o.indexFieldName, '| required:', o.isRequired, '| maxLen:', o.maxFieldLength); });",
              "console.log('>>> Put each of these as an entry in TransferIndex[] in step 4 (PriceCheck): {indexFieldName, indexFieldValue}. Fill every one whose required = true.');",
              "pm.test('IndexingInfo returned', function(){ pm.expect(pm.response.code).to.eql(200); });"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/api/transferservices/IndexingInfo",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "transferservices",
            "IndexingInfo"
          ]
        },
        "body": {
          "mode": "raw",
          "raw": "{\n  \"uniqueKey\": \"{{uniqueKey}}\",\n  \"Direction\": false,\n  \"lang\": \"en\"\n}"
        }
      }
    },
    {
      "name": "1c. Ancillary services (extras available for this vehicle)",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "var j={}; try{j=pm.response.json();}catch(e){}",
              "var list=(j.result||[]);",
              "console.log('Extras available for this uniqueKey (add chosen ones to ancillaryService[] in step 2 add-to-cart):');",
              "list.forEach(function(a){ console.log('  - id:', a.ancillaryId, '| code:', a.servicesCode, '| name:', a.servicesName, '| price:', a.price!==undefined?a.price:''); });",
              "console.log('>>> Shape in add-to-cart: {ancillaryId, count, servicesCode, servicesName}. MEET_GREET is usually free.');",
              "pm.test('AncillaryService returned', function(){ pm.expect(pm.response.code).to.eql(200); });"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/api/transferservices/AncillaryService",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "transferservices",
            "AncillaryService"
          ]
        },
        "body": {
          "mode": "raw",
          "raw": "{\n  \"uniqueKey\": \"{{uniqueKey}}\",\n  \"lang\": \"en\"\n}"
        }
      }
    },
    {
      "name": "2. Add transfer to cart",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "try{ var r=pm.response.json().result; if(r){ if(r.shoppingCartId) pm.collectionVariables.set('shoppingCartId', r.shoppingCartId); if(r.shoppingCartToken) pm.collectionVariables.set('shoppingCartToken', r.shoppingCartToken); console.log('cart:', JSON.stringify(r)); } else { console.log('resp', JSON.stringify(pm.response.json()).slice(0,400)); } }catch(e){console.log(e);}"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/api/ShoppingCart/AddTransferToCart",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "ShoppingCart",
            "AddTransferToCart"
          ]
        },
        "body": {
          "mode": "raw",
          "raw": "{\n  \"shoppingCartId\": \"\",\n  \"cartDetail\": [\n    {\n      \"fromLatitude\": 30.1095011,\n      \"fromLongitude\": 31.389179,\n      \"toLatitude\": 30.0352247,\n      \"toLongitude\": 31.2137474,\n      \"departureDate\": \"2026-12-19T19:00:00\",\n      \"returnDate\": \"2026-12-19T00:00\",\n      \"departureTime\": \"19:00:00\",\n      \"returnTime\": \"00:00\",\n      \"uniqueKey\": \"{{uniqueKey}}\",\n      \"isRoundTrip\": 0,\n      \"fromType\": \"A\",\n      \"toType\": \"H\",\n      \"searchKey\": \"{{searchKey}}\",\n      \"agtMkp\": \"0\",\n      \"agtMkpType\": \"0\",\n      \"agtMkpCurrId\": 5,\n      \"fromPlaceId\": \"ChIJUdjd5XEXWBQRBeLwBHq31Bg\",\n      \"toPlaceId\": \"ChIJcyOeoGJAWBQRjA64QUTDT04\",\n      \"ImagePath\": \"https://static.talixo.de/images/vehicles/economy.png\",\n      \"luggageCapacity\": 3,\n      \"fromLocationName\": \"Cairo Airport\",\n      \"toLocationName\": \"Safir Hotel Cairo\",\n      \"fromAddress\": \"Cairo International Airport, Egypt\",\n      \"toAddress\": \"Safir Hotel Cairo, Egypt\",\n      \"currentDate\": \"{{$isoTimestamp}}\",\n      \"transferRateTypes\": [ { \"transferRateTypeId\": 1, \"count\": 1, \"transferRateTypeName\": \"Adult\" } ],\n      \"ancillaryService\": [],\n      \"TransferIndex\": [],\n      \"validateTransferDetail\": []\n    }\n  ],\n  \"lang\": \"en\"\n}"
        }
      }
    },
    {
      "name": "3. Cart details (GetCartDetails)",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "try{ var r=pm.response.json().result; if(r){ if(r.shoppingCartDetail&&r.shoppingCartDetail[0]) pm.collectionVariables.set('cartId', r.shoppingCartDetail[0].cartId); if(r.transferDetail&&r.transferDetail[0]) pm.collectionVariables.set('cartDetailId', r.transferDetail[0].cartDetailId); if(r.shoppingCartToken) pm.collectionVariables.set('shoppingCartToken', r.shoppingCartToken); console.log('cartId=',pm.collectionVariables.get('cartId'),'cartDetailId=',pm.collectionVariables.get('cartDetailId')); } }catch(e){console.log(e, JSON.stringify(pm.response.json()).slice(0,400));}"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/api/ShoppingCart/GetCartDetails",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "ShoppingCart",
            "GetCartDetails"
          ]
        },
        "body": {
          "mode": "raw",
          "raw": "{\n  \"shoppingCartId\": \"{{shoppingCartId}}\",\n  \"locale\": \"en\"\n}"
        }
      }
    },
    {
      "name": "4. Price check / prebook (ShoppingCart/PriceCheck)",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "try{ var r=pm.response.json().result; if(r&&r.bookingToken){ pm.collectionVariables.set('bookingToken', r.bookingToken); console.log('bookingToken saved; priceHike=',r.priceHike); } else { console.log('prebook resp', JSON.stringify(pm.response.json()).slice(0,500)); } }catch(e){console.log(e);}"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          },
          {
            "key": "x-local",
            "value": "en"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/api/ShoppingCart/PriceCheck",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "ShoppingCart",
            "PriceCheck"
          ]
        },
        "body": {
          "mode": "raw",
          "raw": "{\n  \"shoppingCartId\": \"{{shoppingCartId}}\",\n  \"shoppingCartToken\": \"{{shoppingCartToken}}\",\n  \"leadPaxDetails\": [ { \"prefix\": \"Mr. \", \"firstName\": \"Kareem\", \"lastName\": \"Test\", \"paxType\": \"Adult\" } ],\n  \"preBookDetails\": {\n    \"tourDetails\": [], \"hotelDetails\": [],\n    \"transferDetails\": [\n      {\n        \"cartId\": {{cartId}},\n        \"cartDetailId\": {{cartDetailId}},\n        \"remarks\": \"\",\n        \"paxDetails\": [ { \"prefix\": \"Mr. \", \"firstName\": \"Kareem\", \"lastName\": \"Test\", \"paxType\": \"Adult\", \"isLead\": true } ],\n        \"isMainPassenger\": true,\n        \"ancillaryService\": [],\n        \"TransferIndex\": [\n          { \"indexFieldName\": \"Flight Number\", \"indexFieldValue\": \"MS827\" }\n        ]\n      }\n    ],\n    \"restaurantDetails\": [], \"visaDetails\": [], \"flightPreBookDetails\": [], \"carRentalDetails\": [], \"staticPackageDetails\": [], \"insurancePreBookDetails\": []\n  },\n  \"gstDetails\": {}\n}"
        }
      }
    },
    {
      "name": "5. Book (BookService, credit limit)",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "try{ var r=pm.response.json().result; if(r&&r.referenceNo){ pm.collectionVariables.set('referenceNo', r.referenceNo); try{ pm.collectionVariables.set('referenceNoPlain', require('buffer').Buffer.from(r.referenceNo,'base64').toString()); }catch(e2){ pm.collectionVariables.set('referenceNoPlain', r.referenceNo); } console.log('referenceNo(b64)=',r.referenceNo,'| plain=',pm.collectionVariables.get('referenceNoPlain'),'| code=',r.code); } else { console.log('book resp', JSON.stringify(pm.response.json()).slice(0,600)); } }catch(e){console.log(e);}"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/api/Booking/BookService",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "Booking",
            "BookService"
          ]
        },
        "body": {
          "mode": "raw",
          "raw": "{\n  \"ShoppingCartId\": \"{{shoppingCartId}}\",\n  \"ShoppingCartToken\": \"{{shoppingCartToken}}\",\n  \"bookingToken\": \"{{bookingToken}}\",\n  \"PaymentMode\": \"credit limit\",\n  \"bookingDate\": \"{{$isoTimestamp}}\",\n  \"payId\": \"\",\n  \"userRefNo\": \"\",\n  \"emailId\": \"nour@rimotours.com\",\n  \"mobileNo\": \"+20 1115421083\",\n  \"nationality\": \"Egypt\",\n  \"gstDetails\": {},\n  \"bookingProcessType\": \"VOUCHER\",\n  \"locale\": \"en\"\n}"
        }
      }
    },
    {
      "name": "6. Booking details (get bookingId / detailId)",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "try{ var j=pm.response.json(); console.log('bookingdetails:', JSON.stringify(j).slice(0,1500)); var seen={}; (function dig(o){ if(!o||typeof o!=='object') return; if(o.bookingId!=null&&!seen.b){ pm.collectionVariables.set('bookingId', o.bookingId); seen.b=1; } if(o.detailId!=null&&!seen.d){ pm.collectionVariables.set('detailId', o.detailId); seen.d=1; } for(var k in o) dig(o[k]); })(j.result||j); console.log('bookingId=',pm.collectionVariables.get('bookingId'),'detailId=',pm.collectionVariables.get('detailId')); }catch(e){console.log(e);}"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [],
        "url": {
          "raw": "{{baseUrl}}/api/Booking/BookingDetails/{{referenceNo}}",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "Booking",
            "BookingDetails",
            "{{referenceNo}}"
          ]
        }
      }
    },
    {
      "name": "7. Cancellation detail (refund preview)",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/api/Booking/BookingCancellationDetail",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "Booking",
            "BookingCancellationDetail"
          ]
        },
        "body": {
          "mode": "raw",
          "raw": "{\n  \"referenceNo\": \"{{referenceNo}}\",\n  \"bookingId\": \"{{bookingId}}\",\n  \"detailId\": {{detailId}}\n}"
        }
      }
    },
    {
      "name": "8. Cancel booking  (⚠ returns 400 INTERNAL_ERROR even when it succeeds — ALWAYS run step 9)",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/api/Booking/CancelBooking",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "Booking",
            "CancelBooking"
          ]
        },
        "body": {
          "mode": "raw",
          "raw": "{\n  \"referenceNo\": \"{{referenceNo}}\",\n  \"bookingId\": \"{{bookingId}}\",\n  \"detailId\": {{detailId}},\n  \"cancelReason\": \"test cancellation\",\n  \"cancelledById\": 23,\n  \"cancelledBy\": \"Agent\"\n}"
        }
      },
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "console.log('Cancel HTTP', pm.response.code, '-', JSON.stringify(pm.response.json()).slice(0,200));",
              "console.log('NOTE: a 400 INTERNAL_ERROR here is a known backend quirk. The cancellation usually SUCCEEDED. Run step 9 to verify.');"
            ]
          }
        }
      ]
    },
    {
      "name": "9. VERIFY cancellation (MANDATORY — proves the cancel really happened)",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "var j=pm.response.json(); var r=(j&&j.result&&j.result[0])||{}; var dd=(r.bookingDetails&&r.bookingDetails[0])||{};",
              "var status=dd.bookingStatus; var amt=r.totalSellingAmount;",
              "console.log('referenceNo=',r.referenceNo,'| bookingStatus=',status,'| totalSellingAmount=',amt);",
              "pm.test('Booking status is Cancelled', function(){ pm.expect(status).to.eql('Cancelled'); });",
              "pm.test('Selling amount reversed to 0', function(){ pm.expect(Number(amt)).to.eql(0); });",
              "if(status!=='Cancelled'){ console.log('!! NOT cancelled — re-run step 8, wait 10s, run step 9 again. If still Vouchered, cancel from the B2B website or contact ops.'); }"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [],
        "url": {
          "raw": "{{baseUrl}}/api/Booking/BookingDetails/{{referenceNo}}",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "Booking",
            "BookingDetails",
            "{{referenceNo}}"
          ]
        }
      }
    }
  ]
}