GAMAN API

Ship Updates. Not Headaches.

GAMAN is the travel-booking API platform built for agents and OTAs who move fast. One API for authentication, organization management, flight search & booking, and hotels — all live today.

🚀

Deploy with confidence

A single, consistent REST API for authentication, org management, and flight booking — no juggling multiple systems.

🔒

Secure by default

Every request is authenticated with a Bearer token, and wallet operations are validated against your organization's balance in real time.

🎯

Full organization control

Manage sub-agents, wallets, markup packages, and audit logs — all scoped cleanly to your organization.

📊

Clear, predictable responses

Every endpoint returns the same success / data / error shape, so integration stays simple from day one.

Staging Url: https://staging.gaman.co.in

How to read this documentation: the left sidebar is organized by section (Organization, Flights, Hotels, etc.). Each endpoint shows its HTTP method and path, a plain-English explanation of every field, and a real JSON example for both the request and the response.

Authentication

All endpoints (except login) require a Bearer token in the header:

Authorization: Bearer <access_token>

Login (Org User)

POST /api/v1/auth/login Request:
{
  "agent_id": "GAMDEMO0001",
  "username": "admin",
  "password": "OrgAdmin@123"
}
Success Response (200):
{
  "success": true,
  "message": "login successful",
  "data": {
    "user": {
      "id": "11111111-1111-1111-1111-111111111111",
      "username": "admin",
      "email": "admin@demo.com",
      "name": "Demo Admin",
      "role": "org_admin",
      "status": "active",
      "org_id": "9551fa77-16ad-4df5-9284-dc23cb95c237",
      "sub_agent_id": "GAMDEMO0002"
    },
    "tokens": {
      "access_token": "eyJhbGciOiJIUzI1NiIs...",
      "refresh_token": "eyJhbGciOiJIUzI1NiIs...",
      "expires_in_seconds": 3600
    },
    "agent_id": "GAMDEMO0001"
  }
}
Field Reference:

Refresh Token

POST /api/v1/auth/refresh

Exchange a valid refresh token for a brand-new token pair. This rotates the refresh token (the previous one is revoked), so call it before the refresh token expires. The response mirrors Login's token envelope.

Request:
{
  "refresh_token": "eyJhbGciOiJIUzI1NiIs..."
}
Success Response (200):
{
  "success": true,
  "message": "token refreshed",
  "data": {
    "user": null,
    "tokens": {
      "access_token": "eyJhbGciOiJIUzI1NiIs...",
      "refresh_token": "eyJhbGciOiJIUzI1NiIs...",
      "expires_in_seconds": 21600
    }
  }
}
Field Reference:
Field Description
user.id Unique ID of the logged-in user.
user.role Permission level: org_admin (full org access) or agent (restricted, self-scoped access).
user.org_id ID of the organization this user belongs to.
user.sub_agent_id Human-readable agent code used in some org endpoints (e.g. wallet topup).
tokens.access_token Short-lived JWT. Send it as Authorization: Bearer <access_token> on every subsequent request.
tokens.refresh_token Long-lived token used to obtain a new access token once it expires.
tokens.expires_in_seconds How long the access token stays valid, in seconds (3600 = 1 hour).
agent_id Public-facing agency code for the organization (e.g. shown on invoices).
Field Description
refresh_token The long-lived token returned by Login (or a prior refresh). Required.
tokens.access_token New short-lived JWT. Send as Authorization: Bearer <access_token>.
tokens.refresh_token New refresh token. Store it and discard the old one — the old token is revoked after a successful refresh.
tokens.expires_in_seconds Lifetime of the new access token in seconds (21600 = 6 hours).
Subscription tiers & portal access. Every organization has a subscription_type of full or api_only (visible on GET /org/profile):
  • full — access to both the API and the management frontend portal.
  • api_only — programmatic API and self-service only. The management/portal endpoints under Agent Management, Flight Pricing Package, Hotel Pricing Package, Fare Transactions and Organization Wallet (ledger, agent transactions, topup, export) return 403 Forbidden.
Want the portal features above? Upgrade your subscription to unlock them.
Error Response (403 — api_only org):
{
  "success": false,
  "error": "your organization subscription (API only) does not include portal access to this feature"
}
Error Response (401):
{
  "success": false,
  "error": "invalid credentials"
}

Organization Profile

Your organization is the root account for everything below — wallet, agents, pricing packages, and branding. Read or update its public profile and settings here.

Get Organization Profile

GET /api/v1/org/profile Success Response (200):
{
  "success": true,
  "message": "profile retrieved",
  "data": {
    "id": "9551fa77-16ad-4df5-9284-dc23cb95c237",
    "agent_id": "GAMDEMO0001",
    "name": "Demo Travel Agency",
    "slug": "demo-travel",
    "email": "org@demo.com",
    "phone": "+91 9876543210",
    "address": "123 Main Street, Mumbai",
    "country": "IN",
    "subscription_type": "full",
    "status": "active",
    "ip_whitelist_enabled": false,
    "wallet": {
      "id": "11111111-1111-1111-1111-111111111110",
      "balance": 100000,
      "currency": "INR",
      "credit_limit": 0,
      "is_active": true
    }
  }
}
Field Reference:
Field Description
agent_id Public agency/organization code (e.g. shown to sub-agents and on documents).
slug URL-friendly identifier for the organization.
subscription_type Plan tier the org is on (e.g. full).
status Organization state — active or suspended.
ip_whitelist_enabled If true, only requests from whitelisted IPs are accepted for this org.
wallet.balance Current available wallet balance for the organization.
wallet.credit_limit Additional credit the org can spend beyond its balance (0 = no credit line).
wallet.is_active Whether the wallet can currently be used for transactions.

Organization Settings

Key/value settings scoped to your organization. Use these to store portal or integration preferences. The GET endpoint returns the full list of settings for the org.

Get Organization Settings

GET /api/v1/org/settings Success Response (200):
{
  "success": true,
  "message": "settings retrieved",
  "data": [
    {
      "id": "7d2f1a...",
      "org_id": "9551fa77-16ad-4df5-9284-dc23cb95c237",
      "key": "portal_theme",
      "value": "sunset",
      "created_at": "2026-04-10T09:23:20Z",
      "updated_at": "2026-04-10T09:23:20Z"
    }
  ]
}

Upsert a Setting

PUT /api/v1/org/settings Request:
{
  "key": "portal_theme",
  "value": "sunset"
}

Validation: key and value are required strings.

Success Response (200):
{
  "success": true,
  "message": "setting updated"
}

More Features — Power Up Your Portal

Go beyond the API. The features in this group turn a bare API integration into a fully managed travel operation — so your organization can onboard and manage agents, set smart markups with pricing packages, and fund agent wallets, all from one console. Built for teams that want to scale without writing more code.

  • Agent Management — onboard, organize, and control sub-agents under your organization in minutes.
  • Wallet Transactions — fund agent wallets and export the org ledger for full financial visibility.
  • Flight Pricing Package — set flight markups once and assign them to agents or your whole org.
  • Hotel Pricing Package — do the same for hotels, with markups assigned per agent or org-wide.
No code required — it's all in the B2B portal. Every action here is also available in our management portal. These are part of the full (portal) plan; API-only organizations can upgrade their subscription to unlock them.
Premium feature. Onboard, organize, and control sub-agents from one console. Upgrade your plan to unlock Agent Management →

Agent Management

List Agents

GET /api/v1/org/users

Query Parameters: page, per_page, role (org_admin | agent), status (active | suspended).

Success Response (200):
{
  "success": true,
  "data": [
    {
      "id": "5b920162-500f-474f-8e7a-5f131053a7d5",
      "username": "testagent",
      "email": "agent@demo.com",
      "name": "Test Agent",
      "role": "agent",
      "status": "active",
      "created_at": "2026-04-10T14:47:58.251295+05:30"
    }
  ],
  "meta": {
    "page": 1,
    "per_page": 20,
    "total": 2,
    "total_pages": 1
  }
}
Field Reference:
Field Description
role org_admin can manage the whole org (agents, wallet, packages); agent is limited to their own bookings, wallet, and profile.
status active or suspended. Suspended users cannot log in.
meta.page / per_page Current page number and page size used for pagination.
meta.total / total_pages Total matching records, and total number of pages available.

Add Agent

POST /api/v1/org/users Request:
{
  "email": "agent@demo.com",
  "name": "Test Agent",
  "username": "testagent",
  "password": "Agent@123",
  "role": "agent"
}

Valid Roles: org_admin, agent. Optional field: phone.

Success Response (200):
{
  "success": true,
  "message": "user created",
  "data": {
    "id": "5b920162-500f-474f-8e7a-5f131053a7d5",
    "username": "testagent",
    "email": "agent@demo.com",
    "name": "Test Agent",
    "role": "agent",
    "status": "active",
    "org_id": "9551fa77-16ad-4df5-9284-dc23cb95c237",
    "sub_agent_id": "GAMWE0VFZSA"
  }
}

Get Agent by ID

GET /api/v1/org/users/:id Success Response (200):
{
  "success": true,
  "data": {
    "id": "5b920162-500f-474f-8e7a-5f131053a7d5",
    "username": "testagent",
    "email": "agent@demo.com",
    "name": "Test Agent",
    "role": "agent",
    "status": "active",
    "created_at": "2026-04-10T14:47:58.251295+05:30"
  }
}

Update Agent

PUT /api/v1/org/users/:id Request:
{
  "name": "Updated Name",
  "phone": "+919999999999",
  "status": "active"
}

All fields optional. Valid status values: active, suspended.

Success Response (200):
{
  "success": true,
  "message": "user updated",
  "data": {
    "id": "5b920162-500f-474f-8e7a-5f131053a7d5",
    "username": "testagent",
    "email": "new@demo.com",
    "name": "Updated Name",
    "phone": "+919999999999",
    "role": "agent",
    "status": "active"
  }
}

Delete Agent

