{
  "openapi": "3.0.3",
  "info": {
    "title": "VeloraPay Merchant API",
    "version": "1.0.0",
    "description": "Use the VeloraPay Merchant API to record invoice details, create hosted checkout sessions, and confirm final payment state with signed webhooks."
  },
  "paths": {
    "/api/v1/checkout/cash-slips": {
      "post": {
        "operationId": "createCashDepositSlip",
        "description": "Used by VeloraPay-hosted checkout when the payer selects branch cash deposit. If an active, unexpired slip already exists, the same slip is returned with `replayed: true` so the payer does not receive two payable slips. Merchant backends should send the payer to `checkout_url`, then wait for a signed webhook or session lookup.",
        "summary": "Hosted checkout: create cash deposit slip",
        "tags": [
          "Cash Deposits"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CashDepositSlipCreate"
              },
              "examples": {
                "CreateCashSlip": {
                  "value": {
                    "session_id": "cs_example",
                    "amount_minor": 307038
                  },
                  "summary": "Create cash slip"
                }
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/CashDepositSlipCreate"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/CashDepositSlipCreate"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CashDepositSlipResponse"
                },
                "examples": {
                  "ExistingActiveSlipReplayed": {
                    "value": {
                      "slip_token": "SLIP-ABC123DEF456",
                      "reference": "s-cash-example",
                      "amount_minor": 307038,
                      "currency": "GHS",
                      "invoice_ref": "EPA-2026-001",
                      "customer_name": "Kwame Asante",
                      "status": "active",
                      "expires_at": "2026-06-15T12:00:00Z",
                      "replayed": true
                    },
                    "summary": "Existing active slip replayed"
                  }
                }
              }
            },
            "description": ""
          },
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CashDepositSlipResponse"
                },
                "examples": {
                  "CashSlipCreated": {
                    "value": {
                      "slip_token": "SLIP-ABC123DEF456",
                      "reference": "s-cash-example",
                      "amount_minor": 307038,
                      "currency": "GHS",
                      "invoice_ref": "EPA-2026-001",
                      "customer_name": "Kwame Asante",
                      "status": "active",
                      "expires_at": "2026-06-15T12:00:00Z",
                      "replayed": false
                    },
                    "summary": "Cash slip created"
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            },
            "description": ""
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "SessionIsNoLongerPayable": {
                    "value": {
                      "error": {
                        "code": "SESSION_NOT_PAYABLE",
                        "message": "Checkout session is not open for payment."
                      }
                    },
                    "summary": "Session is no longer payable"
                  }
                }
              }
            },
            "description": ""
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "RateLimited": {
                    "value": {
                      "error": {
                        "code": "RATE_LIMITED",
                        "message": "Too many requests. Try again later.",
                        "retry_after_seconds": 30
                      }
                    },
                    "summary": "Rate limited"
                  }
                }
              }
            },
            "description": ""
          }
        }
      }
    },
    "/api/v1/checkout/options": {
      "get": {
        "operationId": "listCheckoutOptions",
        "description": "Return the public choices a checkout UI needs, including payment methods, branch payment methods, and active bank branches.",
        "summary": "List checkout options",
        "tags": [
          "Checkout Options"
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicCheckoutOptions"
                }
              }
            },
            "description": ""
          }
        }
      }
    },
    "/api/v1/checkout/sessions/{reference}": {
      "get": {
        "operationId": "retrievePublicCheckoutSession",
        "description": "Used by VeloraPay-hosted checkout to show the payer the correct invoice, merchant, amount, payment methods, return link, and line items. Merchant backends should normally retrieve final payment state from `GET /api/v1/sessions/{session_id}` with their integration API key.",
        "summary": "Hosted checkout: get payer checkout details",
        "parameters": [
          {
            "in": "path",
            "name": "reference",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "Checkout Payments"
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicCheckoutSession"
                },
                "examples": {
                  "PublicCheckoutSession": {
                    "value": {
                      "id": "cs_example",
                      "merchant_name": "EPA Ghana",
                      "status": "open",
                      "amount_minor": 307038,
                      "currency": "GHS",
                      "invoice_ref": "EPA-2026-001",
                      "description": "EPA permit payment",
                      "customer_name": "Kwame Asante",
                      "allowed_rails": [
                        "momo",
                        "card",
                        "bank_transfer",
                        "cash"
                      ],
                      "expires_at": "2026-06-14T12:30:00Z",
                      "return_to_merchant_url": "https://epa.gov.gh/payments/return",
                      "card_collection_mode": "test_simulation",
                      "line_items": [
                        {
                          "code": "EPA-PERMIT",
                          "name": "Permit fee",
                          "amount_minor": 300000,
                          "currency": "GHS"
                        }
                      ]
                    },
                    "summary": "Public checkout session"
                  }
                }
              }
            },
            "description": ""
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "RateLimited": {
                    "value": {
                      "error": {
                        "code": "RATE_LIMITED",
                        "message": "Too many requests. Try again later.",
                        "retry_after_seconds": 30
                      }
                    },
                    "summary": "Rate limited"
                  }
                }
              }
            },
            "description": ""
          }
        }
      }
    },
    "/api/v1/checkout/sessions/{reference}/provider-attempts": {
      "post": {
        "operationId": "startCheckoutPayment",
        "description": "Used by VeloraPay-hosted checkout after the payer selects Mobile Money or bank transfer. Standard merchant integrations should send the payer to `checkout_url`, then confirm final status with signed webhooks or `GET /api/v1/sessions/{session_id}`.",
        "summary": "Hosted checkout: start payment method",
        "parameters": [
          {
            "in": "path",
            "name": "reference",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "Checkout Payments"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProviderPaymentInitiate"
              },
              "examples": {
                "HostedCheckoutStartsMobileMoney": {
                  "value": {
                    "rail": "momo",
                    "amount_minor": 311644,
                    "operator": "MTN",
                    "phone": "0240000000",
                    "account_name": "Kwame Asante"
                  },
                  "summary": "Hosted checkout starts Mobile Money"
                }
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/ProviderPaymentInitiate"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/ProviderPaymentInitiate"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderPaymentInitiationResponse"
                },
                "examples": {
                  "ExistingAttemptReplayed": {
                    "value": {
                      "attempt_reference": "s_example",
                      "provider": "fincra",
                      "provider_reference": "fcr_cs_example_momo_example",
                      "rail": "momo",
                      "status": "pending",
                      "amount_charged_minor": 311644,
                      "currency": "GHS",
                      "instructions": {
                        "mode": "mobile_money_prompt",
                        "rail": "momo"
                      },
                      "replayed": true
                    },
                    "summary": "Existing attempt replayed"
                  }
                }
              }
            },
            "description": ""
          },
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderPaymentInitiationResponse"
                },
                "examples": {
                  "MobileMoneyRequestSent": {
                    "value": {
                      "attempt_reference": "s_example",
                      "provider": "fincra",
                      "provider_reference": "fcr_cs_example_momo_example",
                      "rail": "momo",
                      "status": "pending",
                      "amount_charged_minor": 311644,
                      "currency": "GHS",
                      "instructions": {
                        "mode": "mobile_money_prompt",
                        "rail": "momo",
                        "amount_minor": 311644,
                        "currency": "GHS",
                        "operator": "MTN",
                        "phone_last4": "0000"
                      },
                      "replayed": false
                    },
                    "summary": "Mobile Money request sent"
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            },
            "description": ""
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "SessionIsNoLongerPayable": {
                    "value": {
                      "error": {
                        "code": "SESSION_NOT_PAYABLE",
                        "message": "Checkout session is not open for payment."
                      }
                    },
                    "summary": "Session is no longer payable"
                  },
                  "QuotedAmountChanged": {
                    "value": {
                      "error": {
                        "code": "PAYMENT_AMOUNT_MISMATCH",
                        "message": "Quoted amount does not match the current session total."
                      }
                    },
                    "summary": "Quoted amount changed"
                  }
                }
              }
            },
            "description": ""
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "RateLimited": {
                    "value": {
                      "error": {
                        "code": "RATE_LIMITED",
                        "message": "Too many requests. Try again later.",
                        "retry_after_seconds": 30
                      }
                    },
                    "summary": "Rate limited"
                  }
                }
              }
            },
            "description": ""
          }
        }
      }
    },
    "/api/v1/checkout/sessions/{reference}/provider-attempts/{attempt_reference}": {
      "get": {
        "operationId": "retrieveCheckoutPaymentStatus",
        "description": "Read the current payment-method status for hosted checkout. A return to your site is not proof of payment; fulfil only after the checkout reaches a final successful state.",
        "summary": "Hosted checkout: get payment status",
        "parameters": [
          {
            "in": "path",
            "name": "attempt_reference",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "reference",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "query",
            "name": "refresh",
            "schema": {
              "type": "boolean"
            },
            "description": "Set to 1 to refresh the payment status before returning it. Fulfil only after the checkout reaches a final state; a redirect alone is not proof of payment."
          }
        ],
        "tags": [
          "Checkout Payments"
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderPaymentStatusResponse"
                },
                "examples": {
                  "ProviderPaymentStatus": {
                    "value": {
                      "attempt_reference": "s_example",
                      "provider": "fincra",
                      "provider_reference": "fcr_cs_example_momo_example",
                      "rail": "momo",
                      "status": "pending",
                      "amount_charged_minor": 311644,
                      "currency": "GHS",
                      "session_id": "cs_example",
                      "session_status": "pending",
                      "session_finalized_at": null,
                      "raw_status": "initiated",
                      "refreshed": false,
                      "finalized": false
                    },
                    "summary": "Provider payment status"
                  }
                }
              }
            },
            "description": ""
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            },
            "description": ""
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "RateLimited": {
                    "value": {
                      "error": {
                        "code": "RATE_LIMITED",
                        "message": "Too many requests. Try again later.",
                        "retry_after_seconds": 30
                      }
                    },
                    "summary": "Rate limited"
                  }
                }
              }
            },
            "description": ""
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            },
            "description": ""
          }
        }
      }
    },
    "/api/v1/checkout/sessions/{reference}/provider-attempts/{attempt_reference}/authorize": {
      "post": {
        "operationId": "confirmMobileMoneyPayment",
        "description": "Used by VeloraPay-hosted checkout to submit the payer's Mobile Money verification code when one is required. Merchant backends should confirm payment from signed webhooks or `GET /api/v1/sessions/{session_id}`.",
        "summary": "Hosted checkout: confirm Mobile Money code",
        "parameters": [
          {
            "in": "path",
            "name": "attempt_reference",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "reference",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "Checkout Payments"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProviderPaymentAuthorize"
              },
              "examples": {
                "SubmitMobileMoneyCode": {
                  "value": {
                    "code": "123456"
                  },
                  "summary": "Submit Mobile Money code"
                }
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/ProviderPaymentAuthorize"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/ProviderPaymentAuthorize"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderPaymentStatusResponse"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            },
            "description": ""
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            },
            "description": ""
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "RateLimited": {
                    "value": {
                      "error": {
                        "code": "RATE_LIMITED",
                        "message": "Too many requests. Try again later.",
                        "retry_after_seconds": 30
                      }
                    },
                    "summary": "Rate limited"
                  }
                }
              }
            },
            "description": ""
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            },
            "description": ""
          }
        }
      }
    },
    "/api/v1/checkout/sessions/{reference}/provider-attempts/{attempt_reference}/resend": {
      "post": {
        "operationId": "resendMobileMoneyVerification",
        "description": "Used by VeloraPay-hosted checkout to request another Mobile Money verification code while the payer is still on the checkout page. Merchant backends should wait for the terminal webhook or retrieve the checkout session by id.",
        "summary": "Hosted checkout: resend Mobile Money code",
        "parameters": [
          {
            "in": "path",
            "name": "attempt_reference",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "reference",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "Checkout Payments"
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderPaymentStatusResponse"
                },
                "examples": {
                  "MobileMoneyCodeResent": {
                    "value": {
                      "attempt_reference": "s_example",
                      "provider": "fincra",
                      "provider_reference": "fcr_cs_example_momo_example",
                      "rail": "momo",
                      "status": "pending",
                      "amount_charged_minor": 311644,
                      "currency": "GHS",
                      "session_id": "cs_example",
                      "session_status": "open",
                      "session_finalized_at": null,
                      "raw_status": "processing",
                      "refreshed": false,
                      "finalized": false
                    },
                    "summary": "Mobile Money code resent"
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            },
            "description": ""
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            },
            "description": ""
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "RateLimited": {
                    "value": {
                      "error": {
                        "code": "RATE_LIMITED",
                        "message": "Too many requests. Try again later.",
                        "retry_after_seconds": 30
                      }
                    },
                    "summary": "Rate limited"
                  }
                }
              }
            },
            "description": ""
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            },
            "description": ""
          }
        }
      }
    },
    "/api/v1/checkout/sessions/{reference}/quote": {
      "get": {
        "operationId": "retrievePublicCheckoutQuote",
        "description": "Used by VeloraPay-hosted checkout to calculate display totals and payer-borne fees for each enabled payment method on an open checkout. Standard merchant integrations send the payer to `checkout_url`; they do not call this endpoint in the hosted flow.",
        "summary": "Hosted checkout: quote checkout totals",
        "parameters": [
          {
            "in": "path",
            "name": "reference",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "Checkout Payments"
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicCheckoutQuoteResponse"
                },
                "examples": {
                  "PublicCheckoutQuote": {
                    "value": {
                      "id": "cs_example",
                      "status": "open",
                      "base_minor": 307038,
                      "currency": "GHS",
                      "expires_at": "2026-06-14T12:30:00Z",
                      "allowed_rails": [
                        "momo",
                        "card",
                        "cash"
                      ],
                      "surcharges": {
                        "momo": {
                          "bearer": "payer",
                          "fee_minor": 4606,
                          "surcharge_minor": 4606,
                          "total_minor": 311644,
                          "currency": "GHS"
                        },
                        "cash": {
                          "bearer": "merchant",
                          "fee_minor": 0,
                          "surcharge_minor": 0,
                          "total_minor": 307038,
                          "currency": "GHS"
                        }
                      }
                    },
                    "summary": "Public checkout quote"
                  }
                }
              }
            },
            "description": ""
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "SessionIsNoLongerPayable": {
                    "value": {
                      "error": {
                        "code": "SESSION_NOT_PAYABLE",
                        "message": "Checkout session is not open for payment."
                      }
                    },
                    "summary": "Session is no longer payable"
                  }
                }
              }
            },
            "description": ""
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "RateLimited": {
                    "value": {
                      "error": {
                        "code": "RATE_LIMITED",
                        "message": "Too many requests. Try again later.",
                        "retry_after_seconds": 30
                      }
                    },
                    "summary": "Rate limited"
                  }
                }
              }
            },
            "description": ""
          }
        }
      }
    },
    "/api/v1/invoice-lines": {
      "get": {
        "operationId": "listInvoiceLines",
        "description": "Return the line items recorded for one invoice reference. Treat payment status as the checkout's responsibility: use the matching checkout session or webhook confirmation to decide when the invoice is paid.",
        "summary": "List invoice lines",
        "parameters": [
          {
            "in": "query",
            "name": "invoice_ref",
            "schema": {
              "type": "string"
            },
            "description": "Your invoice reference for the checkout session.",
            "required": true
          }
        ],
        "tags": [
          "Service Codes"
        ],
        "security": [
          {
            "merchantApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MerchantInvoiceLineListResponse"
                },
                "examples": {
                  "InvoiceLines": {
                    "value": {
                      "object": "invoice.line_items",
                      "invoice_ref": "EPA-2026-001",
                      "lines": [
                        {
                          "code": "EPA-PERMIT",
                          "name": "Permit fee",
                          "amount_minor": 300000,
                          "currency": "GHS",
                          "remitted": false
                        }
                      ],
                      "total_minor": 300000
                    },
                    "summary": "Invoice lines"
                  }
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            },
            "description": ""
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "InvalidAPIKey": {
                    "value": {
                      "error": {
                        "code": "UNAUTHORIZED",
                        "message": "Invalid API key."
                      }
                    },
                    "summary": "Invalid API key"
                  }
                }
              }
            },
            "description": ""
          }
        }
      },
      "post": {
        "operationId": "ingestInvoiceLines",
        "description": "Record the billable lines for one invoice before or alongside checkout creation. Use the same `invoice_ref` on the checkout session so the payment can be linked back to these service-code amounts.",
        "summary": "Record invoice lines",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional key for safe retries. Reuse the same key with the same request body to receive the original result; use a new key when the request body changes."
          }
        ],
        "tags": [
          "Service Codes"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MerchantInvoiceLineIngest"
              },
              "examples": {
                "IngestInvoiceLines": {
                  "value": {
                    "invoice_ref": "EPA-2026-001",
                    "currency": "GHS",
                    "lines": [
                      {
                        "code": "EPA-PERMIT",
                        "name": "Permit fee",
                        "amount_minor": 300000
                      },
                      {
                        "code": "EPA-LEVY",
                        "name": "Environmental levy",
                        "amount_minor": 7038
                      }
                    ]
                  },
                  "summary": "Ingest invoice lines"
                }
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/MerchantInvoiceLineIngest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/MerchantInvoiceLineIngest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "merchantApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MerchantInvoiceLineIngestResponse"
                },
                "examples": {
                  "InvoiceLinesIngested": {
                    "value": {
                      "object": "invoice.line_items",
                      "invoice_ref": "EPA-2026-001",
                      "ingested": 2,
                      "billed_minor": 307038,
                      "errors": []
                    },
                    "summary": "Invoice lines ingested"
                  }
                }
              }
            },
            "description": ""
          },
          "207": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MerchantInvoiceLineIngestResponse"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            },
            "description": ""
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "InvalidAPIKey": {
                    "value": {
                      "error": {
                        "code": "UNAUTHORIZED",
                        "message": "Invalid API key."
                      }
                    },
                    "summary": "Invalid API key"
                  }
                }
              }
            },
            "description": ""
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            },
            "description": ""
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "IdempotencyKeyReusedWithDifferentBody": {
                    "value": {
                      "error": {
                        "code": "IDEMPOTENCY_KEY_REUSED",
                        "message": "This Idempotency-Key was already used with a different request body."
                      }
                    },
                    "summary": "Idempotency key reused with different body"
                  }
                }
              }
            },
            "description": ""
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "RateLimited": {
                    "value": {
                      "error": {
                        "code": "RATE_LIMITED",
                        "message": "Too many requests. Try again later.",
                        "retry_after_seconds": 30
                      }
                    },
                    "summary": "Rate limited"
                  }
                }
              }
            },
            "description": ""
          }
        }
      }
    },
    "/api/v1/revenue-lines": {
      "get": {
        "operationId": "listRevenueLines",
        "description": "List the service codes your account can collect against. Use these codes on invoice lines so collections can be reported and settled by revenue line.",
        "summary": "List revenue lines",
        "parameters": [
          {
            "in": "query",
            "name": "include_inactive",
            "schema": {
              "type": "boolean"
            },
            "description": "Set to true to include inactive service codes."
          }
        ],
        "tags": [
          "Service Codes"
        ],
        "security": [
          {
            "merchantApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MerchantRevenueLineListResponse"
                },
                "examples": {
                  "RevenueLines": {
                    "value": {
                      "object": "list",
                      "lines": [
                        {
                          "id": "9f221ec6-8be2-46d5-a911-3f52931d59c5",
                          "merchant_id": "0a0787bd-bcc5-4e5e-9ed7-51583565dc3e",
                          "code": "EPA-PERMIT",
                          "name": "Permit fee",
                          "active": true,
                          "source": "sync",
                          "last_synced_at": "2026-06-14T12:00:00Z",
                          "created_at": "2026-06-14T12:00:00Z",
                          "updated_at": "2026-06-14T12:00:00Z"
                        }
                      ],
                      "counts": {
                        "total": 1,
                        "active": 1,
                        "inactive": 0
                      }
                    },
                    "summary": "Revenue lines"
                  }
                }
              }
            },
            "description": ""
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "InvalidAPIKey": {
                    "value": {
                      "error": {
                        "code": "UNAUTHORIZED",
                        "message": "Invalid API key."
                      }
                    },
                    "summary": "Invalid API key"
                  }
                }
              }
            },
            "description": ""
          }
        }
      },
      "post": {
        "operationId": "syncRevenueLines",
        "description": "Add or update service codes from your billing system in one request. Syncing revenue lines prepares your account for invoice line ingestion; it does not create a checkout session.",
        "summary": "Sync revenue lines",
        "tags": [
          "Service Codes"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MerchantRevenueLineBulk"
              },
              "examples": {
                "SyncRevenueLines": {
                  "value": {
                    "lines": [
                      {
                        "code": "EPA-PERMIT",
                        "name": "Permit fee"
                      },
                      {
                        "code": "EPA-LEVY",
                        "name": "Environmental levy"
                      }
                    ],
                    "deactivate_missing": false
                  },
                  "summary": "Sync revenue lines"
                }
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/MerchantRevenueLineBulk"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/MerchantRevenueLineBulk"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "merchantApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MerchantRevenueLineSyncResponse"
                },
                "examples": {
                  "RevenueLinesSynced": {
                    "value": {
                      "object": "revenue_lines.sync",
                      "created": 1,
                      "updated": 1,
                      "reactivated": 0,
                      "deactivated": 0,
                      "unchanged": 0,
                      "total": 2,
                      "errors": []
                    },
                    "summary": "Revenue lines synced"
                  }
                }
              }
            },
            "description": ""
          },
          "207": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MerchantRevenueLineSyncResponse"
                }
              }
            },
            "description": ""
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "InvalidAPIKey": {
                    "value": {
                      "error": {
                        "code": "UNAUTHORIZED",
                        "message": "Invalid API key."
                      }
                    },
                    "summary": "Invalid API key"
                  }
                }
              }
            },
            "description": ""
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "RateLimited": {
                    "value": {
                      "error": {
                        "code": "RATE_LIMITED",
                        "message": "Too many requests. Try again later.",
                        "retry_after_seconds": 30
                      }
                    },
                    "summary": "Rate limited"
                  }
                }
              }
            },
            "description": ""
          }
        }
      }
    },
    "/api/v1/sessions": {
      "post": {
        "operationId": "createCheckoutSession",
        "description": "Create a payer checkout from your invoice data. Call this from your server with a merchant API key, then send the returned `checkout_url` to the payer.",
        "summary": "Create checkout session",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional key for safe retries. Reuse the same key with the same request body to receive the original result; use a new key when the request body changes."
          }
        ],
        "tags": [
          "Checkout Sessions"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutSessionCreate"
              },
              "examples": {
                "CreateCheckoutSession": {
                  "value": {
                    "amount_minor": 307038,
                    "invoice_ref": "EPA-2026-001",
                    "description": "EPA permit payment",
                    "currency": "GHS",
                    "customer": {
                      "name": "Kwame Asante",
                      "email": "kwame@example.com"
                    },
                    "callback_url": "https://epa.gov.gh/payments/return",
                    "metadata": {
                      "source": "merchant_invoice_api"
                    },
                    "expires_in_seconds": 1800
                  },
                  "summary": "Create checkout session"
                }
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutSessionCreate"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutSessionCreate"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "merchantApiKeyAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutSessionResponse"
                },
                "examples": {
                  "SessionCreated": {
                    "value": {
                      "id": "cs_example",
                      "status": "open",
                      "amount_minor": 307038,
                      "currency": "GHS",
                      "invoice_ref": "EPA-2026-001",
                      "description": "EPA permit payment",
                      "checkout_url": "https://velorapay-checkout-staging-fxzcszzkha-uc.a.run.app/pay/cs_example",
                      "expires_at": "2026-06-14T12:30:00Z"
                    },
                    "summary": "Session created"
                  }
                }
              }
            },
            "description": ""
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "InvalidAPIKey": {
                    "value": {
                      "error": {
                        "code": "UNAUTHORIZED",
                        "message": "Invalid API key."
                      }
                    },
                    "summary": "Invalid API key"
                  }
                }
              }
            },
            "description": ""
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            },
            "description": ""
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "IdempotencyKeyReusedWithDifferentBody": {
                    "value": {
                      "error": {
                        "code": "IDEMPOTENCY_KEY_REUSED",
                        "message": "This Idempotency-Key was already used with a different request body."
                      }
                    },
                    "summary": "Idempotency key reused with different body"
                  }
                }
              }
            },
            "description": ""
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "RateLimited": {
                    "value": {
                      "error": {
                        "code": "RATE_LIMITED",
                        "message": "Too many requests. Try again later.",
                        "retry_after_seconds": 30
                      }
                    },
                    "summary": "Rate limited"
                  }
                }
              }
            },
            "description": ""
          }
        }
      }
    },
    "/api/v1/sessions/{reference}": {
      "get": {
        "operationId": "retrieveCheckoutSession",
        "description": "Read a checkout session you created. Use this from your server to confirm the amount, status, invoice reference, and checkout link for your records.",
        "summary": "Get checkout session",
        "parameters": [
          {
            "in": "path",
            "name": "reference",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "Checkout Sessions"
        ],
        "security": [
          {
            "merchantApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutSessionResponse"
                }
              }
            },
            "description": ""
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "InvalidAPIKey": {
                    "value": {
                      "error": {
                        "code": "UNAUTHORIZED",
                        "message": "Invalid API key."
                      }
                    },
                    "summary": "Invalid API key"
                  }
                }
              }
            },
            "description": ""
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "BankOption": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "branches": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BranchOption"
            }
          }
        },
        "required": [
          "branches",
          "code",
          "id",
          "name"
        ]
      },
      "BranchOption": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "code": {
            "type": "string"
          }
        },
        "required": [
          "code",
          "id",
          "name"
        ]
      },
      "CardCollectionModeEnum": {
        "enum": [
          "direct_card",
          "test_simulation"
        ],
        "type": "string",
        "description": "* `direct_card` - direct_card\n* `test_simulation` - test_simulation"
      },
      "CashDepositSlipCreate": {
        "type": "object",
        "properties": {
          "session_id": {
            "type": "string",
            "maxLength": 80
          },
          "amount_minor": {
            "type": "integer",
            "minimum": 1
          }
        },
        "required": [
          "amount_minor",
          "session_id"
        ]
      },
      "CashDepositSlipResponse": {
        "type": "object",
        "properties": {
          "slip_token": {
            "type": "string"
          },
          "reference": {
            "type": "string"
          },
          "amount_minor": {
            "type": "integer"
          },
          "currency": {
            "type": "string"
          },
          "merchant_name": {
            "type": "string"
          },
          "session_reference": {
            "type": "string"
          },
          "invoice_ref": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "customer_name": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "replayed": {
            "type": "boolean"
          },
          "can_record": {
            "type": "boolean"
          }
        },
        "required": [
          "amount_minor",
          "can_record",
          "currency",
          "customer_name",
          "description",
          "expires_at",
          "invoice_ref",
          "merchant_name",
          "reference",
          "replayed",
          "session_reference",
          "slip_token",
          "status"
        ]
      },
      "CheckoutSessionCreate": {
        "type": "object",
        "properties": {
          "amount_minor": {
            "type": "integer",
            "minimum": 1
          },
          "invoice_ref": {
            "type": "string",
            "maxLength": 120
          },
          "description": {
            "type": "string",
            "maxLength": 240
          },
          "currency": {
            "type": "string",
            "default": "GHS",
            "maxLength": 3
          },
          "customer": {
            "$ref": "#/components/schemas/Customer"
          },
          "callback_url": {
            "type": "string",
            "format": "uri",
            "maxLength": 500
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {}
          },
          "expires_in_seconds": {
            "type": "integer",
            "maximum": 86400,
            "minimum": 60
          }
        },
        "required": [
          "amount_minor",
          "invoice_ref"
        ]
      },
      "CheckoutSessionResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/CheckoutSessionStatusEnum"
          },
          "amount_minor": {
            "type": "integer"
          },
          "currency": {
            "type": "string",
            "maxLength": 3
          },
          "invoice_ref": {
            "type": "string",
            "maxLength": 120
          },
          "description": {
            "type": "string",
            "maxLength": 240
          },
          "checkout_url": {
            "type": "string",
            "readOnly": true
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "amount_minor",
          "checkout_url",
          "expires_at",
          "id",
          "invoice_ref"
        ]
      },
      "CheckoutSessionStatusEnum": {
        "enum": [
          "open",
          "pending",
          "success",
          "failed",
          "expired"
        ],
        "type": "string",
        "description": "* `open` - Open\n* `pending` - Pending\n* `success` - Success\n* `failed` - Failed\n* `expired` - Expired"
      },
      "ChoiceOption": {
        "type": "object",
        "properties": {
          "value": {
            "type": "string"
          },
          "label": {
            "type": "string"
          }
        },
        "required": [
          "label",
          "value"
        ]
      },
      "Customer": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 200
          },
          "email": {
            "type": "string",
            "format": "email"
          }
        }
      },
      "ErrorDetail": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "retry_after_seconds": {
            "type": "integer"
          }
        },
        "required": [
          "code",
          "message"
        ]
      },
      "ErrorEnvelope": {
        "type": "object",
        "properties": {
          "error": {
            "$ref": "#/components/schemas/ErrorDetail"
          }
        },
        "required": [
          "error"
        ]
      },
      "MerchantErrorCatalogItem": {
        "type": "object",
        "required": [
          "code",
          "meaning",
          "recovery"
        ],
        "properties": {
          "code": {
            "$ref": "#/components/schemas/MerchantErrorCode"
          },
          "meaning": {
            "type": "string"
          },
          "recovery": {
            "type": "string"
          }
        }
      },
      "MerchantErrorCode": {
        "type": "string",
        "enum": [
          "UNAUTHORIZED",
          "RATE_LIMITED",
          "IDEMPOTENCY_KEY_REUSED",
          "IDEMPOTENCY_KEY_IN_FLIGHT",
          "IDEMPOTENCY_IN_PROGRESS",
          "INVALID_ARGUMENT",
          "INVOICE_LINE_AMOUNT_INVALID",
          "MERCHANT_ID_REQUIRED",
          "PAYMENT_AMOUNT_MISMATCH",
          "PAYMENT_ATTEMPT_PENDING",
          "PROVIDER_PAYMENT_REJECTED",
          "PROVIDER_RAIL_UNAVAILABLE",
          "PROVIDER_RAIL_UNSUPPORTED",
          "RAIL_NOT_ALLOWED",
          "SESSION_NOT_PAYABLE",
          "WEBHOOK_URL_UNSAFE",
          "FEE_QUOTE_INVALID"
        ],
        "description": "Stable merchant-facing error codes returned in error.code."
      },
      "MerchantInvoiceLineIngest": {
        "type": "object",
        "properties": {
          "invoice_ref": {
            "type": "string",
            "maxLength": 120
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MerchantInvoiceLineInput"
            }
          },
          "currency": {
            "type": "string",
            "default": "GHS",
            "maxLength": 3
          }
        },
        "required": [
          "invoice_ref",
          "lines"
        ]
      },
      "MerchantInvoiceLineIngestResponse": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string"
          },
          "invoice_ref": {
            "type": "string"
          },
          "ingested": {
            "type": "integer"
          },
          "billed_minor": {
            "type": "integer"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": {}
            }
          }
        },
        "required": [
          "billed_minor",
          "errors",
          "ingested",
          "invoice_ref",
          "object"
        ]
      },
      "MerchantInvoiceLineInput": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "maxLength": 80
          },
          "name": {
            "type": "string",
            "maxLength": 200
          },
          "amount_minor": {
            "type": "integer",
            "minimum": 1
          }
        },
        "required": [
          "amount_minor",
          "code"
        ]
      },
      "MerchantInvoiceLineListResponse": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string"
          },
          "invoice_ref": {
            "type": "string"
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MerchantInvoiceLineSummary"
            }
          },
          "total_minor": {
            "type": "integer"
          }
        },
        "required": [
          "invoice_ref",
          "lines",
          "object",
          "total_minor"
        ]
      },
      "MerchantInvoiceLineSummary": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "amount_minor": {
            "type": "integer"
          },
          "currency": {
            "type": "string"
          },
          "remitted": {
            "type": "boolean"
          }
        },
        "required": [
          "amount_minor",
          "code",
          "currency",
          "name",
          "remitted"
        ]
      },
      "MerchantRevenueLineBulk": {
        "type": "object",
        "properties": {
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MerchantRevenueLineInput"
            }
          },
          "deactivate_missing": {
            "type": "boolean",
            "default": false
          }
        },
        "required": [
          "lines"
        ]
      },
      "MerchantRevenueLineCounts": {
        "type": "object",
        "properties": {
          "total": {
            "type": "integer"
          },
          "active": {
            "type": "integer"
          },
          "inactive": {
            "type": "integer"
          }
        },
        "required": [
          "active",
          "inactive",
          "total"
        ]
      },
      "MerchantRevenueLineInput": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "maxLength": 80
          },
          "name": {
            "type": "string",
            "maxLength": 200
          }
        },
        "required": [
          "code",
          "name"
        ]
      },
      "MerchantRevenueLineListResponse": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string"
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServiceCodeResponse"
            }
          },
          "counts": {
            "$ref": "#/components/schemas/MerchantRevenueLineCounts"
          }
        },
        "required": [
          "counts",
          "lines",
          "object"
        ]
      },
      "MerchantRevenueLineSyncResponse": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string"
          },
          "created": {
            "type": "integer"
          },
          "updated": {
            "type": "integer"
          },
          "reactivated": {
            "type": "integer"
          },
          "deactivated": {
            "type": "integer"
          },
          "unchanged": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": {}
            }
          }
        },
        "required": [
          "created",
          "deactivated",
          "errors",
          "object",
          "reactivated",
          "total",
          "unchanged",
          "updated"
        ]
      },
      "MerchantServiceCodeSourceEnum": {
        "enum": [
          "manual",
          "upload",
          "sync",
          "lazy"
        ],
        "type": "string",
        "description": "* `manual` - Manual\n* `upload` - Upload\n* `sync` - Sync\n* `lazy` - Lazy"
      },
      "MerchantWebhookEvent": {
        "type": "object",
        "required": [
          "id",
          "type",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "evt_example"
          },
          "type": {
            "$ref": "#/components/schemas/MerchantWebhookEventType"
          },
          "data": {
            "$ref": "#/components/schemas/MerchantWebhookEventData"
          }
        },
        "example": {
          "id": "evt_example",
          "type": "checkout.session.completed",
          "data": {
            "session": {
              "id": "cs_example",
              "status": "success",
              "amount_minor": 307038,
              "currency": "GHS",
              "invoice_ref": "EPA-2026-001",
              "metadata": {}
            }
          }
        }
      },
      "MerchantWebhookEventData": {
        "type": "object",
        "required": [
          "session"
        ],
        "properties": {
          "session": {
            "$ref": "#/components/schemas/MerchantWebhookSession"
          }
        }
      },
      "MerchantWebhookEventType": {
        "type": "string",
        "enum": [
          "checkout.session.completed",
          "checkout.session.failed",
          "checkout.session.expired"
        ],
        "description": "Terminal checkout event types delivered to merchant webhooks."
      },
      "MerchantWebhookSession": {
        "type": "object",
        "required": [
          "id",
          "status",
          "amount_minor",
          "currency",
          "invoice_ref",
          "metadata"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "cs_example"
          },
          "status": {
            "type": "string",
            "description": "Terminal checkout status at the time the event was created."
          },
          "amount_minor": {
            "type": "integer",
            "description": "Invoice amount in the minor unit of currency.",
            "example": 307038
          },
          "currency": {
            "type": "string",
            "example": "GHS"
          },
          "invoice_ref": {
            "type": "string",
            "example": "EPA-2026-001"
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "MerchantWebhookSignatureHeader": {
        "type": "string",
        "description": "Header format: t=<unix_timestamp>,v1=<hex_hmac_sha256>. The signed payload is '<t>.<raw_request_body>'.",
        "example": "t=1781686400,v1=4d967f0d4a8f..."
      },
      "OperatorEnum": {
        "enum": [
          "MTN",
          "VODAFONE",
          "AIRTEL_TIGO"
        ],
        "type": "string",
        "description": "* `MTN` - MTN\n* `VODAFONE` - VODAFONE\n* `AIRTEL_TIGO` - AIRTEL_TIGO"
      },
      "ProviderPaymentAuthorize": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "maxLength": 8,
            "minLength": 4
          }
        },
        "required": [
          "code"
        ]
      },
      "ProviderPaymentInitiate": {
        "type": "object",
        "properties": {
          "rail": {
            "$ref": "#/components/schemas/RailEnum"
          },
          "amount_minor": {
            "type": "integer",
            "minimum": 1
          },
          "phone": {
            "type": "string",
            "maxLength": 32
          },
          "operator": {
            "$ref": "#/components/schemas/OperatorEnum"
          },
          "account_name": {
            "type": "string",
            "maxLength": 120
          }
        },
        "required": [
          "rail"
        ]
      },
      "ProviderPaymentInitiationResponse": {
        "type": "object",
        "properties": {
          "attempt_reference": {
            "type": "string"
          },
          "provider": {
            "type": "string"
          },
          "provider_reference": {
            "type": "string"
          },
          "rail": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "amount_charged_minor": {
            "type": "integer"
          },
          "currency": {
            "type": "string"
          },
          "instructions": {
            "type": "object",
            "additionalProperties": {}
          },
          "replayed": {
            "type": "boolean"
          }
        },
        "required": [
          "amount_charged_minor",
          "attempt_reference",
          "currency",
          "instructions",
          "provider",
          "provider_reference",
          "rail",
          "replayed",
          "status"
        ]
      },
      "ProviderPaymentStatusResponse": {
        "type": "object",
        "properties": {
          "attempt_reference": {
            "type": "string"
          },
          "provider": {
            "type": "string"
          },
          "provider_reference": {
            "type": "string"
          },
          "rail": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "amount_charged_minor": {
            "type": "integer"
          },
          "currency": {
            "type": "string"
          },
          "session_id": {
            "type": "string"
          },
          "session_status": {
            "type": "string"
          },
          "session_finalized_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "raw_status": {
            "type": "string"
          },
          "refreshed": {
            "type": "boolean"
          },
          "finalized": {
            "type": "boolean"
          }
        },
        "required": [
          "amount_charged_minor",
          "attempt_reference",
          "currency",
          "finalized",
          "provider",
          "provider_reference",
          "rail",
          "raw_status",
          "refreshed",
          "session_finalized_at",
          "session_id",
          "session_status",
          "status"
        ]
      },
      "PublicCheckoutLineItem": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "amount_minor": {
            "type": "integer"
          },
          "currency": {
            "type": "string"
          }
        },
        "required": [
          "amount_minor",
          "code",
          "currency",
          "name"
        ]
      },
      "PublicCheckoutOptions": {
        "type": "object",
        "properties": {
          "payment_rails": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChoiceOption"
            }
          },
          "cash_instruments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChoiceOption"
            }
          },
          "branch_payment_methods": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChoiceOption"
            }
          },
          "banks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BankOption"
            }
          }
        },
        "required": [
          "banks",
          "branch_payment_methods",
          "cash_instruments",
          "payment_rails"
        ]
      },
      "PublicCheckoutQuoteResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "base_minor": {
            "type": "integer"
          },
          "currency": {
            "type": "string"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "allowed_rails": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "surcharges": {
            "type": "object",
            "additionalProperties": {
              "type": "object",
              "additionalProperties": {}
            }
          }
        },
        "required": [
          "allowed_rails",
          "base_minor",
          "currency",
          "expires_at",
          "id",
          "status",
          "surcharges"
        ]
      },
      "PublicCheckoutSession": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "merchant_name": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/CheckoutSessionStatusEnum"
          },
          "amount_minor": {
            "type": "integer",
            "maximum": 9223372036854775807,
            "minimum": 1,
            "format": "int64"
          },
          "currency": {
            "type": "string",
            "maxLength": 3
          },
          "invoice_ref": {
            "type": "string",
            "maxLength": 120
          },
          "description": {
            "type": "string",
            "maxLength": 240
          },
          "customer_name": {
            "type": "string",
            "maxLength": 200
          },
          "customer_email": {
            "type": "string",
            "format": "email",
            "maxLength": 254
          },
          "allowed_rails": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "readOnly": true
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "finalized_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "paid_rail": {
            "type": "string",
            "readOnly": true
          },
          "return_to_merchant_url": {
            "type": "string"
          },
          "line_items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicCheckoutLineItem"
            },
            "readOnly": true
          },
          "card_collection_mode": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CardCollectionModeEnum"
              }
            ],
            "readOnly": true
          }
        },
        "required": [
          "allowed_rails",
          "amount_minor",
          "card_collection_mode",
          "expires_at",
          "id",
          "invoice_ref",
          "line_items",
          "merchant_name",
          "paid_rail",
          "return_to_merchant_url"
        ]
      },
      "RailEnum": {
        "enum": [
          "momo",
          "bank_transfer"
        ],
        "type": "string",
        "description": "* `momo` - momo\n* `bank_transfer` - bank_transfer"
      },
      "ServiceCodeResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "readOnly": true
          },
          "merchant_id": {
            "type": "string",
            "format": "uuid"
          },
          "code": {
            "type": "string",
            "maxLength": 80
          },
          "name": {
            "type": "string",
            "maxLength": 200
          },
          "active": {
            "type": "boolean"
          },
          "source": {
            "$ref": "#/components/schemas/MerchantServiceCodeSourceEnum"
          },
          "last_synced_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          }
        },
        "required": [
          "code",
          "created_at",
          "id",
          "merchant_id",
          "name",
          "updated_at"
        ]
      }
    },
    "securitySchemes": {
      "merchantApiKeyAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Merchant API key",
        "description": "Use `Authorization: Bearer <merchant_api_key>` from a merchant server. Never expose merchant API keys in browser or mobile clients."
      }
    }
  },
  "servers": [
    {
      "url": "https://api.staging.velorapay.com",
      "description": "Staging environment for test integrations."
    }
  ],
  "tags": [
    {
      "name": "Checkout Sessions",
      "description": "Create and inspect merchant checkout sessions from invoice data."
    },
    {
      "name": "Checkout Payments",
      "description": "Payment-method actions used by VeloraPay-hosted checkout."
    },
    {
      "name": "Cash Deposits",
      "description": "Generate one active bank cash-deposit slip for a checkout session."
    },
    {
      "name": "Service Codes",
      "description": "Sync merchant revenue lines and invoice line items."
    },
    {
      "name": "Checkout Options",
      "description": "Read public checkout choices used by checkout clients."
    }
  ]
}
