openapi: 3.1.0
info:
  title: CargoMov Merchant Shipping API
  version: 1.0.0
  description: Server-to-server API for approved CargoMov Merchant stores. Never expose API keys in browser code.
servers:
  - url: https://europe-west1-cargomov-ghana.cloudfunctions.net/cargoMovMerchantApi/v1/merchant
security:
  - MerchantKey: []
    MerchantStore: []
paths:
  /quotes:
    post:
      summary: Create an authoritative delivery quote
      operationId: createQuote
      responses:
        '201': { description: Quote created, content: { application/json: { schema: { $ref: '#/components/schemas/QuoteResponse' } } } }
  /quotes/{quoteId}:
    get:
      summary: Retrieve a store-owned quote
      parameters: [{ $ref: '#/components/parameters/QuoteId' }]
      responses: { '200': { description: Quote returned } }
  /payments/verify:
    post:
      summary: Verify a Paystack payment bound to Merchant metadata
      responses: { '200': { description: Payment verified } }
  /shipments:
    post:
      summary: Idempotently create a shipment
      parameters: [{ name: Idempotency-Key, in: header, required: true, schema: { type: string, minLength: 8, maxLength: 200 } }]
      responses: { '201': { description: Shipment created }, '200': { description: Existing idempotent result } }
  /shipments/{shipmentId}:
    get:
      summary: Retrieve a store-owned shipment
      parameters: [{ $ref: '#/components/parameters/ShipmentId' }]
      responses: { '200': { description: Shipment returned } }
  /shipments/{shipmentId}/tracking:
    get:
      summary: Retrieve current delivery tracking state
      parameters: [{ $ref: '#/components/parameters/ShipmentId' }]
      responses: { '200': { description: Tracking returned } }
  /shipments/{shipmentId}/cancel:
    post:
      summary: Cancel an unassigned shipment
      parameters: [{ $ref: '#/components/parameters/ShipmentId' }]
      responses: { '200': { description: Shipment cancelled }, '409': { description: Shipment cannot be cancelled automatically } }
  /services:
    get: { summary: List enabled CargoMov vehicle services, responses: { '200': { description: Services returned } } }
  /coverage:
    get: { summary: Read current coverage policy, responses: { '200': { description: Coverage returned } } }
  /account:
    get: { summary: Read credential-bound Merchant and store status, responses: { '200': { description: Account returned } } }
components:
  securitySchemes:
    MerchantKey: { type: apiKey, in: header, name: CargoMov-Key, description: One-time secret generated from the Merchant dashboard. Keep it server-side. }
    MerchantStore: { type: apiKey, in: header, name: CargoMov-Store, description: Connected Merchant store ID. It must match the store bound to the API key. }
  parameters:
    QuoteId: { name: quoteId, in: path, required: true, schema: { type: string } }
    ShipmentId: { name: shipmentId, in: path, required: true, schema: { type: string } }
  schemas:
    Point:
      type: object
      required: [address, lat, lng]
      properties: { address: { type: string }, lat: { type: number }, lng: { type: number }, ghanaPostGps: { type: string } }
    QuoteResponse:
      type: object
      required: [ok, quoteId, expiresAt, currency, services]
      properties:
        ok: { type: boolean }
        quoteId: { type: string }
        expiresAt: { type: integer, description: Unix time in milliseconds }
        currency: { const: GHS }
        services: { type: array, items: { type: object } }