DELETE /api/v1/org/users/:id Success Response (200):
{
  "success": true,
  "message": "user deleted"
}

Suspend Agent

PUT /api/v1/org/users/:id/suspend Success Response (200):
{
  "success": true,
  "message": "user suspended"
}

Activate Agent

PUT /api/v1/org/users/:id/activate Success Response (200):
{
  "success": true,
                    "message": "user activated"
}

Agent Fare Transactions

Every agent's own fare ledger — each ticketed booking's public fare, the fare charged to the agent (agent_fare), and the agent's commission. Use ?period=weekly|monthly (default monthly).

GET /api/v1/me/fare-transactions?period=monthly&page=1&per_page=20 Success Response (200):
{
  "success": true,
  "message": "fare transactions",
  "data": {
    "period": "monthly",
    "summary": {
      "total_public_fare": 2405,
      "total_agent_fare": 2400,
      "total_agent_commission": 5,
      "transaction_count": 1
    },
    "transactions": [
      {
        "id": "a1b2c3...",
        "booking_ref": "FA-1775272567576",
        "pnr": "FVRVRV",
        "agent_id": "550e8400-...",
        "agent_name": "John Smith",
        "public_fare": 2405,
        "agent_fare": 2400,
        "agent_commission": 5,
        "currency": "INR",
        "issued_at": "2026-04-10T09:23:20Z"
      }
    ],
    "total": 1,
    "page": 1,
    "per_page": 20
  }
}

Organization Wallet

Get Organization Wallet

GET /api/v1/org/wallet Success Response (200):
{
  "success": true,
  "message": "wallet retrieved",
  "data": {
    "id": "11111111-1111-1111-1111-111111111110",
    "owner_id": "9551fa77-16ad-4df5-9284-dc23cb95c237",
    "owner_type": "org",
    "balance": 100000,
    "currency": "INR",
    "credit_limit": 0,
    "is_active": true
  }
}
Field Reference:
Field Description
owner_type Who owns this wallet — org (the organization) or user (an individual agent).
balance Current spendable funds in the wallet's currency.
credit_limit Extra credit allowed beyond the balance before bookings are blocked (0 = none).
is_active If false, the wallet cannot be used to pay for bookings.

Get Wallet Transactions

GET /api/v1/org/wallet/transactions?page=1&per_page=20

Returns the org wallet's transaction history with optional filters. Each entry records a debit when the admin allocated funds to an agent, or a credit when the super admin topped up.

Query Parameters:
Parameter Type Description
page int Page number (default: 1).
per_page int Results per page, max 100 (default: 20).
type string Filter by transaction type — credit or debit.
ref_type string Filter by reference type — topup, booking, refund, deduction.
from date Start date filter (YYYY-MM-DD).
to date End date filter (YYYY-MM-DD).
min_amount float Minimum transaction amount.
max_amount float Maximum transaction amount.
search string Search keyword in description (case-insensitive).
Success Response (200):
{
  "success": true,
  "data": [
    {
      "id": "c5f3a2b1-1111-2222-3333-444444444444",
      "created_at": "2026-04-15T10:00:00.000000+05:30",
      "updated_at": "2026-04-15T10:00:00.000000+05:30",
      "wallet_id": "11111111-1111-1111-1111-111111111110",
      "type": "debit",
      "amount": 5000,
      "balance_before": 105000,
      "balance_after": 100000,
      "ref_type": "topup",
      "ref_id": "550e8400-e29b-41d4-a716-446655440001",
      "description": "allocated to agent: flight testing credits",
      "performed_by": "5b920162-500f-474f-8e7a-5f131053a7d5",
      "agent_id": "550e8400-e29b-41d4-a716-446655440001",
      "agent_name": "John Smith"
    },
    {
      "id": "d6e4b3c2-2222-3333-4444-555555555555",
      "created_at": "2026-04-14T15:30:00.000000+05:30",
      "updated_at": "2026-04-14T15:30:00.000000+05:30",
      "wallet_id": "11111111-1111-1111-1111-111111111110",
      "type": "credit",
      "amount": 50000,
      "balance_before": 55000,
      "balance_after": 105000,
      "ref_type": "topup",
      "ref_id": null,
      "description": "org wallet topup by super admin",
      "performed_by": "00000000-0000-0000-0000-000000000001"
    }
  ],
  "meta": {
    "page": 1,
    "per_page": 20,
    "total": 15,
    "total_pages": 1
  }
}
Field Reference:
Field Description
type debit (funds deducted from the org wallet when allocating to an agent) or credit (funds added, e.g. super-admin topup to org, or a refund).
wallet_id The org wallet's unique identifier — all transactions in this list share the same wallet.
amount Transaction amount in INR.
balance_before / balance_after Org wallet balance immediately before and after the transaction.
ref_type Reason code — topup (allocation to/from agent), booking (flight booking), refund, or deduction.
ref_id Optional reference to a related entity (e.g. booking reference). null for topups.
description Human-readable note — "allocated to agent: <reason>" for admin-to-agent topups, or "org wallet topup by super admin" when SA adds funds.
performed_by User ID of the admin (org admin or super admin) who performed the action.
agent_id If this transaction is an agent allocation, the agent's UUID. omitted for non-allocation transactions.
agent_name Agent's display name. omitted for non-allocation transactions.
Premium feature. Allocate agent funds and export the org ledger for full visibility. Upgrade your plan to unlock Wallet Transactions →

Wallet Transactions

Agent-level wallet funding and ledger exports. These let an org admin allocate funds to individual agents and download the org wallet's transaction history as CSV. All actions are scoped to the organization.

Export Transactions

GET /api/v1/org/wallet/transactions/export?from=2026-07-01&to=2026-07-28

Downloads the org wallet's transaction history as a CSV file. Supports the same filters as the transactions list endpoint (without pagination).

Success Response (200):

Returns a text/csv file with Content-Disposition: attachment. Columns: ID, Date, Type, Amount, Balance Before, Balance After, Reference Type, Description, Performed By.

Topup Agent Wallet

POST /api/v1/org/wallet/topup/:agent_id

Allocates funds from the org wallet to an agent's allocated balance. The :agent_id path param is the agent's internal UUID.

Request:
{
  "amount": 5000,
  "description": "Monthly allocation for John"
}
Success Response (200):
{
  "success": true,
  "message": "wallet allocated to agent"
}
Error Response (400 — Insufficient Balance):
{
  "success": false,
  "error": "insufficient org wallet balance (available: 750.00)"
}
Field Reference:
Field Description
amount Amount to allocate to the agent (deducted from org wallet). Must be greater than zero and ≤ org wallet balance.
description Reason for the allocation. Visible in both org and agent transaction history.

Get Wallet Summary

GET /api/v1/org/wallet/summary

Dashboard-style roll-up of the org wallet: balances, total allocated to agents, and this month's credit/debit activity.

Success Response (200):
{
  "success": true,
  "message": "wallet summary retrieved",
  "data": {
    "current_balance": 100000,
    "credit_limit": 0,
    "available_balance": 100000,
    "total_allocated_to_agents": 25000,
    "agent_count": 8,
    "this_month": {
      "total_credits": 50000,
      "total_debits": 12000,
      "net_change": 38000,
      "transaction_count": 14
    },
    "balance_trend": []
  }
}

List Agents & Allocations

GET /api/v1/org/wallet/agents

Every agent in the org with their current and lifetime allocated balances.

Success Response (200):
{
  "success": true,
  "message": "agents retrieved",
  "data": [
    {
      "agent_id": "550e8400-e29b-41d4-a716-446655440001",
      "name": "John Smith",
      "username": "john",
      "allocated_balance": 5000,
      "total_allocated_to_date": 12000,
      "last_allocation": "2026-04-14T15:30:00Z",
      "is_active": true
    }
  ]
}

Get Agent Transactions

GET /api/v1/org/wallet/agents/:agent_id/transactions?page=1&per_page=20

Same transaction ledger as /org/wallet/transactions but scoped to a single agent. Supports the same type, ref_type, from, to, min_amount, max_amount and search filters.

Success Response (200):
{
  "success": true,
  "data": [
    {
      "id": "c5f3a2b1-1111-2222-3333-444444444444",
      "type": "debit",
      "amount": 5000,
      "balance_before": 105000,
      "balance_after": 100000,
      "ref_type": "topup",
      "description": "allocated to agent: flight testing credits",
      "agent_id": "550e8400-e29b-41d4-a716-446655440001",
      "agent_name": "John Smith"
    }
  ],
  "meta": { "page": 1, "per_page": 20, "total": 3, "total_pages": 1 }
}
Premium feature. Set flight markups once and assign them per agent or org-wide. Upgrade your plan to unlock Flight Pricing Packages →

Flight Pricing Package

Manage org-scoped flight pricing packages and agent-level package assignments. Org-scoped packages override global defaults and are only visible within the org. A package can be assigned to the whole organization (yourself) or to individual agents — an agent-level assignment overrides the org-level one.

Create Package

POST /api/v1/org/packages Request:
{
  "name": "Premium Package",
  "description": "Best fares with a flat markup",
  "markup_type": "flat",
  "markup_value": 150.0,
  "markup_apply_on": "commission",
  "priority": 0
}

Fields: markup_type (flat | percent), markup_apply_on (commission | fare | total).

Restricted fields: org admins cannot set service_fee_type / service_fee_value, gst_on_service_fee, platform_charge, min_commission, or max_commission on org packages. These are platform-level terms configured by the super admin (global packages / SA markup rules) and are always stored as zero for org-scoped packages. Any of these keys sent in the request body are ignored.
Success Response (201):
{
  "success": true,
  "message": "package created",
  "data": {
    "id": "b3f1a2c4-...",
    "name": "Premium Package",
    "description": "Best fares with a flat markup",
    "org_id": "9551fa77-...",
    "scope": "org",
    "markup_type": "flat",
    "markup_value": 150.0,
    "markup_apply_on": "commission",
    "min_commission": 0,
    "max_commission": 0,
    "service_fee_type": "flat",
    "service_fee_value": 0,
    "gst_on_service_fee": 0,
    "platform_charge": 0,
    "priority": 0,
    "is_active": true,
    "created_by": "5b920162-...",
    "created_at": "2026-04-15T10:00:00Z",
    "updated_at": "2026-04-15T10:00:00Z"
  }
}

