{
  "openapi": "3.1.0",
  "info": {
    "title": "Skyfleet API",
    "version": "1.0.0",
    "description": "Skyfleet freight-aggregator REST API for custom merchant integrations.\n\n## Authentication\nEvery request is authenticated with a merchant API key sent as the `X-API-Key: sf_live_…` header (or `Authorization: Bearer sf_live_…`). Create and manage keys in the dashboard under **Settings → Developer → API Keys**, or via the `/settings/api-keys` endpoints. A key runs as its organization, so all data is automatically scoped to that merchant.\n\n## Base URL\n`https://api.skyfleetnow.com/api/v1` — always use HTTPS. The bare `http://` URL 301-redirects and most HTTP clients drop custom headers across a redirect.\n\n## Response envelope\nEvery response is wrapped: `{ \"success\": true, \"data\": … , \"message\"?: string }` on success, or `{ \"success\": false, \"message\": string, \"code\"?: string }` on error. List endpoints add `\"meta\": { total, page, limit, totalPages }`.\n\n## Typical flow\n1. `POST /rates/calculate` — quote a lane and read the `carrierId` of the option you want.\n2. `POST /shipments` — create a draft.\n3. `POST /shipments/{id}/book` — book it (AWB + label generated).\n4. Subscribe to webhooks (or poll `GET /shipments/{awb}/track`) for status.\n5. `POST /rvp/from-forward` or `POST /rvp/create` — raise a return pickup.",
    "contact": { "name": "Skyfleet Developers", "url": "https://www.skyfleetnow.com/developers" }
  },
  "servers": [
    { "url": "https://api.skyfleetnow.com/api/v1", "description": "Production" }
  ],
  "security": [{ "ApiKeyHeader": [] }],
  "tags": [
    { "name": "API Keys", "description": "Provision and revoke merchant API keys." },
    { "name": "Rates", "description": "Rate quotes, serviceability, and zone classification." },
    { "name": "Shipments", "description": "Create, book, track, label, invoice and cancel shipments." },
    { "name": "Tracking", "description": "Authenticated and public shipment tracking." },
    { "name": "Sales Channel Orders", "description": "Orders synced from connected stores (Shopify, WooCommerce, etc.)." },
    { "name": "COD", "description": "Cash-on-delivery remittances and transactions." },
    { "name": "Wallet", "description": "Prepaid wallet balance and ledger." },
    { "name": "NDR", "description": "Non-delivery reports and actions." },
    { "name": "Returns (RVP)", "description": "Reverse pickups — from a delivered order or standalone, with optional doorstep QC." },
    { "name": "Webhooks", "description": "Real-time event subscriptions delivered to your server." }
  ],
  "paths": {
    "/settings/api-keys": {
      "get": {
        "tags": ["API Keys"], "summary": "List API keys",
        "responses": { "200": { "description": "The organization's keys (hashed — full value shown only at creation).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }
      },
      "post": {
        "tags": ["API Keys"], "summary": "Create an API key",
        "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "example": "Production server" }, "expiresAt": { "type": "string", "format": "date-time", "nullable": true } } } } } },
        "responses": { "201": { "description": "The new key. The full `sf_live_…` value is returned ONCE — store it now.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }
      }
    },
    "/settings/api-keys/{id}": {
      "delete": {
        "tags": ["API Keys"], "summary": "Revoke an API key",
        "parameters": [{ "$ref": "#/components/parameters/PathId" }],
        "responses": { "200": { "description": "Key revoked (isActive=false)." } }
      }
    },
    "/rates/calculate": {
      "post": {
        "tags": ["Rates"], "summary": "Calculate rates for a lane",
        "description": "Returns one quote per serviceable courier account, cheapest first. For a reverse pickup pass `shipmentType: \"REVERSE\"` (and `isQcRequired`) to price and list only the RVP lane.",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RateRequest" }, "examples": { "forward": { "value": { "pickupPincode": "110011", "dropPincode": "400001", "weightGrams": 500, "paymentMode": "PREPAID", "lengthCm": 20, "breadthCm": 15, "heightCm": 10, "invoiceValue": 1499 } }, "reverse": { "value": { "pickupPincode": "400001", "dropPincode": "110011", "weightGrams": 500, "paymentMode": "PREPAID", "shipmentType": "REVERSE", "isQcRequired": true, "invoiceValue": 1499 } } } } } },
        "responses": { "200": { "description": "Ranked rate quotes.", "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/Envelope" }, { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Rate" } } } }] } } } } }
      }
    },
    "/rates/serviceability/detailed": {
      "get": {
        "tags": ["Rates"], "summary": "Detailed serviceability for a lane",
        "parameters": [
          { "name": "pickup", "in": "query", "required": true, "schema": { "type": "string" }, "example": "110011" },
          { "name": "drop", "in": "query", "required": true, "schema": { "type": "string" }, "example": "400001" },
          { "name": "serviceType", "in": "query", "schema": { "type": "string", "enum": ["FORWARD", "REVERSE"], "default": "FORWARD" } }
        ],
        "responses": { "200": { "description": "Per-courier serviceability.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }
      }
    },
    "/rates/classify": {
      "get": {
        "tags": ["Rates"], "summary": "Classify the zone for a lane",
        "parameters": [
          { "name": "pickup", "in": "query", "required": true, "schema": { "type": "string" }, "example": "110011" },
          { "name": "drop", "in": "query", "required": true, "schema": { "type": "string" }, "example": "400001" }
        ],
        "responses": { "200": { "description": "Zone name (LOCAL/REGIONAL/METRO/ROI/SPECIAL).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }
      }
    },
    "/shipments": {
      "get": {
        "tags": ["Shipments"], "summary": "List shipments",
        "parameters": [
          { "$ref": "#/components/parameters/Page" }, { "$ref": "#/components/parameters/Limit" },
          { "name": "status", "in": "query", "schema": { "$ref": "#/components/schemas/ShipmentStatus" } },
          { "name": "awb", "in": "query", "schema": { "type": "string" } },
          { "name": "paymentMode", "in": "query", "schema": { "type": "string", "enum": ["PREPAID", "COD"] } }
        ],
        "responses": { "200": { "description": "Paginated shipments.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PaginatedEnvelope" } } } } }
      },
      "post": {
        "tags": ["Shipments"], "summary": "Create a shipment (draft)",
        "description": "Creates a `CREATED` draft — no AWB and no courier call yet. Book it with `POST /shipments/{id}/book`. A duplicate live `orderReferenceNumber` returns 409 (`code: DUPLICATE_ORDER_REF`) unless you pass `allowDuplicate: true`.",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ShipmentCreateRequest" } } } },
        "responses": {
          "201": { "description": "Draft created.", "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/Envelope" }, { "type": "object", "properties": { "data": { "type": "object", "properties": { "shipment": { "$ref": "#/components/schemas/Shipment" }, "courierResponse": { "type": "null" } } } } }] } } } },
          "409": { "$ref": "#/components/responses/DuplicateOrderRef" }
        }
      }
    },
    "/shipments/{id}": {
      "get": {
        "tags": ["Shipments"], "summary": "Get a shipment",
        "parameters": [{ "$ref": "#/components/parameters/PathId" }],
        "responses": { "200": { "description": "The shipment with packages, items, tracking events and COD.", "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/Envelope" }, { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Shipment" } } }] } } } }, "404": { "$ref": "#/components/responses/NotFound" } }
      },
      "patch": {
        "tags": ["Shipments"], "summary": "Edit a draft",
        "parameters": [{ "$ref": "#/components/parameters/PathId" }],
        "requestBody": { "content": { "application/json": { "schema": { "type": "object", "description": "Any editable draft field (addresses, packages, remarks, isQcRequired, etc.).", "example": { "remarks": "Handle with care" } } } } },
        "responses": { "200": { "description": "Updated draft." } }
      }
    },
    "/shipments/{id}/book": {
      "post": {
        "tags": ["Shipments"], "summary": "Book a shipment",
        "description": "Allocates a courier and generates the AWB + label. Omit `carrierBrand` for auto-allocation with fail-over; pass `carrierId` (from a rate quote) to book a specific account. Requires approved KYC and a configured wallet; PREPAID must have enough balance for freight.",
        "parameters": [{ "$ref": "#/components/parameters/PathId" }],
        "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BookRequest" }, "examples": { "specific": { "value": { "carrierId": "delhivery-surface" } }, "byBrand": { "value": { "carrierBrand": "DELHIVERY", "serviceType": "SURFACE" } }, "auto": { "value": {} } } } } },
        "responses": {
          "200": { "description": "Booked. `shipment.awbNumber` and `shipment.labelUrl` are set.", "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/Envelope" }, { "type": "object", "properties": { "data": { "type": "object", "properties": { "shipment": { "$ref": "#/components/schemas/Shipment" }, "courierResponse": { "$ref": "#/components/schemas/CourierResponse" } } } } }] } } } },
          "402": { "description": "Wallet not configured or insufficient balance." },
          "403": { "description": "KYC not approved." }
        }
      }
    },
    "/shipments/{id}/cancel": {
      "post": {
        "tags": ["Shipments"], "summary": "Cancel a shipment",
        "description": "Only for `CREATED`, `LABEL_GENERATED` or `PICKUP_SCHEDULED`. Refunds debited freight to the wallet.",
        "parameters": [{ "$ref": "#/components/parameters/PathId" }],
        "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "reason": { "type": "string", "example": "Customer cancelled" } } } } } },
        "responses": { "200": { "description": "Cancellation result.", "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/Envelope" }, { "type": "object", "properties": { "data": { "type": "object", "properties": { "success": { "type": "boolean" }, "courierCancelled": { "type": "boolean" }, "courierError": { "type": "string", "nullable": true }, "refunded": { "type": "number" } } } } }] } } } } }
      }
    },
    "/shipments/{id}/label.pdf": {
      "get": {
        "tags": ["Shipments"], "summary": "Label PDF (redirects)",
        "description": "Stable Skyfleet-branded label link (the `labelUrl` returned by booking). 302-redirects to the PDF. Requires `X-API-Key`.",
        "parameters": [{ "$ref": "#/components/parameters/PathId" }],
        "responses": { "302": { "description": "Redirect to the label PDF." } }
      }
    },
    "/shipments/{id}/label-url": {
      "get": {
        "tags": ["Shipments"], "summary": "Label URL (JSON)",
        "parameters": [{ "$ref": "#/components/parameters/PathId" }],
        "responses": { "200": { "description": "`{ url }` presigned label link." } }
      }
    },
    "/shipments/{id}/invoice-url": {
      "get": {
        "tags": ["Shipments"], "summary": "Commercial invoice URL",
        "parameters": [{ "$ref": "#/components/parameters/PathId" }],
        "responses": { "200": { "description": "`{ url }` presigned invoice link." } }
      }
    },
    "/shipments/{id}/pod": {
      "get": {
        "tags": ["Shipments"], "summary": "Proof of delivery",
        "description": "POD for a delivered / RTO-delivered shipment. The first call may fetch + cache on-demand.",
        "parameters": [{ "$ref": "#/components/parameters/PathId" }],
        "responses": { "200": { "description": "POD record.", "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/Envelope" }, { "type": "object", "properties": { "data": { "type": "object", "properties": { "recipientName": { "type": "string", "nullable": true }, "recipientRelation": { "type": "string", "nullable": true }, "recipientContact": { "type": "string", "nullable": true }, "documentUrl": { "type": "string", "nullable": true }, "documentUrls": { "type": "array", "items": { "type": "string" } }, "fetchedAt": { "type": "string", "format": "date-time", "nullable": true } } } } }] } } } } }
      }
    },
    "/shipments/bulk-download": {
      "post": {
        "tags": ["Shipments"], "summary": "Bulk download labels/invoices",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["shipmentIds", "type"], "properties": { "shipmentIds": { "type": "array", "items": { "type": "string" } }, "type": { "type": "string", "enum": ["labels", "invoices"] } } } } } },
        "responses": { "200": { "description": "A merged PDF / archive link." } }
      }
    },
    "/shipments/{awb}/track": {
      "get": {
        "tags": ["Tracking"], "summary": "Track by AWB (authenticated)",
        "parameters": [{ "name": "awb", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "Current status + ordered tracking events.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } }
      }
    },
    "/public/track/{awb}": {
      "get": {
        "tags": ["Tracking"], "summary": "Public tracking (no auth)",
        "security": [],
        "parameters": [{ "name": "awb", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "Customer-safe tracking timeline (courier names sanitized)." } }
      }
    },
    "/channels": {
      "get": { "tags": ["Sales Channel Orders"], "summary": "List connected channels", "responses": { "200": { "description": "Connected store integrations." } } }
    },
    "/channels/{integrationId}": {
      "patch": {
        "tags": ["Sales Channel Orders"], "summary": "Update a channel integration",
        "parameters": [{ "name": "integrationId", "in": "path", "required": true, "schema": { "type": "string" } }],
        "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "autoCreateShipments": { "type": "boolean" }, "defaultPickupAddressId": { "type": "string" }, "defaultPaymentMode": { "type": "string", "enum": ["PREPAID", "COD"] }, "defaultWeightGrams": { "type": "integer" }, "initialSyncDays": { "type": "integer" } } } } } },
        "responses": { "200": { "description": "Updated integration." } }
      }
    },
    "/channels/orders": {
      "get": {
        "tags": ["Sales Channel Orders"], "summary": "List channel orders",
        "parameters": [
          { "name": "status", "in": "query", "schema": { "type": "string", "example": "NEW" } },
          { "name": "integrationId", "in": "query", "schema": { "type": "string" } },
          { "$ref": "#/components/parameters/Page" }, { "$ref": "#/components/parameters/Limit" }
        ],
        "responses": { "200": { "description": "Paginated channel orders.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PaginatedEnvelope" } } } } }
      }
    },
    "/channels/orders/stats": {
      "get": { "tags": ["Sales Channel Orders"], "summary": "Channel order stats", "responses": { "200": { "description": "Counts by status." } } }
    },
    "/channels/orders/{channelOrderId}/import": {
      "post": {
        "tags": ["Sales Channel Orders"], "summary": "Import one channel order → draft shipment",
        "parameters": [{ "name": "channelOrderId", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "Created draft shipment." } }
      }
    },
    "/channels/orders/{channelOrderId}/book": {
      "post": {
        "tags": ["Sales Channel Orders"], "summary": "Import + book one channel order",
        "parameters": [{ "name": "channelOrderId", "in": "path", "required": true, "schema": { "type": "string" } }],
        "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "carrierId": { "type": "string", "example": "bluedart-air" } } } } } },
        "responses": { "200": { "description": "Booked shipment." } }
      }
    },
    "/channels/orders/{channelOrderId}/skip": {
      "post": {
        "tags": ["Sales Channel Orders"], "summary": "Skip a channel order",
        "parameters": [{ "name": "channelOrderId", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "Order marked skipped." } }
      }
    },
    "/channels/orders/bulk-import": {
      "post": {
        "tags": ["Sales Channel Orders"], "summary": "Bulk import channel orders",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "orderIds": { "type": "array", "items": { "type": "string" } }, "mode": { "type": "string", "enum": ["import", "book"], "default": "import" } } } } } },
        "responses": { "200": { "description": "Import summary." } }
      }
    },
    "/cod/remittances": {
      "get": { "tags": ["COD"], "summary": "List remittances", "parameters": [{ "$ref": "#/components/parameters/Page" }, { "$ref": "#/components/parameters/Limit" }, { "name": "status", "in": "query", "schema": { "type": "string" } }], "responses": { "200": { "description": "Paginated remittances.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PaginatedEnvelope" } } } } } }
    },
    "/cod/remittance-schedule": { "get": { "tags": ["COD"], "summary": "Remittance schedule", "responses": { "200": { "description": "Remittance cadence." } } } },
    "/cod/eligible": { "get": { "tags": ["COD"], "summary": "Eligible COD", "responses": { "200": { "description": "COD eligible for the next cycle." } } } },
    "/cod/upcoming": { "get": { "tags": ["COD"], "summary": "Upcoming COD", "responses": { "200": { "description": "Upcoming COD payouts." } } } },
    "/cod/transactions": { "get": { "tags": ["COD"], "summary": "COD transactions", "parameters": [{ "$ref": "#/components/parameters/Page" }, { "$ref": "#/components/parameters/Limit" }], "responses": { "200": { "description": "Paginated COD ledger.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PaginatedEnvelope" } } } } } }
    },
    "/wallet": { "get": { "tags": ["Wallet"], "summary": "Wallet balance", "responses": { "200": { "description": "Balance + wallet type." } } } },
    "/wallet/config": { "get": { "tags": ["Wallet"], "summary": "Wallet config", "responses": { "200": { "description": "Wallet configuration." } } } },
    "/wallet/transactions": { "get": { "tags": ["Wallet"], "summary": "Wallet transactions", "parameters": [{ "$ref": "#/components/parameters/Page" }, { "$ref": "#/components/parameters/Limit" }, { "name": "category", "in": "query", "schema": { "type": "string", "example": "orders" } }], "responses": { "200": { "description": "Paginated wallet ledger.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PaginatedEnvelope" } } } } } }
    },
    "/ndr": {
      "get": { "tags": ["NDR"], "summary": "List NDRs", "parameters": [{ "$ref": "#/components/parameters/Page" }, { "$ref": "#/components/parameters/Limit" }, { "name": "status", "in": "query", "schema": { "type": "string", "example": "PENDING" } }], "responses": { "200": { "description": "Paginated NDR events.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PaginatedEnvelope" } } } } } }
    },
    "/ndr/action": {
      "post": {
        "tags": ["NDR"], "summary": "Take an NDR action",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["ndrEventId", "action"], "properties": { "ndrEventId": { "type": "string" }, "action": { "type": "string", "enum": ["REATTEMPT", "RTO", "CANCEL"], "example": "REATTEMPT" }, "preferredDate": { "type": "string", "format": "date", "example": "2026-07-12" }, "notes": { "type": "string" } } } } } },
        "responses": { "200": { "description": "Action recorded and pushed to the courier." } }
      }
    },
    "/rvp": {
      "get": {
        "tags": ["Returns (RVP)"], "summary": "List reverse pickups",
        "parameters": [{ "$ref": "#/components/parameters/Page" }, { "$ref": "#/components/parameters/Limit" }, { "name": "status", "in": "query", "schema": { "$ref": "#/components/schemas/ShipmentStatus" } }, { "name": "awb", "in": "query", "schema": { "type": "string" } }],
        "responses": { "200": { "description": "Paginated reverse shipments.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PaginatedEnvelope" } } } } }
      }
    },
    "/rvp/stats": {
      "get": { "tags": ["Returns (RVP)"], "summary": "Reverse pickup stats", "responses": { "200": { "description": "`{ total, qcRequired, byStatus }`.", "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/Envelope" }, { "type": "object", "properties": { "data": { "type": "object", "properties": { "total": { "type": "integer" }, "qcRequired": { "type": "integer" }, "byStatus": { "type": "object", "additionalProperties": { "type": "integer" } } } } } }] } } } } } }
    },
    "/rvp/from-forward": {
      "post": {
        "tags": ["Returns (RVP)"], "summary": "Create RVP from a delivered order",
        "description": "Spawns a return pickup from an existing DELIVERED / RTO-delivered forward shipment. The customer pickup address, items and dimensions are inherited from the original order. Provide `forwardShipmentId` or `forwardAwb`. Omit `items` to return the whole order; pass a subset for a partial return. Each item's `imageUrl` is sent to the pickup agent as the doorstep-QC reference.",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RvpFromForwardRequest" }, "examples": { "whole": { "value": { "forwardAwb": "SKYF0001532213", "isQcRequired": false, "reasonForReturn": "Size mismatch" } }, "withQc": { "value": { "forwardAwb": "SKYF0001532213", "isQcRequired": true, "reasonForReturn": "Wrong product", "items": [{ "itemName": "Cotton T-Shirt", "sku": "TS-01", "quantity": 1, "unitPrice": 1499, "imageUrl": "https://cdn.example.com/ts-01.jpg" }] } } } } } },
        "responses": { "200": { "description": "Reverse pickup draft created — book it to schedule pickup.", "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/Envelope" }, { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Shipment" } } }] } } } } }
      }
    },
    "/rvp/create": {
      "post": {
        "tags": ["Returns (RVP)"], "summary": "Create a standalone RVP",
        "description": "Create a fresh reverse pickup with no originating Skyfleet order (e.g. a return for an order placed on another platform). You supply both addresses and the items. `pickup` = collect from the customer; `drop` = return to your warehouse.",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RvpStandaloneRequest" }, "examples": { "standalone": { "value": { "orderReferenceNumber": "RET-9001", "isQcRequired": true, "pickup": { "name": "Ravi Kumar", "phone": "9812345678", "address": "12 MG Road", "city": "Mumbai", "state": "Maharashtra", "pincode": "400001" }, "drop": { "name": "Acme Warehouse", "phone": "9876543210", "address": "Plot 4, Industrial Area", "city": "New Delhi", "state": "Delhi", "pincode": "110011" }, "items": [{ "itemName": "Cotton T-Shirt", "sku": "TS-01", "quantity": 1, "unitPrice": 1499, "imageUrl": "https://cdn.example.com/ts-01.jpg" }], "weightKg": 0.5 } } } } } },
        "responses": { "200": { "description": "Reverse pickup draft created — book it to schedule pickup.", "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/Envelope" }, { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Shipment" } } }] } } } } }
      }
    },
    "/webhooks": {
      "get": {
        "tags": ["Webhooks"], "summary": "List subscriptions",
        "responses": { "200": { "description": "`{ subscriptions, allowedEvents }`.", "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/Envelope" }, { "type": "object", "properties": { "data": { "type": "object", "properties": { "subscriptions": { "type": "array", "items": { "$ref": "#/components/schemas/WebhookSubscription" } }, "allowedEvents": { "type": "array", "items": { "type": "string" } } } } } }] } } } } }
      },
      "post": {
        "tags": ["Webhooks"], "summary": "Create a subscription",
        "description": "Register an HTTPS endpoint. Omit `events` to receive all. The response includes the signing `secret` (used to verify `X-Skyfleet-Signature`).",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["name", "url"], "properties": { "name": { "type": "string", "example": "Production listener" }, "url": { "type": "string", "format": "uri", "example": "https://your-server.com/skyfleet-webhook" }, "events": { "type": "array", "items": { "$ref": "#/components/schemas/WebhookEvent" } } } } } } },
        "responses": { "201": { "description": "Created subscription (with `secret`).", "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/Envelope" }, { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/WebhookSubscription" } } }] } } } } }
      }
    },
    "/webhooks/{id}": {
      "patch": {
        "tags": ["Webhooks"], "summary": "Update a subscription",
        "parameters": [{ "$ref": "#/components/parameters/PathId" }],
        "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string" }, "url": { "type": "string", "format": "uri" }, "events": { "type": "array", "items": { "$ref": "#/components/schemas/WebhookEvent" } }, "isActive": { "type": "boolean" } } } } } },
        "responses": { "200": { "description": "Updated subscription." } }
      },
      "delete": {
        "tags": ["Webhooks"], "summary": "Delete a subscription",
        "parameters": [{ "$ref": "#/components/parameters/PathId" }],
        "responses": { "200": { "description": "Deleted (delivery history cascades)." } }
      }
    },
    "/webhooks/{id}/rotate-secret": {
      "post": {
        "tags": ["Webhooks"], "summary": "Rotate signing secret",
        "description": "Issues a new secret; the old one stops verifying immediately.",
        "parameters": [{ "$ref": "#/components/parameters/PathId" }],
        "responses": { "200": { "description": "`{ secret }` — the new 64-char hex secret." } }
      }
    },
    "/webhooks/{id}/test": {
      "post": {
        "tags": ["Webhooks"], "summary": "Send a test event",
        "description": "Fires a sample `test.ping` event at the subscription URL.",
        "parameters": [{ "$ref": "#/components/parameters/PathId" }],
        "responses": { "200": { "description": "`{ success, deliveryId }`." } }
      }
    },
    "/webhooks/{id}/deliveries": {
      "get": {
        "tags": ["Webhooks"], "summary": "List delivery attempts",
        "parameters": [{ "$ref": "#/components/parameters/PathId" }, { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 10, "maximum": 100, "default": 50 } }],
        "responses": { "200": { "description": "Recent delivery attempts (newest first)." } }
      }
    },
    "/webhooks/deliveries/{id}/retry": {
      "post": {
        "tags": ["Webhooks"], "summary": "Retry a failed delivery",
        "parameters": [{ "$ref": "#/components/parameters/PathId" }],
        "responses": { "200": { "description": "`{ success, newDeliveryId }`." } }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyHeader": { "type": "apiKey", "in": "header", "name": "X-API-Key", "description": "Merchant API key, e.g. `sf_live_…`. Alternatively send `Authorization: Bearer sf_live_…`." }
    },
    "parameters": {
      "PathId": { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } },
      "Page": { "name": "page", "in": "query", "schema": { "type": "integer", "default": 1, "minimum": 1 } },
      "Limit": { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 20, "minimum": 1, "maximum": 100 } }
    },
    "responses": {
      "NotFound": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "success": false, "message": "Shipment not found" } } } },
      "DuplicateOrderRef": { "description": "A live shipment already exists for this orderReferenceNumber.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "success": false, "message": "An active shipment already exists for this order reference", "code": "DUPLICATE_ORDER_REF" } } } },
      "Unauthorized": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "success": false, "message": "Access token required" } } } }
    },
    "schemas": {
      "Envelope": { "type": "object", "properties": { "success": { "type": "boolean", "example": true }, "data": {}, "message": { "type": "string" } } },
      "PaginatedEnvelope": { "type": "object", "properties": { "success": { "type": "boolean", "example": true }, "data": { "type": "array", "items": {} }, "meta": { "type": "object", "properties": { "total": { "type": "integer" }, "page": { "type": "integer" }, "limit": { "type": "integer" }, "totalPages": { "type": "integer" } } } } },
      "Error": { "type": "object", "properties": { "success": { "type": "boolean", "example": false }, "message": { "type": "string" }, "code": { "type": "string" } } },
      "ShipmentStatus": { "type": "string", "enum": ["CREATED", "LABEL_GENERATED", "PICKUP_SCHEDULED", "PICKUP_FAILED", "PICKED_UP", "IN_TRANSIT", "OUT_FOR_DELIVERY", "DELIVERED", "DELIVERY_FAILED", "RTO_INITIATED", "RTO_IN_TRANSIT", "RTO_DELIVERED", "LOST", "DAMAGED", "CANCELLED"] },
      "Address": {
        "type": "object", "required": ["name", "phone", "address", "city", "state", "pincode"],
        "properties": {
          "name": { "type": "string" }, "nickname": { "type": "string" }, "phone": { "type": "string" }, "email": { "type": "string" },
          "address": { "type": "string" }, "city": { "type": "string" }, "state": { "type": "string" }, "pincode": { "type": "string" },
          "country": { "type": "string", "default": "IN" }, "landmark": { "type": "string" }, "organisation": { "type": "string" }, "gstin": { "type": "string" },
          "addressType": { "type": "string", "enum": ["RESIDENTIAL", "COMMERCIAL"] }
        }
      },
      "Item": {
        "type": "object", "required": ["name", "quantity", "unitPrice"],
        "properties": {
          "name": { "type": "string" }, "sku": { "type": "string" }, "hsnCode": { "type": "string" }, "category": { "type": "string" },
          "brand": { "type": "string" }, "quantity": { "type": "integer" }, "unitPrice": { "type": "number" }, "taxAmount": { "type": "number" }, "gstRate": { "type": "number" }
        }
      },
      "Package": {
        "type": "object", "required": ["weightGrams", "lengthCm", "breadthCm", "heightCm", "items"],
        "properties": {
          "weightGrams": { "type": "number" }, "lengthCm": { "type": "number" }, "breadthCm": { "type": "number" }, "heightCm": { "type": "number" },
          "isFragile": { "type": "boolean" }, "isDangerous": { "type": "boolean" }, "items": { "type": "array", "items": { "$ref": "#/components/schemas/Item" } }
        }
      },
      "RateRequest": {
        "type": "object", "required": ["pickupPincode", "dropPincode", "weightGrams", "paymentMode"],
        "properties": {
          "pickupPincode": { "type": "string" }, "dropPincode": { "type": "string" }, "weightGrams": { "type": "number" },
          "lengthCm": { "type": "number" }, "breadthCm": { "type": "number" }, "heightCm": { "type": "number" },
          "paymentMode": { "type": "string", "enum": ["PREPAID", "COD"] }, "invoiceValue": { "type": "number" },
          "shipmentType": { "type": "string", "enum": ["FORWARD", "REVERSE"], "default": "FORWARD" },
          "isQcRequired": { "type": "boolean", "description": "Reverse only — selects RVP-with-QC vs without-QC pricing." }
        }
      },
      "Rate": {
        "type": "object",
        "properties": {
          "courier": { "type": "string", "description": "Merchant-facing name, e.g. \"Delhivery Surface\"." },
          "brand": { "type": "string" }, "carrierId": { "type": "string", "description": "Pass this to POST /shipments/{id}/book." },
          "serviceType": { "type": "string" }, "zone": { "type": "string" }, "totalCharge": { "type": "number" },
          "freightCharge": { "type": "number" }, "codCharge": { "type": "number" }, "gstAmount": { "type": "number" }, "eddDays": { "type": "integer" }
        }
      },
      "ShipmentCreateRequest": {
        "type": "object", "required": ["shipmentType", "paymentMode", "orderReferenceNumber", "invoiceValue", "pickup", "drop", "packages"],
        "properties": {
          "shipmentType": { "type": "string", "enum": ["FORWARD", "REVERSE", "EXCHANGE"] },
          "paymentMode": { "type": "string", "enum": ["PREPAID", "COD"] },
          "orderReferenceNumber": { "type": "string" },
          "channelOrderId": { "type": "string" }, "channelName": { "type": "string" },
          "invoiceValue": { "type": "number" }, "codAmount": { "type": "number", "default": 0 },
          "invoiceNumber": { "type": "string" }, "invoiceDate": { "type": "string", "format": "date" },
          "pickupAddressId": { "type": "string" },
          "pickup": { "$ref": "#/components/schemas/Address" },
          "drop": { "$ref": "#/components/schemas/Address" },
          "return": { "$ref": "#/components/schemas/Address" },
          "packages": { "type": "array", "items": { "$ref": "#/components/schemas/Package" } },
          "shipperGstin": { "type": "string" }, "preferredCourier": { "type": "string" },
          "carrierId": { "type": "string", "description": "Exact rate code — preserves Air vs Surface selection." },
          "isFragile": { "type": "boolean" }, "isInsured": { "type": "boolean" }, "isOtpDelivery": { "type": "boolean" },
          "vasServiceIds": { "type": "array", "items": { "type": "string" } },
          "isQcRequired": { "type": "boolean", "description": "Reverse only — doorstep QC." },
          "allowDuplicate": { "type": "boolean", "description": "Bypass the duplicate orderReferenceNumber 409 guard." },
          "remarks": { "type": "string" }
        }
      },
      "BookRequest": {
        "type": "object",
        "properties": {
          "carrierBrand": { "type": "string", "description": "Book a specific brand (no fail-over). Omit for auto-allocation." },
          "carrierId": { "type": "string", "description": "Exact rate code from a quote (preserves Air vs Surface)." },
          "serviceType": { "type": "string", "enum": ["AIR", "SURFACE", "REVERSE"] }
        }
      },
      "RvpItem": {
        "type": "object", "required": ["itemName", "quantity", "unitPrice"],
        "properties": {
          "itemName": { "type": "string" }, "sku": { "type": "string" }, "quantity": { "type": "integer" }, "unitPrice": { "type": "number" },
          "imageUrl": { "type": "string", "nullable": true, "description": "Doorstep-QC reference photo (sent to the pickup agent)." },
          "color": { "type": "string", "nullable": true }, "brand": { "type": "string", "nullable": true },
          "category": { "type": "string", "nullable": true }, "hsnCode": { "type": "string", "nullable": true }
        }
      },
      "RvpAddress": {
        "type": "object", "required": ["name", "phone", "address", "pincode"],
        "properties": {
          "name": { "type": "string" }, "phone": { "type": "string" }, "email": { "type": "string" },
          "address": { "type": "string" }, "city": { "type": "string" }, "state": { "type": "string" }, "pincode": { "type": "string" }, "landmark": { "type": "string" }
        }
      },
      "RvpFromForwardRequest": {
        "type": "object",
        "properties": {
          "forwardShipmentId": { "type": "string", "description": "Required unless forwardAwb is given." },
          "forwardAwb": { "type": "string", "description": "Alternative lookup by AWB." },
          "orderReferenceNumber": { "type": "string", "description": "Defaults to <forward-ref>-RVP." },
          "isQcRequired": { "type": "boolean", "default": false },
          "reasonForReturn": { "type": "string" },
          "dropOverride": { "$ref": "#/components/schemas/RvpAddress" },
          "items": { "type": "array", "items": { "$ref": "#/components/schemas/RvpItem" }, "description": "Omit to return all items; a subset makes it a partial return." },
          "invoiceValue": { "type": "number", "description": "Defaults to sum(unitPrice × quantity)." }
        }
      },
      "RvpStandaloneRequest": {
        "type": "object", "required": ["pickup", "drop", "items"],
        "properties": {
          "pickup": { "$ref": "#/components/schemas/RvpAddress" },
          "drop": { "$ref": "#/components/schemas/RvpAddress" },
          "items": { "type": "array", "items": { "$ref": "#/components/schemas/RvpItem" }, "minItems": 1 },
          "orderReferenceNumber": { "type": "string" },
          "isQcRequired": { "type": "boolean", "default": false },
          "invoiceValue": { "type": "number", "description": "Defaults to sum(unitPrice × quantity)." },
          "weightKg": { "type": "number", "default": 0.5 },
          "dimensionsCm": { "type": "object", "properties": { "length": { "type": "number" }, "breadth": { "type": "number" }, "height": { "type": "number" } } }
        }
      },
      "ShipmentItemOut": {
        "type": "object",
        "properties": {
          "id": { "type": "string" }, "itemName": { "type": "string" }, "sku": { "type": "string", "nullable": true },
          "hsnCode": { "type": "string", "nullable": true }, "category": { "type": "string", "nullable": true }, "brand": { "type": "string", "nullable": true },
          "color": { "type": "string", "nullable": true }, "quantity": { "type": "integer" }, "unitPrice": { "type": "number" }, "totalPrice": { "type": "number" },
          "imageUrl": { "type": "string", "nullable": true }
        }
      },
      "ShipmentPackageOut": {
        "type": "object",
        "properties": {
          "id": { "type": "string" }, "packageNumber": { "type": "integer" }, "weightGrams": { "type": "number" },
          "lengthCm": { "type": "number" }, "breadthCm": { "type": "number" }, "heightCm": { "type": "number" },
          "items": { "type": "array", "items": { "$ref": "#/components/schemas/ShipmentItemOut" } }
        }
      },
      "Shipment": {
        "type": "object",
        "description": "A shipment. Reverse pickups add the qc* / forwardShipmentId fields.",
        "properties": {
          "id": { "type": "string" }, "shipmentNumber": { "type": "string" }, "organizationId": { "type": "string" },
          "shipmentType": { "type": "string", "enum": ["FORWARD", "REVERSE", "EXCHANGE"] },
          "paymentMode": { "type": "string", "enum": ["PREPAID", "COD"] },
          "status": { "$ref": "#/components/schemas/ShipmentStatus" },
          "awbNumber": { "type": "string", "nullable": true }, "waybill": { "type": "string", "nullable": true },
          "orderReferenceNumber": { "type": "string" }, "channelOrderId": { "type": "string", "nullable": true }, "channelName": { "type": "string", "nullable": true },
          "courier": { "type": "string", "nullable": true, "description": "Internal courier enum." },
          "courierName": { "type": "string", "description": "Merchant-facing courier display name, e.g. \"Xpressbees Air\"." },
          "carrierId": { "type": "string", "nullable": true }, "courierOrderId": { "type": "string", "nullable": true },
          "invoiceValue": { "type": "number" }, "codAmount": { "type": "number" },
          "freightCharge": { "type": "number", "nullable": true }, "codCharge": { "type": "number", "nullable": true },
          "totalCharge": { "type": "number", "nullable": true }, "gstAmount": { "type": "number", "nullable": true }, "rtoCharge": { "type": "number", "nullable": true },
          "chargedWeight": { "type": "number", "nullable": true }, "billedWeight": { "type": "number", "nullable": true }, "totalWeight": { "type": "number" },
          "totalLength": { "type": "number", "nullable": true }, "totalBreadth": { "type": "number", "nullable": true }, "totalHeight": { "type": "number", "nullable": true }, "volumetricWeight": { "type": "number", "nullable": true },
          "zone": { "type": "string", "nullable": true },
          "pickupName": { "type": "string" }, "pickupPhone": { "type": "string" }, "pickupEmail": { "type": "string", "nullable": true },
          "pickupAddress": { "type": "string" }, "pickupCity": { "type": "string" }, "pickupState": { "type": "string" }, "pickupPincode": { "type": "string" },
          "dropName": { "type": "string" }, "dropPhone": { "type": "string" }, "dropEmail": { "type": "string", "nullable": true },
          "dropAddress": { "type": "string" }, "dropCity": { "type": "string" }, "dropState": { "type": "string" }, "dropPincode": { "type": "string" },
          "invoiceNumber": { "type": "string", "nullable": true }, "invoiceDate": { "type": "string", "format": "date-time", "nullable": true },
          "labelUrl": { "type": "string", "nullable": true }, "commercialInvoiceUrl": { "type": "string", "nullable": true }, "labelGeneratedAt": { "type": "string", "format": "date-time", "nullable": true },
          "isQcRequired": { "type": "boolean", "description": "Reverse only." },
          "forwardShipmentId": { "type": "string", "nullable": true, "description": "Reverse only — links an RVP to its original forward order." },
          "qcStatus": { "type": "string", "nullable": true, "enum": ["passed", "fail", "fail_hub", null], "description": "Reverse/QC — doorstep QC outcome." },
          "qcRemarks": { "type": "string", "nullable": true }, "qcImages": { "type": "array", "items": { "type": "string" }, "nullable": true, "description": "Reverse/QC — photos captured on QC failure." },
          "qcCheckedAt": { "type": "string", "format": "date-time", "nullable": true },
          "podRecipientName": { "type": "string", "nullable": true }, "podRecipientRelation": { "type": "string", "nullable": true }, "podRecipientContact": { "type": "string", "nullable": true },
          "podDocumentUrl": { "type": "string", "nullable": true }, "podFetchedAt": { "type": "string", "format": "date-time", "nullable": true },
          "isCodCollected": { "type": "boolean" }, "codCollectedAt": { "type": "string", "format": "date-time", "nullable": true },
          "orderDate": { "type": "string", "format": "date-time", "nullable": true }, "pickupScheduledAt": { "type": "string", "format": "date-time", "nullable": true },
          "pickedUpAt": { "type": "string", "format": "date-time", "nullable": true }, "deliveredAt": { "type": "string", "format": "date-time", "nullable": true }, "cancelledAt": { "type": "string", "format": "date-time", "nullable": true },
          "expectedDeliveryDate": { "type": "string", "format": "date-time", "nullable": true }, "lastStatusUpdate": { "type": "string", "format": "date-time", "nullable": true },
          "remarks": { "type": "string", "nullable": true },
          "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" },
          "packages": { "type": "array", "items": { "$ref": "#/components/schemas/ShipmentPackageOut" } }
        }
      },
      "CourierResponse": {
        "type": "object", "description": "Raw upstream booking result (mirrored for direct carriers).",
        "properties": {
          "metadata": { "type": "object", "properties": { "status": { "type": "integer" }, "message": { "type": "string" }, "success": { "type": "boolean" }, "retryable": { "type": "boolean", "nullable": true } } },
          "result": { "type": "object", "properties": { "waybill": { "type": "string" }, "order_reference_number": { "type": "string" }, "carrier_partner_id": { "type": "string" }, "courier_name": { "type": "string" }, "sort_code": { "type": "string", "nullable": true } } }
        }
      },
      "WebhookSubscription": {
        "type": "object",
        "properties": {
          "id": { "type": "string" }, "name": { "type": "string" }, "url": { "type": "string", "format": "uri" },
          "events": { "type": "array", "items": { "$ref": "#/components/schemas/WebhookEvent" }, "description": "Empty = all events." },
          "secret": { "type": "string", "description": "HMAC-SHA256 signing secret (returned on create / rotate)." },
          "isActive": { "type": "boolean" }, "totalSent": { "type": "integer" }, "totalFailed": { "type": "integer" },
          "lastFiredAt": { "type": "string", "format": "date-time", "nullable": true }, "createdAt": { "type": "string", "format": "date-time" }
        }
      },
      "WebhookEvent": {
        "type": "string",
        "description": "Subscribable event. `shipment.created` is subscribable but not currently emitted.",
        "enum": ["shipment.created", "shipment.label_generated", "shipment.pickup_scheduled", "shipment.picked_up", "shipment.in_transit", "shipment.out_for_delivery", "shipment.delivered", "shipment.delivery_failed", "shipment.rto_initiated", "shipment.rto_in_transit", "shipment.rto_delivered", "shipment.cancelled", "shipment.lost", "shipment.damaged"]
      },
      "WebhookPayload": {
        "type": "object",
        "description": "The JSON body Skyfleet POSTs to your subscription URL. Verify the raw body against X-Skyfleet-Signature (HMAC-SHA256 with your subscription secret).",
        "properties": {
          "event": { "$ref": "#/components/schemas/WebhookEvent" },
          "timestamp": { "type": "string", "format": "date-time" },
          "data": { "type": "object", "properties": { "shipment": { "type": "object", "properties": {
            "id": { "type": "string" }, "shipmentNumber": { "type": "string" }, "awbNumber": { "type": "string", "nullable": true },
            "orderReferenceNumber": { "type": "string" }, "channelOrderId": { "type": "string", "nullable": true }, "channelName": { "type": "string", "nullable": true },
            "shipmentType": { "type": "string" }, "status": { "$ref": "#/components/schemas/ShipmentStatus" }, "paymentMode": { "type": "string" },
            "courier": { "type": "string", "nullable": true }, "carrierId": { "type": "string", "nullable": true },
            "invoiceValue": { "type": "number" }, "codAmount": { "type": "number" }, "totalCharge": { "type": "number", "nullable": true }, "totalWeight": { "type": "number" },
            "dropName": { "type": "string" }, "dropCity": { "type": "string" }, "dropState": { "type": "string" }, "dropPincode": { "type": "string" },
            "pickedUpAt": { "type": "string", "format": "date-time", "nullable": true }, "deliveredAt": { "type": "string", "format": "date-time", "nullable": true }, "cancelledAt": { "type": "string", "format": "date-time", "nullable": true },
            "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" }
          } } } }
        }
      }
    }
  }
}