List Packages

GET /api/v1/org/packages Success Response (200):
{
  "success": true,
  "message": "packages retrieved",
  "data": [
    {
      "id": "b3f1a2c4-...",
      "name": "Premium Package",
      "scope": "org",
      "org_id": "9551fa77-...",
      "markup_type": "flat",
      "markup_value": 150.0,
      "markup_apply_on": "commission",
      "min_commission": 0,
      "max_commission": 0,
      "service_fee_type": "flat",
      "service_fee_value": 0,
      "gst_on_service_fee": 0,
      "platform_charge": 0,
      "priority": 0,
      "is_active": true,
      "is_applied": false,
      "created_at": "2026-04-15T10:00:00Z",
      "updated_at": "2026-04-15T10:00:00Z"
    }
  ]
}

Get Assigned Package

GET /api/v1/org/packages/assigned

Returns the currently assigned org-level package (not agent-specific). Returns 404 if no package is assigned.

Success Response (200):
{
  "success": true,
  "message": "assigned package",
  "data": {
    "id": "b3f1a2c4-...",
    "name": "Premium Package",
    "scope": "org",
    "org_id": "9551fa77-...",
    "markup_type": "flat",
    "markup_value": 150.0,
    "markup_apply_on": "commission",
    "min_commission": 0,
    "max_commission": 0,
    "service_fee_type": "flat",
    "service_fee_value": 0,
    "gst_on_service_fee": 0,
    "platform_charge": 0,
    "priority": 0,
    "is_active": true,
    "created_by": "5b920162-...",
    "created_at": "2026-04-15T10:00:00Z",
    "updated_at": "2026-04-15T10:00:00Z",
    "assignments": null
  }
}

Update Package

PUT /api/v1/org/packages/:id

Same request body as Create Package. Updates all configurable fields.

Success Response (200):
{
  "success": true,
  "message": "package updated",
  "data": {
    "id": "b3f1a2c4-...",
    "name": "Premium Package",
    "description": "Best fares with a flat markup",
    "org_id": "9551fa77-...",
    "scope": "org",
    "markup_type": "flat",
    "markup_value": 175.0,
    "markup_apply_on": "commission",
    "min_commission": 0,
    "max_commission": 0,
    "service_fee_type": "flat",
    "service_fee_value": 0,
    "gst_on_service_fee": 0,
    "platform_charge": 0,
    "priority": 0,
    "is_active": true,
    "created_by": "5b920162-...",
    "created_at": "2026-04-15T10:00:00Z",
    "updated_at": "2026-04-16T11:32:07Z"
  }
}

Delete Package

DELETE /api/v1/org/packages/:id

Performs a hard delete (scoped to the org).

Success Response (200):
{
  "success": true,
  "message": "package deleted"
}

Assign Package to Organization

POST /api/v1/org/packages/assign

Assigns a package to the org itself. Removes any previous org-level assignment.

Request:
{
  "package_id": "b3f1a2c4-..."
}
Success Response (200):
{
  "success": true,
  "message": "package assigned"
}

Unassign Package from Organization

DELETE /api/v1/org/packages/assign Success Response (200):
{
  "success": true,
  "message": "package unassigned"
}

List Agent Assignments

GET /api/v1/org/packages/agent-assignments

Returns all agent-specific package assignments for the org, with the preloaded package details.

Success Response (200):
{
  "success": true,
  "message": "agent assignments",
  "data": [
    {
      "id": "a1b2c3d4-...",
      "package_id": "b3f1a2c4-...",
      "org_id": "9551fa77-...",
      "agent_id": "5b920162-...",
      "assigned_at": "2026-04-15T10:00:00Z",
      "assigned_by": "6315581f-...",
      "package": {
        "id": "b3f1a2c4-...",
        "name": "Premium Package",
        "markup_type": "flat",
        "markup_value": 150.0,
        ...
      }
    }
  ]
}

Assign Package to Agent

POST /api/v1/org/packages/assign-agent/:agent_id

Assigns a package to a specific agent (agent-level override). Replaces any prior agent assignment.

Request:
{
  "package_id": "b3f1a2c4-..."
}
Success Response (200):
{
  "success": true,
  "message": "package assigned to agent"
}

Unassign Package from Agent

DELETE /api/v1/org/packages/assign-agent/:agent_id Success Response (200):
{
  "success": true,
  "message": "agent assignment removed"
}

Delete Package

DELETE /api/v1/org/packages/:id Success Response (200):
{
  "success": true,
  "message": "package deleted"
}
Premium feature. Set hotel markups once and assign them per agent or org-wide. Upgrade your plan to unlock Hotel Pricing Packages →

Hotel Pricing Package

Manage org-scoped hotel pricing packages and agent-level assignments. A hotel package may define price bands (price_ranges) that drive the markup by booking total, or a single fallback markup_type / markup_value. Org-scoped packages override global defaults. A package can be assigned to the whole organization (yourself) or to individual agents — an agent-level assignment overrides the org-level one.

List Hotel Packages

GET /api/v1/org/hotel-packages Success Response (200):
{
  "success": true,
  "message": "hotel packages retrieved",
  "data": [
    {
      "id": "c3f1a2c4-...",
      "name": "Premium Hotel Package",
      "scope": "org",
      "org_id": "9551fa77-...",
      "service_type": "hotel",
      "markup_type": "flat",
      "markup_value": 150.0,
      "markup_apply_on": "commission",
      "priority": 0,
      "is_active": true,
      "price_ranges": [
        { "id": "pr1", "min_amount": 0, "max_amount": null, "markup_type": "flat", "markup_value": 100 }
      ],
      "created_at": "2026-04-15T10:00:00Z",
      "updated_at": "2026-04-15T10:00:00Z"
    }
  ]
}

Create Hotel Package

POST /api/v1/org/hotel-packages Request:
{
  "name": "Premium Hotel Package",
  "description": "Best hotel fares with a flat markup",
  "markup_type": "flat",
  "markup_value": 150.0,
  "price_ranges": [
    { "min_amount": 0, "max_amount": null, "markup_type": "flat", "markup_value": 100 }
  ]
}
Restricted fields: org admins cannot set service_fee_type / service_fee_value, gst_on_service_fee, platform_charge, min_commission or max_commission on org packages. These are platform-level terms configured by the super admin and are always stored as zero for org-scoped packages. Any of these keys sent in the request body are ignored.
Success Response (201):
{
  "success": true,
  "message": "hotel package created",
  "data": {
    "id": "c3f1a2c4-...",
    "name": "Premium Hotel Package",
    "description": "Best hotel fares with a flat markup",
    "org_id": "9551fa77-...",
    "scope": "org",
    "service_type": "hotel",
    "markup_type": "flat",
    "markup_value": 150.0,
    "markup_apply_on": "commission",
    "priority": 0,
    "is_active": true,
    "price_ranges": [
      { "id": "pr1", "min_amount": 0, "max_amount": null, "markup_type": "flat", "markup_value": 100, "sort_order": 0 }
    ],
    "created_by": "5b920162-...",
    "created_at": "2026-04-15T10:00:00Z",
    "updated_at": "2026-04-15T10:00:00Z"
  }
}

Update Hotel Package

PUT /api/v1/org/hotel-packages/:id

Same request body as Create Hotel Package. Updates all configurable fields.

Success Response (200):
{
  "success": true,
  "message": "hotel package updated",
  "data": {
    "id": "c3f1a2c4-...",
    "name": "Premium Hotel Package",
    "markup_type": "flat",
    "markup_value": 175.0,
    "markup_apply_on": "commission",
    "priority": 0,
    "is_active": true,
    "price_ranges": [
      { "id": "pr1", "min_amount": 0, "max_amount": null, "markup_type": "flat", "markup_value": 125, "sort_order": 0 }
    ],
    "updated_at": "2026-04-16T11:32:07Z"
  }
}

Delete Hotel Package

DELETE /api/v1/org/hotel-packages/:id

Performs a hard delete (scoped to the org).

Success Response (200):
{
  "success": true,
  "message": "hotel package deleted"
}

Assign Package to Organization

POST /api/v1/org/hotel-packages/assign

Assigns a hotel package to the org itself. Replaces any previous org-level assignment.

Request:
{
  "package_id": "c3f1a2c4-..."
}
Success Response (200):
{
  "success": true,
  "message": "hotel package assigned"
}

Assign Package to Agent

POST /api/v1/org/hotel-packages/assign-agent/:agent_id

Assigns a hotel package to a specific agent (agent-level override). Replaces any prior agent assignment.

Request:
{
  "package_id": "c3f1a2c4-..."
}
Success Response (200):
{
  "success": true,
  "message": "hotel package assigned to agent"
}

Delete Hotel Package

DELETE /api/v1/org/hotel-packages/:id Success Response (200):
{
  "success": true,
  "message": "hotel package deleted"
}

Fare Transactions

View fare transaction history (fare ledger) for the entire organization. Only org_admin can access these endpoints.

List Fare Transactions

GET /api/v1/org/fare-transactions

Query Parameters: page, per_page, period (weekly | monthly, default monthly).

Success Response (200):
{
  "success": true,
  "message": "fare transactions",
  "data": {
    "period": "monthly",
    "summary": {
      "total_public_fare": 125000.50,
      "total_agent_fare": 118750.48,
      "total_agent_commission": 6250.02,
      "transaction_count": 42
    },
    "transactions": [
      {
        "id": "uuid",
        "booking_ref": "GAM-ABCDEF",
        "pnr": "6EABCD",
        "agent_id": "5b920162-...",
        "agent_name": "Test Agent",
        "public_fare": 5500.00,
        "agent_fare": 5225.00,
        "agent_commission": 275.00,
        "currency": "INR",
        "issued_at": "2026-04-15T10:00:00Z"
      }
    ],
    "total": 42,
    "page": 1,
    "per_page": 20
  }
}

Agent Fare Transactions (by Agent ID)

GET /api/v1/org/fare-transactions/:agent_id

Same response shape as List Fare Transactions, but scoped to a single agent within the organization. Query Parameters: page, per_page, period (weekly | monthly, default monthly).

Success Response (200):
{
  "success": true,
  "message": "fare transactions",
  "data": {
    "period": "monthly",
    "summary": {
      "total_public_fare": 125000.50,
      "total_agent_fare": 118750.48,
      "total_agent_commission": 6250.02,
      "transaction_count": 42
    },
    "transactions": [
      {
        "id": "uuid",
        "booking_ref": "GAM-ABCDEF",
        "pnr": "6EABCD",
        "agent_id": "5b920162-...",
        "agent_name": "Test Agent",
        "public_fare": 5500.00,
        "agent_fare": 5225.00,
        "agent_commission": 275.00,
        "currency": "INR",
        "issued_at": "2026-04-15T10:00:00Z"
      }
    ],
    "total": 42,
    "page": 1,
    "per_page": 20
  }
}

Supplier Summary

GET /api/v1/org/finance-summary

Aggregated fare ledger grouped by supplier for the organization. Query Parameter: period (weekly | monthly, default monthly).

Success Response (200):
{
  "success": true,
  "message": "supplier finance summary",
  "data": {
    "period": "monthly",
    "by_supplier": [
      {
        "provider": "rezb",
        "currency": "INR",
        "public_fare": 125000.50,
        "agent_fare": 118750.48,
        "markup": 6250.02,
        "bookings": 42
      }
    ]
  }
}

Organization Reports

Generate and download org-scoped reports. Reports are generated asynchronously — create one, then poll GET /org/reports until its status is ready, then download the CSV.

Agents have an equivalent self-scoped surface under /reports and /reports/:id/download with the identical request/response schema, scoped to the requesting agent.

Generate a Report

POST /api/v1/org/reports Request:
{
  "type": "sales",
  "period_start": "2026-07-01",
  "period_end": "2026-07-31",
  "filters": {}
}

type is one of sales, agent_activity, booking, wallet. period_start / period_end are required YYYY-MM-DD.

Success Response (201):
{
  "success": true,
  "message": "report queued for generation",
  "data": {
    "id": "3f9c2b...",
    "type": "sales",
    "status": "queued",
    "period_start": "2026-07-01T00:00:00Z",
    "period_end": "2026-07-31T00:00:00Z",
    "requested_by": "5b920162-...",
    "requester_type": "org_user",
    "org_id": "9551fa77-...",
    "created_at": "2026-07-28T10:00:00Z"
  }
}

List Reports

GET /api/v1/org/reports?page=1&per_page=20 Success Response (200):
{
  "success": true,
  "data": [
    {
      "id": "3f9c2b...",
      "type": "sales",
      "status": "ready",
      "period_start": "2026-07-01T00:00:00Z",
      "period_end": "2026-07-31T00:00:00Z",
      "file_url": "/reports/3f9c2b.../download",
      "generated_at": "2026-07-28T10:01:12Z",
      "expires_at": "2026-08-28T10:01:12Z"
    }
  ],
  "meta": { "page": 1, "per_page": 20, "total": 1, "total_pages": 1 }
}

status values: queued, processing, ready, failed.

Download Report (CSV)

GET /api/v1/org/reports/:id/download

Returns the report as a CSV file attachment (Content-Disposition: attachment; filename="report-<type>-<id>.csv"), not a JSON body. The report must have status: "ready" or the API returns 400.

Response:
HTTP/1.1 200 OK
Content-Type: text/csv
Content-Disposition: attachment; filename="report-sales-3f9c2b....csv"

booking_ref,pnr,public_fare,agent_fare,...
FA-...,...,2405,2400,...

Self Profile (/me endpoints)

All authenticated org users (both org_admin and agent) can access these endpoints.

Get My Profile

GET /api/v1/me Success Response (200):
{
  "success": true,
  "message": "profile retrieved",
  "data": {
    "id": "11111111-1111-1111-1111-111111111111",
    "username": "admin",
    "email": "admin@demo.com",
    "name": "Demo Admin",
    "phone": "",
    "role": "org_admin",
    "status": "active",
    "org_id": "9551fa77-16ad-4df5-9284-dc23cb95c237",
    "sub_agent_id": "GAMDEMO0002",
    "last_login_at": "2026-04-10T14:45:35.36903+05:30"
  }
}

Update My Profile

PUT /api/v1/me Request:
{
  "name": "Updated Name",
  "phone": "+919999999999"
}
Success Response (200):
{
  "success": true,
  "message": "profile updated",
  "data": {
    "id": "11111111-1111-1111-1111-111111111111",
    "username": "admin",
    "email": "admin@demo.com",
    "name": "Updated Name",
    "phone": "+919999999999",
    "role": "org_admin",
    "status": "active"
  }
}

Change Password

PUT /api/v1/me/password Request:
{
  "current_password": "OldPassword@123",
  "new_password": "NewPassword@123"
}
Success Response (200):
{
  "success": true,
  "message": "password changed successfully"
}
Error Response (400):
{
  "success": false,
  "error": "current password is incorrect"
}

My Stats

GET /api/v1/me/stats Success Response (200):
{
  "success": true,
  "message": "stats retrieved",
  "data": {
    "total_bookings": 0,
    "confirmed_bookings": 0,
    "cancelled_bookings": 0,
    "total_spent": 0,
    "total_commissions": 0,
    "wallet_balance": 0
  }
}

Wallet (Self)

Get My Wallet

GET /api/v1/wallet Success Response (200):
{
  "success": true,
  "message": "wallet retrieved",
  "data": {
    "id": "22222222-2222-2222-2222-222222222220",
    "owner_id": "5b920162-500f-474f-8e7a-5f131053a7d5",
    "owner_type": "user",
    "balance": 5000,
    "allocated_balance": 5000,
    "currency": "INR",
    "credit_limit": 0,
    "is_active": true
  }
}

Get My Transactions

GET /api/v1/wallet/transactions

Query Parameters: page, per_page

Success Response (200):
{
  "success": true,
  "data": [
    {
      "id": "uuid",
      "type": "credit",
      "amount": 5000,
      "description": "Wallet topup from org",
      "created_at": "2026-04-15T10:00:00Z"
    }
  ],
  "meta": {
    "page": 1,
    "per_page": 20,
    "total": 1,
    "total_pages": 1
  }
}

Get Fare Rules

POST /api/v1/flights/fare-rules Request:
{
  "search_id": "srch_20260410_17407",
  "offer_ids": ["m7n4p8qr:W8j24Tcq6yjEiC6Sn8BKGwSb..."]
}

Note: Use offer_ids from the search response. Alternatively, you can pass fare_keys or booking_keys. At least one of these arrays must be non-empty.

Provider note: For m7n4p8qr, the underlying GetFareRule call may return a provider-side error (e.g. EX-Unable to get FareRule for the requested flight) in non-production/sandbox environments. The request is built correctly (it carries the track ID, flight number and travel date reconstructed from the fare key); the failure originates at the supplier, not the aggregator.
Success Response (200):
{
  "success": true,
  "message": "fare rules retrieved",
  "data": {
    "fare_key": "m7n4p8qr:W8j24Tcq6yjEiC6Sn8BKGwSb...",
    "cancellation": "Cancellation 0H-24H: INR 350",
    "date_change": "Date change allowed with fare difference",
    "baggage_policy": "Check-in: 15KG | Cabin: 7KG",
    "raw_text": "FARE BASIS: XNRA015\nFARE TYPE: Refundable\nCANCELLATION: 0H-24H penalty INR 350\nBAGGAGE: 15KG check-in + 7KG cabin"
  }
}

Price Itinerary

POST /api/v1/flights/price

One Way

{
    "offer_ids": ["m7n4p8qr:W8j24Tcq6yjEiC6Sn8BKGwSb..."],
    "adults": 1,
    "children": 0,
    "infants": 0
}

Round Trip

{
    "offer_ids": [
        "m7n4p8qr:W8j24Tcq6yjEiC6Sn8BKGwSb...",
        "m7n4p8qr:9kLm3NpQr7tYvBxZ5cFgHsJd..."
    ],
    "adults": 1,
    "children": 0,
    "infants": 0
}

Alternative format: Wrap offer_ids inside flight_selection object. The API accepts both offer_ids at root level and { flight_selection: { offer_ids: [...] } }.

Response — One Way / Round Trip

{
  "success": true,
  "message": "pricing successful",
  "data": {
    "booking_keys": ["m7n4p8qr-book:1BG8QVD8geiCxp0Phy...."],
    "status": "PRICE_VERIFIED",
    "currency": "INR",
    "expires_at": "2026-04-10T16:26:54.903522+05:30",
    "price_summary": {
      "total_payable": 2410,
      "public_fare": 2410,
      "currency": "INR",
      "exchange_rate": 1,
      "base_fare_total": 1000,
      "tax_total": 1321,
      "agent_details": {
        "agent_fare": 2405,
        "service_fee": 50,
        "gst_on_service_fee": 9,
        "platform_charge": 25
      }
    },
    "passenger_breakdown": [
      {
        "pax_type": "ADT",
        "count": 1,
        "base_per_pax": 1000,
        "tax_per_pax": 1410,
        "total_per_pax": 2410,
        "tax_breakdown": [
          { "code": "RCF", "amount": 50, "description": "Regulatory Compliance Fee" },
          { "code": "YQ", "amount": 600, "description": "Fuel Surcharge" },
          { "code": "ASF", "amount": 236, "description": "Airport Service Fee" },
          { "code": "UDF", "amount": 152, "description": "User Development Fee" }
        ]
      }
    ],
    "itinerary_snapshot": {
      "segments": [
        {
          "segment_id": "seg_1",
          "airline": "6E",
          "operating_carrier": "6E",
          "flight_number": "6E 320",
          "origin": "DEL",
          "destination": "BOM",
          "dep_terminal": "1",
          "arr_terminal": "2",
          "departure": "2026-04-15T08:40:00",
          "arrival": "2026-04-15T10:20:00",
          "cabin_class": "ECONOMY",
          "rbd": "R",
          "fare_basis": "RLIP",
          "fare_type": "B",
          "baggage": "20 KG",
          "cabin_baggage": "7 Kg",
          "refundable": true,
          "avail_seats": 114,
          "duration_minutes": 100
        }
      ]
    },
    "fare_rules": {
      "is_refundable": true,
      "cancellation_fee": null,
      "change_fee": null,
      "rule_text": null
    },
    "ancillaries": [
      {
        "type": "MEAL",
        "code": "VLML",
        "name": "Veg lacto meal + beverage",
        "price": 0,
        "segment_id": "seg_1"
      },
      {
        "type": "BAGGAGE",
        "code": "XBPC",
        "name": "ExcessBaggage 15KG",
        "price": 4500,
        "segment_id": "seg_1"
      }
    ]
  }
}
Field Reference:
Field Description
booking_keys Locked-in price keys — pass these to /book instead of the original offer_ids.
status PRICE_VERIFIED means the fare is confirmed and safe to book before expires_at.
expires_at Deadline by which the booking must be completed at this price.
price_summary.total_payable Final amount the customer pays, including all taxes.
price_summary.agent_details.agent_fare Amount that will be deducted from the agent's wallet if they proceed with booking.
passenger_breakdown[].tax_breakdown Itemized taxes and surcharges (e.g. fuel surcharge, airport fee) per passenger type.
fare_rules.is_refundable Whether this fare allows a refund on cancellation.
ancillaries Optional add-ons (meals, extra baggage, etc.) available for this itinerary, with their price.
Round Trip — itinerary_snapshot.segments difference:
"itinerary_snapshot": {
    "segments": [
      {
        "segment_id": "seg_1",
        "airline": "6E",
        "operating_carrier": "6E",
        "flight_number": "6E 320",
        "origin": "DEL",
        "destination": "BOM",
        "dep_terminal": "1",
        "arr_terminal": "2",
        "departure": "2026-05-01T08:40:00",
        "arrival": "2026-05-01T10:20:00",
        "cabin_class": "ECONOMY",
        "rbd": "R",
        "fare_basis": "RLIP",
        "fare_type": "B",
        "baggage": "15 KG",
        "cabin_baggage": "7 Kg",
        "refundable": false,
        "avail_seats": 6,
        "duration_minutes": 100
      },
      {
        "segment_id": "seg_2",
        "airline": "6E",
        "operating_carrier": "6E",
        "flight_number": "6E 455",
        "origin": "BOM",
        "destination": "DEL",
        "dep_terminal": "2",
        "arr_terminal": "3",
        "departure": "2026-05-05T19:15:00",
        "arrival": "2026-05-05T21:05:00",
        "cabin_class": "ECONOMY",
        "rbd": "R",
        "fare_basis": "RLIP",
        "fare_type": "B",
        "baggage": "15 KG",
        "cabin_baggage": "7 Kg",
        "refundable": false,
        "avail_seats": 4,
        "duration_minutes": 110
      }
    ]
}

For a round trip, every other field in the response (price_summary, passenger_breakdown, fare_rules, ancillaries) keeps the same shape shown above — only itinerary_snapshot.segments grows to one entry per flight leg (outbound + return), and the totals reflect the combined price of both legs.

Error Response (402 - Insufficient Balance):
{
  "success": false,
  "error": "insufficient wallet balance to proceed — available: 0.00, required: 2372.00 (agent fare)"
}

This means the agent's wallet doesn't have enough balance to cover the agent_fare. Top up the wallet before retrying (see Organization Wallet or Wallet (Self)).

Error Response (400 - Offer Expired):
{
  "success": false,
  "error": "offer has expired, please search again"
}

Offers from Flight Search are only valid for a short window (supplier_ref.expires_at). If pricing is attempted after that window, re-run the search and price the new offer_id.

Book Flight

POST /api/v1/flights/book

One Way

{
  "booking_keys": ["m7n4p8qr-book:1BG8QVD8gz...."],
  "contact_email": "john.doe@example.com",
  "contact_phone": "9876543210",
  "contact_country_code": "91",
  "passengers": [
    {
      "pax_index": 1,
      "type": "ADT",
      "title": "MR",
      "first_name": "JOHN",
      "last_name": "DOE",
      "gender": "Male",
      "dob": "1990-06-15",
      "infant_ref": 0,
      "ancillaries": [
        {
          "type": "MEAL",
          "code": "VLML-",
          "segment_id": "seg_1"
        }
      ]
    }
  ]
}

Round Trip

{
  "booking_keys": [
    "m7n4p8qr-book:1BG8QVD8gz....",
    "m7n4p8qr-book:9kLm3NpQr7tYvBxZ..."
  ],
  "contact_email": "john.doe@example.com",
  "contact_phone": "9876543210",
  "contact_country_code": "91",
  "passengers": [
    {
      "pax_index": 1,
      "type": "ADT",
      "title": "MR",
      "first_name": "JOHN",
      "last_name": "DOE",
      "gender": "Male",
      "dob": "1990-06-15",
      "infant_ref": 0,
      "ancillaries": [
        {
          "type": "MEAL",
          "code": "VLML-",
          "segment_id": "seg_1"
        }
      ]
    }
  ]
}
Note: The booking_keys array comes from the /price response. Use offer_ids instead if booking without pricing. If the org has ticket password enabled, include "issue_ticket_password": "your-password".

Response — One Way

{
  "success": true,
  "message": "booking confirmed",
  "data": {
    "booking_ref": "FA-1773235577155",
    "provider": "m7n4p8qr",
    "status": "CONFIRMED",
    "total_amount": 4540,
    "currency": "INR",
    "legs": [
      {
        "booking_track_id": "RACCU03000030103585841103260092140",
        "provider_pnr": "BX11HC0130",
        "airline_pnr": "U11VNS",
        "ticket_number": "BX11HC01301-1",
        "origin": "DEL",
        "destination": "CCU",
        "gross_amount": 4540,
        "currency": "INR",
        "issued_date": "11/03/2026 18:56:13"
      }
    ]
  }
}

Response — Round Trip

{
  "success": true,
  "message": "booking confirmed",
  "data": {
    "booking_ref": "FA-1773241902318",
    "provider": "m7n4p8qr",
    "status": "CONFIRMED",
    "total_amount": 4810,
    "currency": "INR",
    "legs": [
      {
        "booking_track_id": "RACCU03000030103585841103260092141",
        "provider_pnr": "BX11HC0131",
        "airline_pnr": "U11VNT",
        "ticket_number": "BX11HC01311-1",
        "origin": "DEL",
        "destination": "BOM",
        "gross_amount": 2405,
        "currency": "INR",
        "issued_date": "11/03/2026 18:59:02"
      },
      {
        "booking_track_id": "RACCU03000030103585841103260092142",
        "provider_pnr": "BX11HC0132",
        "airline_pnr": "U11VNU",
        "ticket_number": "BX11HC01311-2",
        "origin": "BOM",
        "destination": "DEL",
        "gross_amount": 2405,
        "currency": "INR",
        "issued_date": "11/03/2026 18:59:02"
      }
    ]
  }
}
Field Reference:
Field Description
booking_ref GAMAN's own booking reference — use this for all later booking-management calls.
provider Code of the airline/GDS provider that fulfilled the booking.
status CONFIRMED means seats are held; ticketing may still be pending — check tickets/issue-ticket.
legs[].booking_track_id Internal tracking ID for this leg — used by the /track endpoint.
legs[].provider_pnr / airline_pnr Reservation code from the provider system and the airline respectively — give the airline PNR to customers.
legs[].ticket_number Airline e-ticket number, once issued.

Round Trip: as shown above, the legs array contains 2 entries — the first for the outbound flight, the second for the return flight — each with its own PNR and ticket number.

Error Response (400 - Booking Failed):
{
  "success": false,
  "error": "booking key has expired, please price the itinerary again"
}

Returned when the booking_keys from Price Itinerary have passed their expires_at time before /book was called. Re-run Price Itinerary to get fresh booking_keys and retry.

List Bookings

GET /api/v1/flights/bookings

Query Parameters: page, per_page, status (pending, confirmed, cancelled)

Success Response (200):
{
  "success": true,
  "data": [
    {
      "id": "8555813d-f437-49ff-9e7e-a1d144894528",
      "booking_ref": "FA-1775272567576",
      "pnr": "BX04HD0001",
      "provider": "m7n4p8qr",
      "origin": "BOM",
      "destination": "DEL",
      "passenger_count": 1,
      "base_fare": 2162,
      "public_fare": 2162,
      "currency": "INR",
      "status": "confirmed",
      "booked_at": "2026-04-04T08:46:07.576683+05:30",
      "passengers": [
        {
          "title": "MR",
          "first_name": "JOHN",
          "last_name": "DOE",
          "type": "ADT"
        }
      ]
    }
  ],
  "meta": {
    "page": 1,
    "per_page": 20,
    "total": 3,
    "total_pages": 1
  }
}

Get Booking Details

GET /api/v1/flights/bookings/:ref Example:
GET /api/v1/flights/bookings/FA-1775272567576
Success Response (200):
{
  "success": true,
  "message": "booking retrieved",
  "data": {
    "booking_id": "ca056426-bc9a-4859-8dbc-44c5bac26e83",
    "booking_ref": "FA-1773235577155",
    "provider": "m7n4p8qr",
    "provider_ref": "RACCU03000030103585841103260092140",
    "status": "CONFIRMED",
    "created_at": "2026-03-11T18:56:17.159116+05:30",
    "currency": "INR",
    "pnr_details": [
      {
        "pnr": "BX11HC0130",
        "airline_pnr": "U11VNS",
        "airline": "6E",
        "supplier": "m7n4p8qr",
        "supplier_ref": "RACCU03000030103585841103260092140",
        "status": "CONFIRMED",
        "segment_refs": ["seg_1"],
        "ancillaries": [
          { "type": "MEAL", "code": "VLML-", "segment_id": "seg_1" }
        ]
      }
    ],
    "passengers": [
      {
        "pax_id": "pax_001",
        "type": "ADT",
        "title": "MR",
        "first_name": "JOHN",
        "last_name": "DOE",
        "dob": "1990-06-15",
        "gender": "Male",
        "seat_onward": "",
        "seat_return": ""
      }
    ],
    "itinerary": {
      "legs": [
        { "leg_index": 0, "origin": "DEL", "destination": "CCU", "segment_refs": ["seg_1"] }
      ],
      "segments": [
        {
          "segment_id": "seg_1",
          "airline": "6E",
          "flight_number": "6E 320",
          "origin": "DEL",
          "destination": "CCU",
          "departure": "2026-03-11T18:30:00",
          "arrival": "2026-03-11T20:45:00",
          "duration_minutes": 135,
          "cabin": "ECONOMY",
          "rbd": "R",
          "baggage": "15KG",
          "cabin_baggage": "7KG",
          "operating_carrier": "6E",
          "status": "CONFIRMED"
        }
      ]
    },
    "pricing": {
      "currency": "INR",
      "total_payable": 4540,
      "supplier_currency": "INR",
      "supplier_total": 4540,
      "exchange_rate": 1,
      "public_fare": 2410,
      "agent_fare": 2405,
      "ancillary": 0,
      "agent_details": {
        "agent_fare": 2405,
        "service_fee": 50,
        "gst_on_service_fee": 9,
        "platform_charge": 25
      },
      "pax_breakdown": [
        {
          "pax_id": "pax_001",
          "type": "ADT",
          "base": 1000,
          "tax": 1410,
          "total": 2410
        }
      ]
    },
    "tickets": [
      {
        "tkt_number": "BX11HC01301-1",
        "pax_id": "pax_001",
        "pnr_ref": "BX11HC0130",
        "status": "ISSUED",
        "segment_refs": ["seg_1"]
      }
    ],
    "baggage_allowance": [],
    "contact_details": {
      "country_code": "91",
      "phone": "9876543210",
      "email": "john.doe@example.com"
    },
    "can_issue_ticket": false
  }
}
Field Reference:
Field Description
pnr_details[].status Status of this specific PNR (a booking can span multiple PNRs).
passengers[].seat_onward / seat_return Assigned seat numbers, if seat selection was made — empty if not yet assigned.
pricing.public_fare vs agent_fare Customer-facing price vs. what was actually charged to the agent's wallet; the difference includes fees and commission.
pricing.ancillary Total of all ancillaries (meals / baggage / seats) selected at booking time, added on top of public_fare. Equals total_payable − public_fare − fees when present.
pricing.agent_details Optional breakdown mirroring the Price response: agent_fare, service_fee, gst_on_service_fee, platform_charge, markup_amount. Omitted when no package is assigned. Provided for reconciliation; not shown on the customer-facing booking page.
tickets[].status ISSUED means the e-ticket exists; otherwise call Issue Ticket.
can_issue_ticket Whether the /issue-ticket endpoint can currently be called for this booking.
Note: The pnr field is deprecated. Use pnr_details array for multi-PNR bookings.
Round Trip: For round trip bookings, the itinerary.legs array contains 2 entries (index 0 = outbound, index 1 = inbound), and itinerary.segments includes all segments across both legs. The pnr_details array may contain separate PNRs per leg depending on the provider.

Retrieve Booking

Fetches latest booking data directly from the provider system and returns both the local DB record and the provider's response.

GET /api/v1/flights/bookings/:ref/retrieve Example:
GET /api/v1/flights/bookings/FA-1775272567576/retrieve
Success Response (200):
{
  "success": true,
  "message": "booking retrieved",
  "data": {
    "local": {
      "booking_ref": "FA-1775272567576",
      "pnr": "BX04HD0001",
      "status": "confirmed",
      "provider": "m7n4p8qr"
    },
    "provider": {
      "booking_ref": "FA-1775272567576",
      "pnr": "BX04HD0001",
      "status": "confirmed",
      "provider_booking_id": "RACCU03000030103630040404260094069",
      "ticket_status": "CONFIRMED"
    }
  }
}

Track Booking Status

Tracks booking status from the provider. Response format is provider-specific.

GET /api/v1/flights/bookings/:ref/track Example:
GET /api/v1/flights/bookings/FA-1775272567576/track
Success Response (200) — m7n4p8qr provider:
{
  "success": true,
  "message": "booking status",
  "data": {
    "Status": {
      "Track_Status": "SUCCESS",
      "ResultCode": "1"
    },
    "TrackStatusresponse": {
      "ItinearyDetails": [
        {
          "RiyaPNR": "BX04HD0001",
          "TotalAmount": "2162.00",
          "TicketStatus": "CONFIRMED",
          "TripType": "O"
        }
      ]
    }
  }
}
Provider-specific: Response structure varies by provider. The example shows the m7n4p8qr provider format. For other providers, the response may differ.

Special Service Requests (SSR)

Retrieve and attach Special Service Requests (meals, baggage, seats) for an existing flight booking.

Get SSR (Special Services)

Retrieves Special Service Requests for a booking. Response is provider-dependent.

GET /api/v1/flights/bookings/:ref/ssr Query Parameters:
?airline_pnr=U11VNS (optional)
Example:
GET /api/v1/flights/bookings/FA-1775272567576/ssr
Success Response (200):
{
  "success": true,
  "message": "SSR options",
  "data": {
    "SsrDetails": {
      "Segments": [
        {
          "SegmentNo": "1",
          "Meals": [
            {
              "Code": "VGML",
              "Description": "Vegetarian Vegan Meal",
              "Price": 350,
              "Currency": "INR"
            },
            {
              "Code": "VLML",
              "Description": "Vegetarian Lacto/Ovo Meal",
              "Price": 350,
              "Currency": "INR"
            }
          ],
          "Baggage": [
            {
              "Code": "BAG15",
              "Description": "Extra Baggage 15 KG",
              "Price": 1200,
              "Currency": "INR"
            }
          ],
          "Seats": [
            {
              "Code": "12A",
              "Description": "Window Seat",
              "Price": 500,
              "Currency": "INR"
            },
            {
              "Code": "12B",
              "Description": "Aisle Seat",
              "Price": 500,
              "Currency": "INR"
            }
          ]
        }
      ]
    }
  }
}
Provider-specific: The SSR response format varies by provider. The airline_pnr query parameter can be used to target a specific PNR.
a3f9kx2b note: This PNR-based endpoint is supported for m7n4p8qr bookings only. a3f9kx2b returns provider does not support SSR here because a3f9kx2b exposes ancillaries via the Price response (ancillaries), not a booked-PNR lookup. Use /price to fetch a3f9kx2b SSR options.

Add SSR to Booking

Attaches ancillaries (meals / baggage / seats) to an already-booked PNR. This complements adding ancillaries at book time (see Book Flight). Supported for m7n4p8qr bookings; other providers return provider does not support adding SSR.

POST /api/v1/flights/bookings/:ref/ssr Request:
{
  "ssr": [
    {
      "type": "MEAL",
      "code": "VLML-",
      "segment_id": "seg_1",
      "pax_ref": 1,
      "name": "Veg Meal"
    }
  ],
  "remarks": ""
}

Validation: ssr is required (at least one item). Each item needs type (MEAL | BAGGAGE | SEAT | OTHER), code (the provider SSR code) and pax_ref (1-based passenger reference number). segment_id targets a specific segment.

Success Response (200):
{
  "success": true,
  "message": "SSR added",
  "data": { }
}

data is the provider's updated booking (provider-specific). On failure the provider error is returned verbatim.

Cancellation

Get the cancellation penalty for an existing flight booking before cancelling it.

Cancellation

POST /api/v1/flights/bookings/:ref/penalty Example:
POST /api/v1/flights/bookings/FA-1775272567576/penalty
Request:
{}
Success Response (200):
{
  "success": true,
  "message": "cancellation penalty",
  "data": {
    "booking_ref": "FA-1775272567576",
    "pnr": "BX04HD0001",
    "penalty": 350,
    "refund_amount": 1812,
                    "currency": "INR"
  }
}

Cancel Booking

POST /api/v1/flights/bookings/:ref/cancel Example:
POST /api/v1/flights/bookings/FA-1775272567576/cancel
Request:
{}  
Success Response (200):
{
  "success": true,
  "message": "booking cancelled"
}

Note: Always check /penalty first to see the cancellation fee before cancelling.

Issue Ticket

Issue a held (booked-but-not-ticketed) flight booking.

Issue Ticket

POST /api/v1/flights/bookings/:ref/issue-ticket Example:
POST /api/v1/flights/bookings/FA-1775272567576/issue-ticket
Request:
{
  "amount": 4540,
  "public_fare": 2410,
  "agent_fare": 2405,
  "agent_commission": 5
}

Validation: amount is required and must be > 0.

Success Response (200):
{
  "success": true,
  "message": "ticket issued",
  "data": {
    "ticket_numbers": ["BX04HD00011-1"],
    "status": "issued"
  }
}

Reschedule

Change the date/route of an existing booking: first check availability, then get the penalty quote (the new fare difference plus the provider's cancellation charge for the existing booking), and finally confirm the reschedule — which books the new itinerary and cancels (refunding to wallet) the original.

Reschedule Availability

Returns the flights available for the new date/route so you can pick a replacement before rescheduling.

POST /api/v1/flights/bookings/:ref/reschedule-avail Example:
POST /api/v1/flights/bookings/FA-1775272567576/reschedule-avail
Request:
{
  "origin": "BOM",
  "destination": "DEL",
  "new_date": "2026-06-15",
  "remarks": ""
}

Validation: origin and destination are required (3-letter IATA codes). new_date is required (format: YYYYMMDD or YYYY-MM-DD).

Success Response (200):
{
  "success": true,
  "message": "reschedule availability",
  "data": [
    {
      "itinerary_id": "itn_P9Q4N_fe0f65",
      "source": "a3f9kx2b",
      "validating_carrier": {
        "code": "IX",
        "name": "Air India Express",
        "logo_url": "https://pics.avs.io/200/200/IX.png"
      },
      "pricing": {
        "currency": "INR",
        "total": 2642,
        "base": 1001,
        "taxes": 1641,
        "fees": 0,
        "is_refundable": true,
        "provider_agent_fare": 2642
      },
      "slices": [
        {
          "slice_id": "seg_62a777",
          "duration_minutes": 140,
          "segments": [
            {
              "id": "seg_2cbfc8",
              "flight_number": "IX1056",
              "airline": "IX",
              "operating_carrier": "IX",
              "origin": { "code": "DEL", "name": "Indira Gandhi Airport", "city": "Delhi", "country": "IN", "terminal": "1" },
              "destination": { "code": "BOM", "name": "Chhatrapati Shivaji Maharaj Intl", "city": "Mumbai", "country": "IN", "terminal": "2" },
              "departure": "2026-10-01T17:50:00Z",
              "arrival": "2026-10-01T20:10:00Z",
              "duration_minutes": 140,
              "seats_available": 4,
              "cabin": "ECONOMY"
            }
          ]
        }
      ],
      "fare_key": "tbo:..."
    }
  ]
}

Reschedule Penalty Quote

Get the cost of rescheduling a booking: the new itinerary's fare difference plus the provider's cancellation charge for the existing booking.

POST /api/v1/flights/bookings/:ref/reschedule-penalty Example:
POST /api/v1/flights/bookings/FA-1775272567576/reschedule-penalty
Request:
{
  "fare_key": "m7n4p8qr:UB3OIvUu8kiJPzhNgFuo29...",
  "itinerary_id": "itn_P9Q4N_fe0f65"
}
Success Response (200):
{
  "success": true,
  "message": "reschedule penalty quote",
  "data": {
    "booking_ref": "FA-1775272567576",
    "pnr": "BX04HD0001",
    "original_agent_fare": 2400,
    "original_public_fare": 2405,
    "new_agent_fare": 2642,
    "new_public_fare": 2642,
    "fare_difference_agent": 242,
    "fare_difference_public": 237,
    "penalty": 500,
    "currency": "INR",
    "total_reschedule_charge": 737,
    "note": ""
  }
}

Confirm Reschedule

Books the new itinerary and then cancels (refunding to wallet) the original booking. Use the fare_key from the penalty quote together with the passenger / contact details from the original booking.

POST /api/v1/flights/bookings/:ref/reschedule Example:
POST /api/v1/flights/bookings/FA-1775272567576/reschedule
Request:
{
  "fare_keys": ["m7n4p8qr:UB3OIvUu8kiJPzhNgFuo29..."],
  "contact_email": "traveler@example.com",
  "contact_phone": "9999999999",
  "contact_country_code": "IN",
  "passengers": [
    {
      "pax_index": 1,
      "title": "Mr",
      "first_name": "Test",
      "last_name": "User",
      "type": "ADT",
      "gender": "Male"
    }
  ],
  "pnr": "",
  "remarks": ""
}
Success Response (200):
{
  "success": true,
  "message": "reschedule confirmed",
  "data": {
    "new_booking": {
      "booking_ref": "FA-1775279999",
      "pnr": "NEWPNR001",
      "status": "booked"
    },
    "cancellation": {
      "booking_ref": "FA-1775272567576",
      "status": "cancelled",
      "refund_to_wallet": 1900
    }
  }
}

Flight Refunds

List Refunds

GET /api/v1/flights/refunds?page=1&per_page=20

All refunds in your org (or, for agents, only your own). Supports the same page/per_page pagination.

Success Response (200):
{
  "success": true,
  "data": [
    {
      "booking_ref": "FA-1775272567576",
      "pnr": "FVRVRV",
      "booking_status": "CANCELLED",
      "refund_status": "refunded",
      "provider_refund_id": "PR-...",
      "cancellation_charge": 500,
      "provider_refund_amount": 1900,
      "platform_charges": 0,
      "refund_to_wallet": 1900,
      "currency": "INR",
      "agent_name": "John Smith",
      "cancelled_at": "2026-04-12T10:00:00Z",
      "refunded_at": "2026-04-12T12:00:00Z"
    }
  ],
  "meta": { "page": 1, "per_page": 20, "total": 1, "total_pages": 1 }
}

Refund Status

POST /api/v1/flights/bookings/:ref/refund-status

Live status of a refund for a booking reference. No request body required.

Success Response (200):
{
  "success": true,
  "message": "refund status",
  "data": {
    "booking_ref": "FA-1775272567576",
    "status": "refunded",
    "provider": "m7n4p8qr",
    "cancellation_charge": 500,
    "provider_refund_amount": 1900,
    "platform_charges": 0,
    "refund_to_wallet": 1900,
    "currency": "INR",
    "refund_id": "PR-...",
    "credit_note_no": "CN-...",
    "refunded_at": "2026-04-12T12:00:00Z",
    "message": "refund completed"
  }
}

Hotels

The Hotels API follows the standard booking lifecycle — SEARCH → PRICE → BOOK → RETRIEVE → CANCEL — through a single provider-agnostic interface. The platform currently connects to the RezLive (XMLHub) bed bank, with Travelport, Sabre and TBO hotel providers supported by the same unified layer.

Endpoint Summary

Method Endpoint Description
POST /api/v1/hotels/search Search available hotels for a stay.
POST /api/v1/hotels/price Get detailed pricing for selected rooms.
POST /api/v1/hotels/book Create a reservation.
GET /api/v1/hotels/bookings List bookings (paginated).
GET /api/v1/hotels/bookings/:ref Get a single booking's details.
POST /api/v1/hotels/bookings/:ref/cancel Cancel a reservation.

Authentication

All hotel endpoints require the same Authorization: Bearer <access_token> header and the standard role chain (authenticated user, org admin or agent). Responses always use the unified success / data / error shape.

Provider routing: the platform identifies the supplying provider from the hotel_id prefix returned by search. Every provider returns an obfuscated, prefixed id — e.g. HZL_109712 (RezLive), TBH_… (TBO), SBH_… (Sabre), TPH_… (Travelport). You never pick a provider manually — just echo the exact hotel_id values returned by search into the price / details / book steps. A hotel_id without its prefix (e.g. 109712) cannot be routed and will be rejected by /hotels/details.
Live data: hotel search returns live availability and pricing from the configured bed bank. RezLive test-panel credentials are used in staging.
Available on every plan. Hotel search, price, book, retrieve and cancel are core booking APIs and are accessible to both api_only and full organizations — they are not gated by the portal-access restriction described above.

Hotel Details

Fetch descriptive details (description, address, amenities, images, room amenities) for one or more hotels in a single call. Pass a list of hotel_ids to retrieve them all at once.

Recommended flow: After running a hotel search, use this API to pull richer information (description, photos, amenities) for the hotels you fetched — pass the hotel_ids returned by search to get full details on exactly those properties.
Provider-specific IDs: Hotel IDs are scoped to the provider that returned them — there is no common hotel ID shared across all providers. Always use the hotel_id exactly as returned by /hotels/search (it is already prefixed with the provider token, e.g. HZL109712). Sending an ID from a different provider will not resolve.

Hotel Details

POST /api/v1/hotels/details Request:
{
  "hotel_ids": ["109712", "116828"]
}
Success Response (200):
{
  "success": true,
  "message": "hotel details retrieved",
  "data": [
    {
      "provider": "HZL",
      "hotels": [
        {
          "hotel_id": "HZL109712",
          "provider_hotel_id": "109712",
          "name": "Dubai Marine Beach Resort & Spa",
          "star_rating": 5,
          "property_type": "Hotel",
          "description": "Beachfront resort...",
          "address": { "line1": "...", "city": "Dubai", "country": "AE" },
          "contact": { "phone": "...", "email": "..." },
          "images": [],
          "amenities": [],
          "room_amenities": [],
          "has_free_breakfast": true
        }
      ]
    }
  ]
}

Hotel Price

POST /api/v1/hotels/price

Locks in detailed pricing for the selected rooms of one hotel (RezLive: pre-book step). Returns a price_id that must be echoed into the book call.

Request:
{
  "search_id": "srch_hotel_20260803_a1b2c",
  "hotel_id": "HZL109712",
  "room_selections": [
    {
      "room_id": "BK-8842945",
      "rate_id": "BK-8842945",
      "quantity": 1
    }
  ]
}
Success Response (200):
{
  "success": true,
  "message": "pricing retrieved",
  "data": {
    "price_id": "HZL_price_HZL109712",
    "hotel_id": "HZL109712",
    "status": "success",
    "expires_at": "2026-08-03T06:25:00Z",
    "currency": "INR",
    "pricing_breakdown": {
      "room_charges": { "nights": 3, "rate_per_night": 5718, "subtotal": 17154 },
      "taxes": { "total_taxes": 0 },
      "fees": { "service_charge": 0, "resort_fee": 0, "total_fees": 0 },
      "discounts": { "loyalty_discount": 0, "total_discounts": 0 },
      "total_before_discount": 17154,
      "total_discount": 0,
      "total_after_discount": 17154,
      "grand_total": 17154
    }
  }
}

The grand_total is the supplier amount. Your final charge may include platform fees — use the fare block in /book to record the payable amount.

Book Hotel

POST /api/v1/hotels/book

Creates a reservation. The wallet is debited for the fare.agent_fare after the booking is persisted. An insufficient balance returns 402 Payment Required.

Request:
{
  "price_id": "HZL_price_HZL109712",
  "hotel_id": "HZL109712",
  "check_in": "2026-08-05",
  "check_out": "2026-08-08",
  "rooms": [
    {
      "room_id": "ROOM-1",
      "rate_id": "BK-8842945",
      "guests": [
        {
          "type": "adult",
          "title": "Mr",
          "first_name": "John",
          "last_name": "Doe",
          "nationality": "IN"
        },
        {
          "type": "child",
          "title": "Master",
          "first_name": "Jay",
          "last_name": "Doe"
        }
      ]
    }
  ],
  "contact": {
    "first_name": "John",
    "last_name": "Doe",
    "email": "john@example.com",
    "phone": "+911234567890"
  },
  "fare": {
    "public_fare": 17154,
    "agent_fare": 17154,
    "agent_commission": 0,
    "currency": "INR"
  }
}

Request Fields

Field Description
price_id From the /price response — resumes the pricing session.
hotel_id The prefixed id from search, e.g. HZL109712.
rooms[] Each selected room with its room_id, rate_id (booking key) and guest list.
contact Booking contact (email/phone used for the reservation).
fare Optional block echoed from pricing: public_fare, agent_fare (amount the wallet is checked and debited for), agent_commission, currency.
Success Response (201):
{
  "success": true,
  "message": "hotel booking created",
  "data": {
    "booking_id": "BK-HTL-2026-a1b2c3d4",
    "status": "confirmed",
    "confirmation_number": "RZL8824",
    "provider_confirmation": "88241230",
    "created_at": "2026-08-03T06:00:00Z",
    "hotel": { "name": "Dubai Marine Beach Resort & Spa" },
    "reservation": {
      "check_in": "2026-08-05",
      "check_out": "2026-08-08",
      "nights": 3,
      "rooms": [ { "room_type": "Deluxe Sea View Room", "guests": [] } ]
    },
    "pricing": {
      "currency": "INR",
      "room_charges": 17154,
      "taxes": 0,
      "fees": 0,
      "discounts": 0,
      "total_paid": 17154,
      "payment_status": "pending"
    }
  }
}
Persistence: every successful booking is stored with its guests, contact and the raw provider response. Fetch it anytime with GET /hotels/bookings/:ref.

List Hotel Bookings

GET /api/v1/hotels/bookings

Query Parameters: page, per_page. Org admins see the whole organization; agents see only their own bookings.

Success Response (200):
{
  "success": true,
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "booking_ref": "HTL-1785319200000",
      "provider": "HZL",
      "provider_booking_id": "88241230",
      "provider_confirmation": "RZL8824",
      "hotel_id": "HZL109712",
      "hotel_name": "Dubai Marine Beach Resort & Spa",
      "check_in": "2026-08-05",
      "check_out": "2026-08-08",
      "nights": 3,
      "room_count": 1,
      "currency": "INR",
      "total_amount": 17154,
      "net_amount": 17154,
      "public_fare": 17154,
      "status": "confirmed",
      "payment_status": "pending",
      "booked_at": "2026-08-03T06:00:00Z",
      "contact_email": "john@example.com",
      "contact_phone": "+911234567890",
      "created_at": "2026-08-03T06:00:00Z",
      "guests": [
        {
          "id": "550e8400-e29b-41d4-a716-446655440001",
          "title": "Mr",
          "first_name": "John",
          "last_name": "Doe",
          "type": "adult",
          "nationality": "IN"
        }
      ]
    }
  ],
  "meta": {
    "page": 1,
    "per_page": 20,
    "total": 1,
    "total_pages": 1
  }
}

Get Hotel Booking Details

GET /api/v1/hotels/bookings/:ref

Fetches a single booking by its booking_ref (e.g. HTL-1785319200000). If the stored status is pending, the platform refreshes it from the provider before responding.

Success Response (200):
{
  "success": true,
  "message": "hotel booking retrieved",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "booking_ref": "HTL-1785319200000",
    "provider": "HZL",
    "provider_booking_id": "88241230",
    "provider_confirmation": "RZL8824",
    "hotel_id": "HZL109712",
    "hotel_name": "Dubai Marine Beach Resort & Spa",
    "check_in": "2026-08-05",
    "check_out": "2026-08-08",
    "nights": 3,
    "room_count": 1,
    "currency": "INR",
    "total_amount": 17154,
    "net_amount": 17154,
    "public_fare": 17154,
    "status": "confirmed",
    "payment_status": "pending",
    "booked_at": "2026-08-03T06:00:00Z",
    "contact_email": "john@example.com",
    "contact_phone": "+911234567890",
    "guests": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440001",
        "title": "Mr",
        "first_name": "John",
        "last_name": "Doe",
        "type": "adult",
        "nationality": "IN"
      }
    ]
  }
}
Cross-org safety: a booking ref from another organization returns 404 — indistinguishable from "not found".

Get Voucher

GET /api/v1/hotels/bookings/:ref/voucher

Retrieves the provider voucher for a confirmed hotel booking.

Success Response (200):
{
  "success": true,
  "message": "hotel voucher retrieved",
  "data": {
    "confirmation_number": "RZL8824",
    "status": "Confirmed",
    "hotel_name": "Dubai Marine Beach Resort & Spa",
    "hotel_address": "Jumeirah Beach Road, Dubai",
    "check_in": "2026-08-05",
    "check_out": "2026-08-08",
    "currency": "INR",
    "total_price": "17154",
    "provider": "HZL"
  }
}

Cancel Hotel Booking

POST /api/v1/hotels/bookings/:ref/cancel

Cancels a reservation at the provider and updates the stored booking. Already-cancelled or refunded bookings cannot be cancelled again.

Request:
{
  "reason": "change of plans",
  "notify_guest": false
}
Success Response (200):
{
  "success": true,
  "message": "hotel booking cancelled",
  "data": {
    "booking_id": "88241230",
    "status": "cancelled",
    "cancelled_at": "2026-08-03T07:30:00Z",
    "cancellation_fee": {
      "amount": 0,
      "currency": "INR",
      "reason": ""
    },
    "refund": {
      "amount": 17154,
      "currency": "INR",
      "method": "",
      "estimated_processing_days": 0
    },
    "message": ""
  }
}

Bookings

Booking management is shared across the Flights and Hotels surfaces. org_admin users see every booking in the organization; agent users see only their own. The detailed request/response schemas for each endpoint are documented in the Flights and Hotels sections — this section is a consolidated index of the booking lifecycle APIs.

Flight Booking APIs

Method Endpoint Description
GET /api/v1/flights/bookings List the org's flight bookings (paginated).
GET /api/v1/flights/bookings/:ref Get a single flight booking's details.
GET /api/v1/flights/bookings/:ref/retrieve Re-fetch live status from the supplier.
GET /api/v1/flights/bookings/:ref/track Track booking status over time.
GET /api/v1/flights/bookings/:ref/ssr Get SSR (special service request) options.
POST /api/v1/flights/bookings/:ref/ssr Add SSR (ancillaries) to an existing booking.
POST /api/v1/flights/bookings/:ref/penalty Calculate cancellation penalty.
POST /api/v1/flights/bookings/:ref/cancel Cancel a booking (refunds to wallet).
POST /api/v1/flights/bookings/:ref/issue-ticket Issue the e-ticket.
POST /api/v1/flights/bookings/:ref/reschedule-avail Check reschedule availability.
POST /api/v1/flights/bookings/:ref/reschedule-penalty Get the reschedule penalty quote.
POST /api/v1/flights/bookings/:ref/reschedule Confirm the reschedule (books new, cancels old).

Hotel Booking APIs

Method Endpoint Description
GET /api/v1/hotels/bookings List the org's hotel bookings (paginated).
GET /api/v1/hotels/bookings/:ref Get a single hotel booking's details (refreshes pending status from supplier).
GET /api/v1/hotels/bookings/:ref/voucher Download the booking voucher.
POST /api/v1/hotels/bookings/:ref/cancel Cancel a hotel booking.

Notifications

Stay in the loop with booking, wallet, and system events. List them, count what's unread, and mark them read — one at a time or all at once.

List Notifications

GET /api/v1/notifications

Query Parameters: page, per_page

Success Response (200):
{
  "success": true,
  "data": [],
  "meta": {
    "page": 1,
    "per_page": 20,
    "total": 0,
    "total_pages": 0
  }
}

Get Unread Count

GET /api/v1/notifications/unread-count Success Response (200):
{
  "success": true,
  "message": "unread count",
  "data": {
    "unread": 0
  }
}

Mark Notification as Read

PUT /api/v1/notifications/:id/read Success Response (200):
{
  "success": true,
  "message": "notification marked as read"
}

Mark All as Read

PUT /api/v1/notifications/read-all Success Response (200):
{
  "success": true,
  "message": "all notifications marked as read"
}

Common Error Responses

Every error — whether auth, validation, or server — returns the same predictable success / error shape, so your client can handle failures in one place.

401 Unauthorized

{
  "success": false,
  "error": "invalid credentials"
}

403 Forbidden

{
  "success": false,
  "error": "access denied"
}

404 Not Found

{
  "success": false,
  "error": "resource not found"
}

422 Validation Error

{
  "success": false,
  "error": "code=422, message=[{field this field is required}]"
}

402 Payment Required (Insufficient Balance)

{
  "success": false,
  "error": "insufficient wallet balance to proceed — available: 0.00, required: 2372.00 (agent fare)"
}

429 Rate Limited

{
  "success": false,
  "error": "too many requests"
}

500 Internal Server Error

{
  "success": false,
  "error": "internal server error, please try again later"
}

Rare, and not tied to anything in your request. Safe to retry with backoff; if it persists on a specific endpoint, contact GAMAN support with the approximate request time.