{
  "version": "2026-11-02",
  "baseUrl": "https://api.veyqo.org/api/v1",
  "browserBaseUrl": "https://api.veyqo.org/checkout/v1",
  "groups": [
    {
      "name": "Payments",
      "description": "Create a payment, read it back, and settle or refund it.",
      "endpoints": [
        {
          "id": "payments.create",
          "method": "POST",
          "path": "/payments",
          "summary": "Create a payment",
          "description": "Starts a payment with the provider connected in this environment and returns a checkout URL. The amount is an integer in the smallest currency unit.",
          "scope": "payments:write",
          "idempotent": true,
          "runnable": true,
          "example": {
            "amount": 50000,
            "currency": "NGN",
            "reference": "ORDER-1001",
            "provider": "paystack",
            "customer": {
              "email": "customer@example.com",
              "name": "Ada Lovelace"
            },
            "metadata": {
              "order_id": "1001"
            }
          },
          "notes": [
            "`reference` is optional. Omitted, the payment id becomes the reference.",
            "The customer may be nested, as here, or flat as `customer_email`."
          ],
          "responseSchema": "Payment",
          "responseExample": {
            "success": true,
            "data": {
              "id": "pay_01M6EB66SC61Q3RQYAN0693DGM",
              "object": "payment",
              "reference": "ORDER-1001",
              "status": "pending",
              "amount": 50000,
              "amount_refunded": 0,
              "currency": "NGN",
              "customer": {
                "email": "customer@example.com",
                "name": "Ada Lovelace",
                "phone": null
              },
              "description": "Order 1001",
              "checkout_url": "https://checkout.paystack.com/example",
              "provider": "paystack",
              "provider_reference": "provider_reference_example",
              "metadata": {
                "order_id": "1001"
              },
              "failure_code": null,
              "failure_message": null,
              "authorized_at": null,
              "succeeded_at": null,
              "failed_at": null,
              "created_at": "2026-11-02T12:00:00+00:00"
            }
          },
          "successStatus": 201,
          "requestSchema": "CreatePayment",
          "parameters": [],
          "paginated": false,
          "errors": [
            "INVALID_API_KEY",
            "INSUFFICIENT_PERMISSION",
            "RATE_LIMIT_EXCEEDED",
            "METHOD_NOT_ALLOWED",
            "INTERNAL_ERROR",
            "VALIDATION_FAILED",
            "DUPLICATE_REFERENCE",
            "PROVIDER_NOT_CONNECTED",
            "INVALID_PROVIDER",
            "INVALID_CURRENCY",
            "PROVIDER_AUTHENTICATION_FAILED",
            "PROVIDER_REQUEST_FAILED",
            "PROVIDER_UNAVAILABLE",
            "PLAN_LIMIT_REACHED",
            "IDEMPOTENCY_KEY_REUSED",
            "IDEMPOTENCY_IN_PROGRESS"
          ]
        },
        {
          "id": "payments.list",
          "method": "GET",
          "path": "/payments",
          "summary": "List payments",
          "description": "List payments in this project environment, newest first. Only status, reference, created_after, created_before and pagination filters are implemented.",
          "scope": "payments:read",
          "runnable": true,
          "query": {
            "per_page": 5
          },
          "responseSchema": "Payment",
          "responseExample": {
            "success": true,
            "data": [
              {
                "id": "pay_01M6EB66SC61Q3RQYAN0693DGM",
                "object": "payment",
                "reference": "ORDER-1001",
                "status": "pending",
                "amount": 50000,
                "amount_refunded": 0,
                "currency": "NGN",
                "customer": {
                  "email": "customer@example.com",
                  "name": "Ada Lovelace",
                  "phone": null
                },
                "description": "Order 1001",
                "checkout_url": "https://checkout.paystack.com/example",
                "provider": "paystack",
                "provider_reference": "provider_reference_example",
                "metadata": {
                  "order_id": "1001"
                },
                "failure_code": null,
                "failure_message": null,
                "authorized_at": null,
                "succeeded_at": null,
                "failed_at": null,
                "created_at": "2026-11-02T12:00:00+00:00"
              }
            ],
            "meta": {
              "page": 1,
              "per_page": 25,
              "total": 1,
              "has_more": false
            }
          },
          "successStatus": 200,
          "requestSchema": null,
          "parameters": [
            {
              "name": "page",
              "in": "query",
              "required": false,
              "description": "Page number, starting at 1.",
              "schema": {
                "type": "integer",
                "minimum": 1,
                "default": 1
              }
            },
            {
              "name": "per_page",
              "in": "query",
              "required": false,
              "description": "Page size, default 25 and maximum 100.",
              "schema": {
                "type": "integer",
                "minimum": 1,
                "maximum": 100,
                "default": 25
              }
            },
            {
              "name": "status",
              "in": "query",
              "required": false,
              "description": "Normalized payment status.",
              "schema": {
                "type": "string",
                "enum": [
                  "created",
                  "pending",
                  "processing",
                  "succeeded",
                  "failed",
                  "cancelled",
                  "refunded",
                  "partially_refunded"
                ]
              }
            },
            {
              "name": "reference",
              "in": "query",
              "required": false,
              "description": "Exact merchant reference.",
              "schema": {
                "type": "string"
              }
            },
            {
              "name": "created_after",
              "in": "query",
              "required": false,
              "description": "Inclusive creation-time lower bound. Use an ISO 8601 date/time.",
              "schema": {
                "type": "string"
              }
            },
            {
              "name": "created_before",
              "in": "query",
              "required": false,
              "description": "Inclusive creation-time upper bound. Use an ISO 8601 date/time.",
              "schema": {
                "type": "string"
              }
            }
          ],
          "paginated": true,
          "errors": [
            "INVALID_API_KEY",
            "INSUFFICIENT_PERMISSION",
            "RATE_LIMIT_EXCEEDED",
            "METHOD_NOT_ALLOWED",
            "INTERNAL_ERROR"
          ]
        },
        {
          "id": "payments.show",
          "method": "GET",
          "path": "/payments/{id}",
          "summary": "Retrieve a payment",
          "description": "Retrieve by Veyqo payment ID or your merchant reference directly in the path. URL-encode references; use the Veyqo ID when a reference contains reserved URL characters.",
          "scope": "payments:read",
          "runnable": true,
          "needs": "payment",
          "responseSchema": "Payment",
          "responseExample": {
            "success": true,
            "data": {
              "id": "pay_01M6EB66SC61Q3RQYAN0693DGM",
              "object": "payment",
              "reference": "ORDER-1001",
              "status": "pending",
              "amount": 50000,
              "amount_refunded": 0,
              "currency": "NGN",
              "customer": {
                "email": "customer@example.com",
                "name": "Ada Lovelace",
                "phone": null
              },
              "description": "Order 1001",
              "checkout_url": "https://checkout.paystack.com/example",
              "provider": "paystack",
              "provider_reference": "provider_reference_example",
              "metadata": {
                "order_id": "1001"
              },
              "failure_code": null,
              "failure_message": null,
              "authorized_at": null,
              "succeeded_at": null,
              "failed_at": null,
              "created_at": "2026-11-02T12:00:00+00:00"
            }
          },
          "successStatus": 200,
          "requestSchema": null,
          "parameters": [],
          "paginated": false,
          "errors": [
            "INVALID_API_KEY",
            "INSUFFICIENT_PERMISSION",
            "RATE_LIMIT_EXCEEDED",
            "METHOD_NOT_ALLOWED",
            "INTERNAL_ERROR",
            "PAYMENT_NOT_FOUND",
            "ENVIRONMENT_MISMATCH"
          ]
        },
        {
          "id": "payments.verify",
          "method": "POST",
          "path": "/payments/{id}/verify",
          "summary": "Verify a payment",
          "description": "Asks the provider what actually happened and updates the payment. Use it when a webhook has not arrived — never trust a browser redirect alone.",
          "scope": "payments:read",
          "runnable": true,
          "needs": "payment",
          "responseSchema": "Payment",
          "responseExample": {
            "success": true,
            "data": {
              "id": "pay_01M6EB66SC61Q3RQYAN0693DGM",
              "object": "payment",
              "reference": "ORDER-1001",
              "status": "pending",
              "amount": 50000,
              "amount_refunded": 0,
              "currency": "NGN",
              "customer": {
                "email": "customer@example.com",
                "name": "Ada Lovelace",
                "phone": null
              },
              "description": "Order 1001",
              "checkout_url": "https://checkout.paystack.com/example",
              "provider": "paystack",
              "provider_reference": "provider_reference_example",
              "metadata": {
                "order_id": "1001"
              },
              "failure_code": null,
              "failure_message": null,
              "authorized_at": null,
              "succeeded_at": null,
              "failed_at": null,
              "created_at": "2026-11-02T12:00:00+00:00"
            }
          },
          "successStatus": 200,
          "requestSchema": null,
          "parameters": [],
          "paginated": false,
          "errors": [
            "INVALID_API_KEY",
            "INSUFFICIENT_PERMISSION",
            "RATE_LIMIT_EXCEEDED",
            "METHOD_NOT_ALLOWED",
            "INTERNAL_ERROR",
            "PAYMENT_NOT_FOUND",
            "ENVIRONMENT_MISMATCH",
            "PROVIDER_UNAVAILABLE",
            "PROVIDER_AUTHENTICATION_FAILED",
            "PROVIDER_REQUEST_FAILED"
          ],
          "notes": [
            "No request body is required. Use a fresh request without a reused Idempotency-Key when polling, so a cached earlier result cannot hide the latest status.",
            "A successful HTTP response can still contain pending or processing. Fulfil only after confirming succeeded and matching the stored order."
          ]
        },
        {
          "id": "refunds.create",
          "method": "POST",
          "path": "/payments/{id}/refunds",
          "summary": "Refund a payment",
          "description": "Full or partial. Omit `amount` to refund everything still refundable.",
          "scope": "refunds:write",
          "idempotent": true,
          "runnable": true,
          "needs": "payment",
          "example": {
            "amount": 25000,
            "reason": "requested_by_customer"
          },
          "responseSchema": "Refund",
          "responseExample": {
            "success": true,
            "data": {
              "id": "ref_01M6EB66SC61Q3RQYAN0693DGM",
              "object": "refund",
              "payment": "pay_01M6EB66SC61Q3RQYAN0693DGM",
              "amount": 25000,
              "currency": "NGN",
              "status": "pending",
              "reason": "requested_by_customer",
              "failure_message": null,
              "created_at": "2026-11-02T12:00:00+00:00"
            }
          },
          "successStatus": 201,
          "requestSchema": "CreateRefund",
          "parameters": [],
          "paginated": false,
          "errors": [
            "INVALID_API_KEY",
            "INSUFFICIENT_PERMISSION",
            "RATE_LIMIT_EXCEEDED",
            "METHOD_NOT_ALLOWED",
            "INTERNAL_ERROR",
            "PAYMENT_NOT_FOUND",
            "ENVIRONMENT_MISMATCH",
            "VALIDATION_FAILED",
            "PAYMENT_ALREADY_REFUNDED",
            "INVALID_PROVIDER",
            "PROVIDER_AUTHENTICATION_FAILED",
            "PROVIDER_UNAVAILABLE",
            "PROVIDER_REQUEST_FAILED",
            "IDEMPOTENCY_KEY_REUSED",
            "IDEMPOTENCY_IN_PROGRESS"
          ]
        },
        {
          "id": "refunds.show",
          "method": "GET",
          "path": "/refunds/{id}",
          "summary": "Retrieve a refund",
          "description": "The refund and the payment it belongs to.",
          "scope": "refunds:read",
          "runnable": false,
          "needs": "refund",
          "responseSchema": "Refund",
          "responseExample": {
            "success": true,
            "data": {
              "id": "ref_01M6EB66SC61Q3RQYAN0693DGM",
              "object": "refund",
              "payment": "pay_01M6EB66SC61Q3RQYAN0693DGM",
              "amount": 25000,
              "currency": "NGN",
              "status": "pending",
              "reason": "requested_by_customer",
              "failure_message": null,
              "created_at": "2026-11-02T12:00:00+00:00"
            }
          },
          "successStatus": 200,
          "requestSchema": null,
          "parameters": [],
          "paginated": false,
          "errors": [
            "INVALID_API_KEY",
            "INSUFFICIENT_PERMISSION",
            "RATE_LIMIT_EXCEEDED",
            "METHOD_NOT_ALLOWED",
            "INTERNAL_ERROR",
            "RESOURCE_NOT_FOUND",
            "ENVIRONMENT_MISMATCH"
          ]
        }
      ]
    },
    {
      "name": "Events",
      "description": "What Veyqo normalized from your providers.",
      "endpoints": [
        {
          "id": "events.list",
          "method": "GET",
          "path": "/events",
          "summary": "List events",
          "description": "Every event Veyqo produced in this environment, newest first. Filter by `type`.",
          "scope": "events:read",
          "runnable": true,
          "query": {
            "per_page": 5
          },
          "responseSchema": "Event",
          "responseExample": {
            "success": true,
            "data": [
              {
                "id": "evt_01M6EB66SC61Q3RQYAN0693DGM",
                "type": "payment.succeeded",
                "created_at": "2026-11-02T12:00:00+00:00",
                "environment": "sandbox",
                "data": {
                  "payment_id": "pay_01M6EB66SC61Q3RQYAN0693DGM",
                  "reference": "ORDER-1001",
                  "amount": 50000,
                  "amount_refunded": 0,
                  "currency": "NGN",
                  "status": "succeeded",
                  "customer": {
                    "email": "customer@example.com",
                    "name": "Ada Lovelace"
                  },
                  "provider": {
                    "name": "paystack",
                    "reference": "provider_reference_example"
                  },
                  "metadata": {
                    "order_id": "1001"
                  }
                }
              }
            ],
            "meta": {
              "page": 1,
              "per_page": 25,
              "total": 1,
              "has_more": false
            }
          },
          "successStatus": 200,
          "requestSchema": null,
          "parameters": [
            {
              "name": "page",
              "in": "query",
              "required": false,
              "description": "Page number, starting at 1.",
              "schema": {
                "type": "integer",
                "minimum": 1,
                "default": 1
              }
            },
            {
              "name": "per_page",
              "in": "query",
              "required": false,
              "description": "Page size, default 25 and maximum 100.",
              "schema": {
                "type": "integer",
                "minimum": 1,
                "maximum": 100,
                "default": 25
              }
            },
            {
              "name": "type",
              "in": "query",
              "required": false,
              "description": "Exact supported event type.",
              "schema": {
                "type": "string"
              }
            },
            {
              "name": "payment_id",
              "in": "query",
              "required": false,
              "description": "Veyqo payment ID, not your order reference.",
              "schema": {
                "type": "string"
              }
            },
            {
              "name": "created_after",
              "in": "query",
              "required": false,
              "description": "Inclusive creation-time lower bound. Use an ISO 8601 date/time.",
              "schema": {
                "type": "string"
              }
            },
            {
              "name": "created_before",
              "in": "query",
              "required": false,
              "description": "Inclusive creation-time upper bound. Use an ISO 8601 date/time.",
              "schema": {
                "type": "string"
              }
            }
          ],
          "paginated": true,
          "errors": [
            "INVALID_API_KEY",
            "INSUFFICIENT_PERMISSION",
            "RATE_LIMIT_EXCEEDED",
            "METHOD_NOT_ALLOWED",
            "INTERNAL_ERROR",
            "VALIDATION_FAILED"
          ]
        },
        {
          "id": "events.show",
          "method": "GET",
          "path": "/events/{id}",
          "summary": "Retrieve an event",
          "description": "The normalized event, identical in shape whichever provider caused it.",
          "scope": "events:read",
          "runnable": false,
          "needs": "event",
          "responseSchema": "Event",
          "responseExample": {
            "success": true,
            "data": {
              "id": "evt_01M6EB66SC61Q3RQYAN0693DGM",
              "type": "payment.succeeded",
              "created_at": "2026-11-02T12:00:00+00:00",
              "environment": "sandbox",
              "data": {
                "payment_id": "pay_01M6EB66SC61Q3RQYAN0693DGM",
                "reference": "ORDER-1001",
                "amount": 50000,
                "amount_refunded": 0,
                "currency": "NGN",
                "status": "succeeded",
                "customer": {
                  "email": "customer@example.com",
                  "name": "Ada Lovelace"
                },
                "provider": {
                  "name": "paystack",
                  "reference": "provider_reference_example"
                },
                "metadata": {
                  "order_id": "1001"
                }
              }
            }
          },
          "successStatus": 200,
          "requestSchema": null,
          "parameters": [],
          "paginated": false,
          "errors": [
            "INVALID_API_KEY",
            "INSUFFICIENT_PERMISSION",
            "RATE_LIMIT_EXCEEDED",
            "METHOD_NOT_ALLOWED",
            "INTERNAL_ERROR",
            "RESOURCE_NOT_FOUND"
          ]
        }
      ]
    },
    {
      "name": "Checkout",
      "description": "A Veyqo page where the customer pays by card, bank transfer, USSD or mobile money, through the gateway you choose.",
      "endpoints": [
        {
          "id": "checkout.sessions.create",
          "method": "POST",
          "path": "/checkout/sessions",
          "summary": "Create a checkout session",
          "description": "Returns a checkout `url` where the customer pays without leaving Veyqo: by bank transfer, USSD or mobile money on the page itself, or by card in the gateway's own secure form over it. Created here with your secret key, the amount cannot be changed by the customer; open it with the JS SDK or redirect to `url`.",
          "scope": "payments:write",
          "runnable": true,
          "example": {
            "amount": 50000,
            "currency": "NGN",
            "reference": "ORDER-1001",
            "provider": "paystack",
            "customer": {
              "email": "customer@example.com"
            },
            "success_url": "https://shop.example.com/thanks",
            "cancel_url": "https://shop.example.com/cart"
          },
          "notes": [
            "`provider` names the gateway that takes the money. Omitted, the project default is used, or the only connected gateway; the customer never chooses it.",
            "The methods offered are the ones that gateway supports in the currency. A session expires after an hour. Each method the customer tries is its own payment; `metadata.checkout_session` names the session on every one."
          ],
          "responseSchema": "CheckoutSession",
          "responseExample": {
            "success": true,
            "data": {
              "id": "cs_01M6EB66SC61Q3RQYAN0693DGM",
              "object": "checkout_session",
              "url": "https://veyqo.org/pay/cs_01M6EB66SC61Q3RQYAN0693DGM",
              "status": "open",
              "source": "api",
              "provider": "paystack",
              "amount": 50000,
              "currency": "NGN",
              "reference": "ORDER-1001",
              "description": "Order 1001",
              "customer_email": "customer@example.com",
              "payment": null,
              "success_url": "https://shop.example.com/thanks",
              "cancel_url": "https://shop.example.com/cart",
              "expires_at": "2026-11-02T13:00:00+00:00",
              "completed_at": null,
              "created_at": "2026-11-02T12:00:00+00:00"
            }
          },
          "successStatus": 201,
          "requestSchema": "CreateCheckoutSession",
          "parameters": [],
          "paginated": false,
          "errors": [
            "INVALID_API_KEY",
            "INSUFFICIENT_PERMISSION",
            "RATE_LIMIT_EXCEEDED",
            "METHOD_NOT_ALLOWED",
            "INTERNAL_ERROR",
            "VALIDATION_FAILED",
            "IDEMPOTENCY_KEY_REUSED",
            "IDEMPOTENCY_IN_PROGRESS",
            "PLAN_LIMIT_REACHED"
          ],
          "idempotent": true
        },
        {
          "id": "checkout.sessions.show",
          "method": "GET",
          "path": "/checkout/sessions/{id}",
          "summary": "Retrieve a checkout session",
          "description": "Its status (`open`, `completed`, `expired`) and the payment behind it. A payment still waiting is verified with the provider before this answers.",
          "scope": "payments:read",
          "runnable": false,
          "responseSchema": "CheckoutSession",
          "responseExample": {
            "success": true,
            "data": {
              "id": "cs_01M6EB66SC61Q3RQYAN0693DGM",
              "object": "checkout_session",
              "url": "https://veyqo.org/pay/cs_01M6EB66SC61Q3RQYAN0693DGM",
              "status": "open",
              "source": "api",
              "provider": "paystack",
              "amount": 50000,
              "currency": "NGN",
              "reference": "ORDER-1001",
              "description": "Order 1001",
              "customer_email": "customer@example.com",
              "payment": null,
              "success_url": "https://shop.example.com/thanks",
              "cancel_url": "https://shop.example.com/cart",
              "expires_at": "2026-11-02T13:00:00+00:00",
              "completed_at": null,
              "created_at": "2026-11-02T12:00:00+00:00"
            }
          },
          "successStatus": 200,
          "requestSchema": null,
          "parameters": [],
          "paginated": false,
          "errors": [
            "INVALID_API_KEY",
            "INSUFFICIENT_PERMISSION",
            "RATE_LIMIT_EXCEEDED",
            "METHOD_NOT_ALLOWED",
            "INTERNAL_ERROR",
            "RESOURCE_NOT_FOUND",
            "PROVIDER_UNAVAILABLE"
          ]
        }
      ]
    },
    {
      "name": "Providers",
      "description": "What this environment can currently charge through.",
      "endpoints": [
        {
          "id": "providers.list",
          "method": "GET",
          "path": "/providers",
          "summary": "List connected providers",
          "description": "Lists provider connection rows for this environment, including status, health and explicitly public provider keys. Disabled or historical rows may be present; secret credentials are never returned.",
          "scope": "payments:read",
          "runnable": true,
          "responseSchema": "Provider",
          "responseExample": {
            "success": true,
            "data": [
              {
                "provider": "paystack",
                "name": "Paystack",
                "status": "active",
                "health": "healthy",
                "currencies": [
                  "NGN",
                  "GHS",
                  "ZAR",
                  "KES",
                  "USD"
                ],
                "capabilities": [
                  "collections",
                  "refunds",
                  "transfers"
                ],
                "public_credentials": {
                  "public_key": "pk_test_public_example"
                },
                "connected_at": "2026-11-02T12:00:00+00:00"
              }
            ]
          },
          "successStatus": 200,
          "requestSchema": null,
          "parameters": [],
          "paginated": false,
          "errors": [
            "INVALID_API_KEY",
            "INSUFFICIENT_PERMISSION",
            "RATE_LIMIT_EXCEEDED",
            "METHOD_NOT_ALLOWED",
            "INTERNAL_ERROR"
          ]
        }
      ]
    }
  ],
  "schemas": {
    "Payment": {
      "type": "object",
      "description": "",
      "properties": {
        "id": {
          "type": "string",
          "description": "Globally unique Veyqo payment ID; use it for reconciliation."
        },
        "object": {
          "const": "payment"
        },
        "reference": {
          "type": "string",
          "description": "Merchant reference unique within the project environment; defaults to the payment ID."
        },
        "status": {
          "type": "string",
          "enum": [
            "created",
            "pending",
            "processing",
            "succeeded",
            "failed",
            "cancelled",
            "refunded",
            "partially_refunded"
          ],
          "description": "Normalized payment state. Do not fulfil pending, processing, failed or cancelled payments."
        },
        "amount": {
          "type": "integer",
          "description": "Original amount in the smallest currency unit."
        },
        "amount_refunded": {
          "type": "integer",
          "description": "Successfully refunded amount in the smallest currency unit."
        },
        "currency": {
          "type": "string",
          "description": "Three-letter currency code."
        },
        "customer": {
          "type": "object",
          "description": "",
          "properties": {
            "email": {
              "type": "string",
              "description": "Customer email address."
            },
            "name": {
              "type": [
                "string",
                "null"
              ],
              "description": "Customer name."
            },
            "phone": {
              "type": [
                "string",
                "null"
              ],
              "description": "Customer phone."
            }
          },
          "required": [
            "email",
            "name",
            "phone"
          ]
        },
        "description": {
          "type": [
            "string",
            "null"
          ],
          "description": "Optional description."
        },
        "checkout_url": {
          "type": [
            "string",
            "null"
          ],
          "description": "Provider checkout URL for direct payments; may be null depending on the flow.",
          "format": "uri"
        },
        "provider": {
          "type": "string",
          "description": "Selected provider slug."
        },
        "provider_reference": {
          "type": [
            "string",
            "null"
          ],
          "description": "Reference the provider assigned, not your order reference."
        },
        "metadata": {
          "type": [
            "object",
            "array"
          ],
          "description": "Your non-sensitive JSON metadata. Objects are recommended; do not store secrets or card details."
        },
        "failure_code": {
          "type": [
            "string",
            "null"
          ],
          "description": "Machine-readable payment failure reason, separate from API error codes."
        },
        "failure_message": {
          "type": [
            "string",
            "null"
          ],
          "description": "Human-readable payment failure reason."
        },
        "authorized_at": {
          "type": [
            "string",
            "null"
          ],
          "description": "ISO 8601 timestamp.",
          "format": "date-time"
        },
        "succeeded_at": {
          "type": [
            "string",
            "null"
          ],
          "description": "ISO 8601 timestamp.",
          "format": "date-time"
        },
        "failed_at": {
          "type": [
            "string",
            "null"
          ],
          "description": "ISO 8601 timestamp.",
          "format": "date-time"
        },
        "created_at": {
          "type": [
            "string",
            "null"
          ],
          "description": "ISO 8601 timestamp.",
          "format": "date-time"
        }
      },
      "required": [
        "id",
        "object",
        "reference",
        "status",
        "amount",
        "amount_refunded",
        "currency",
        "customer",
        "description",
        "checkout_url",
        "provider",
        "provider_reference",
        "metadata",
        "failure_code",
        "failure_message",
        "authorized_at",
        "succeeded_at",
        "failed_at",
        "created_at"
      ],
      "example": {
        "id": "pay_01M6EB66SC61Q3RQYAN0693DGM",
        "object": "payment",
        "reference": "ORDER-1001",
        "status": "pending",
        "amount": 50000,
        "amount_refunded": 0,
        "currency": "NGN",
        "customer": {
          "email": "customer@example.com",
          "name": "Ada Lovelace",
          "phone": null
        },
        "description": "Order 1001",
        "checkout_url": "https://checkout.paystack.com/example",
        "provider": "paystack",
        "provider_reference": "provider_reference_example",
        "metadata": {
          "order_id": "1001"
        },
        "failure_code": null,
        "failure_message": null,
        "authorized_at": null,
        "succeeded_at": null,
        "failed_at": null,
        "created_at": "2026-11-02T12:00:00+00:00"
      }
    },
    "Refund": {
      "type": "object",
      "description": "",
      "properties": {
        "id": {
          "type": "string",
          "description": "Veyqo refund ID."
        },
        "object": {
          "const": "refund"
        },
        "payment": {
          "type": "string",
          "description": "Original Veyqo payment ID."
        },
        "amount": {
          "type": "integer",
          "description": "Refund amount in the smallest currency unit."
        },
        "currency": {
          "type": "string",
          "description": "Original payment currency."
        },
        "status": {
          "type": "string",
          "enum": [
            "pending",
            "succeeded",
            "failed"
          ]
        },
        "reason": {
          "type": [
            "string",
            "null"
          ],
          "description": "Optional reason."
        },
        "failure_message": {
          "type": [
            "string",
            "null"
          ],
          "description": "Provider failure message when available."
        },
        "created_at": {
          "type": [
            "string",
            "null"
          ],
          "description": "ISO 8601 timestamp.",
          "format": "date-time"
        }
      },
      "required": [
        "id",
        "object",
        "payment",
        "amount",
        "currency",
        "status",
        "reason",
        "failure_message",
        "created_at"
      ],
      "example": {
        "id": "ref_01M6EB66SC61Q3RQYAN0693DGM",
        "object": "refund",
        "payment": "pay_01M6EB66SC61Q3RQYAN0693DGM",
        "amount": 25000,
        "currency": "NGN",
        "status": "pending",
        "reason": "requested_by_customer",
        "failure_message": null,
        "created_at": "2026-11-02T12:00:00+00:00"
      }
    },
    "CheckoutSession": {
      "type": "object",
      "description": "",
      "properties": {
        "id": {
          "type": "string",
          "description": "Checkout session ID (cs_ prefix)."
        },
        "object": {
          "const": "checkout_session"
        },
        "url": {
          "type": "string",
          "description": "Hosted Veyqo URL; redirect here or open this session using VeyqoCheckout.",
          "format": "uri"
        },
        "status": {
          "type": "string",
          "enum": [
            "open",
            "completed",
            "expired"
          ]
        },
        "source": {
          "type": "string",
          "enum": [
            "api",
            "browser",
            "link"
          ]
        },
        "provider": {
          "type": "string",
          "description": "Selected provider slug; this field is an object on the browser session detail endpoint."
        },
        "amount": {
          "type": "integer",
          "description": "Server-defined amount in minor units."
        },
        "currency": {
          "type": "string",
          "description": "Three-letter currency."
        },
        "reference": {
          "type": [
            "string",
            "null"
          ],
          "description": "Your order reference, when supplied."
        },
        "description": {
          "type": [
            "string",
            "null"
          ],
          "description": "Checkout description."
        },
        "customer_email": {
          "type": [
            "string",
            "null"
          ],
          "description": "Customer email if already supplied."
        },
        "payment": {
          "anyOf": [
            {
              "type": "object",
              "description": "",
              "properties": {
                "id": {
                  "type": "string",
                  "description": ""
                },
                "reference": {
                  "type": "string",
                  "description": ""
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "created",
                    "pending",
                    "processing",
                    "succeeded",
                    "failed",
                    "cancelled",
                    "refunded",
                    "partially_refunded"
                  ]
                },
                "provider": {
                  "type": "string",
                  "description": ""
                }
              },
              "required": [
                "id",
                "reference",
                "status",
                "provider"
              ]
            },
            {
              "type": "null"
            }
          ],
          "description": "Current payment attempt, if any. A session can have multiple attempts over time."
        },
        "success_url": {
          "type": [
            "string",
            "null"
          ],
          "description": "Configured return URL. A redirect is not proof of payment."
        },
        "cancel_url": {
          "type": [
            "string",
            "null"
          ],
          "description": "Configured cancellation URL."
        },
        "expires_at": {
          "type": "string",
          "description": "Session expiry time.",
          "format": "date-time"
        },
        "completed_at": {
          "type": [
            "string",
            "null"
          ],
          "description": "ISO 8601 timestamp.",
          "format": "date-time"
        },
        "created_at": {
          "type": [
            "string",
            "null"
          ],
          "description": "ISO 8601 timestamp.",
          "format": "date-time"
        }
      },
      "required": [
        "id",
        "object",
        "url",
        "status",
        "source",
        "provider",
        "amount",
        "currency",
        "reference",
        "description",
        "customer_email",
        "payment",
        "success_url",
        "cancel_url",
        "expires_at",
        "completed_at",
        "created_at"
      ],
      "example": {
        "id": "cs_01M6EB66SC61Q3RQYAN0693DGM",
        "object": "checkout_session",
        "url": "https://veyqo.org/pay/cs_01M6EB66SC61Q3RQYAN0693DGM",
        "status": "open",
        "source": "api",
        "provider": "paystack",
        "amount": 50000,
        "currency": "NGN",
        "reference": "ORDER-1001",
        "description": "Order 1001",
        "customer_email": "customer@example.com",
        "payment": null,
        "success_url": "https://shop.example.com/thanks",
        "cancel_url": "https://shop.example.com/cart",
        "expires_at": "2026-11-02T13:00:00+00:00",
        "completed_at": null,
        "created_at": "2026-11-02T12:00:00+00:00"
      }
    },
    "Provider": {
      "type": "object",
      "description": "",
      "properties": {
        "provider": {
          "type": "string",
          "description": "Provider slug."
        },
        "name": {
          "type": "string",
          "description": "Provider display name."
        },
        "status": {
          "type": "string",
          "description": "Connection status; active does not guarantee a healthy provider account."
        },
        "health": {
          "type": "string",
          "description": "Observed connection health."
        },
        "currencies": {
          "type": "array",
          "items": {
            "type": "string",
            "description": ""
          },
          "description": ""
        },
        "capabilities": {
          "type": "array",
          "items": {
            "type": "string",
            "description": ""
          },
          "description": ""
        },
        "public_credentials": {
          "type": "object",
          "additionalProperties": {
            "type": "string"
          },
          "description": "Only provider keys explicitly marked public, such as public_key. Never includes secret credentials."
        },
        "connected_at": {
          "type": [
            "string",
            "null"
          ],
          "description": "ISO 8601 timestamp.",
          "format": "date-time"
        }
      },
      "required": [
        "provider",
        "name",
        "status",
        "health",
        "currencies",
        "capabilities",
        "public_credentials",
        "connected_at"
      ],
      "example": {
        "provider": "paystack",
        "name": "Paystack",
        "status": "active",
        "health": "healthy",
        "currencies": [
          "NGN",
          "GHS",
          "ZAR",
          "KES",
          "USD"
        ],
        "capabilities": [
          "collections",
          "refunds",
          "transfers"
        ],
        "public_credentials": {
          "public_key": "pk_test_public_example"
        },
        "connected_at": "2026-11-02T12:00:00+00:00"
      }
    },
    "EventData": {
      "type": "object",
      "description": "Payment snapshot when this event was recorded. Refund events also include refund_id and refund_amount.",
      "properties": {
        "payment_id": {
          "type": "string",
          "description": "Payment ID to retrieve and verify."
        },
        "reference": {
          "type": "string",
          "description": "Merchant reference."
        },
        "amount": {
          "type": "integer",
          "description": "Original minor-unit amount."
        },
        "amount_refunded": {
          "type": "integer",
          "description": "Minor-unit refunded amount."
        },
        "currency": {
          "type": "string",
          "description": ""
        },
        "status": {
          "type": "string",
          "enum": [
            "created",
            "pending",
            "processing",
            "succeeded",
            "failed",
            "cancelled",
            "refunded",
            "partially_refunded"
          ]
        },
        "customer": {
          "type": "object",
          "description": "",
          "properties": {
            "email": {
              "type": "string",
              "description": ""
            },
            "name": {
              "type": "string",
              "description": ""
            }
          },
          "required": [
            "email"
          ]
        },
        "provider": {
          "type": "object",
          "description": "",
          "properties": {
            "name": {
              "type": "string",
              "description": "Provider slug."
            },
            "reference": {
              "type": [
                "string",
                "null"
              ],
              "description": "Provider reference."
            }
          },
          "required": [
            "name",
            "reference"
          ]
        },
        "metadata": {
          "type": [
            "object",
            "array"
          ],
          "description": "Your non-sensitive JSON metadata. Objects are recommended; do not store secrets or card details."
        },
        "refund_id": {
          "type": "string",
          "description": "Present for refund events."
        },
        "refund_amount": {
          "type": "integer",
          "description": "Present for refund events, in minor units."
        },
        "refund_status": {
          "type": "string",
          "enum": [
            "pending",
            "succeeded",
            "failed"
          ],
          "description": "Present for refund events."
        },
        "reason": {
          "type": [
            "string",
            "null"
          ],
          "description": "Present for refund events."
        }
      },
      "required": [
        "payment_id",
        "reference",
        "amount",
        "amount_refunded",
        "currency",
        "status",
        "customer",
        "provider",
        "metadata"
      ]
    },
    "Event": {
      "type": "object",
      "description": "",
      "properties": {
        "id": {
          "type": "string",
          "description": "Deduplication key: the same ID as Veyqo-Event-Id."
        },
        "type": {
          "type": "string",
          "description": "Normalized event type; see the webhook guide."
        },
        "created_at": {
          "type": "string",
          "description": "Event creation timestamp.",
          "format": "date-time"
        },
        "environment": {
          "type": "string",
          "enum": [
            "sandbox",
            "live"
          ]
        },
        "data": {
          "$ref": "#/components/schemas/EventData"
        }
      },
      "required": [
        "id",
        "type",
        "created_at",
        "environment",
        "data"
      ],
      "example": {
        "id": "evt_01M6EB66SC61Q3RQYAN0693DGM",
        "type": "payment.succeeded",
        "created_at": "2026-11-02T12:00:00+00:00",
        "environment": "sandbox",
        "data": {
          "payment_id": "pay_01M6EB66SC61Q3RQYAN0693DGM",
          "reference": "ORDER-1001",
          "amount": 50000,
          "amount_refunded": 0,
          "currency": "NGN",
          "status": "succeeded",
          "customer": {
            "email": "customer@example.com",
            "name": "Ada Lovelace"
          },
          "provider": {
            "name": "paystack",
            "reference": "provider_reference_example"
          },
          "metadata": {
            "order_id": "1001"
          }
        }
      }
    },
    "Pagination": {
      "type": "object",
      "description": "",
      "properties": {
        "page": {
          "type": "integer",
          "description": "Current page, starting at 1."
        },
        "per_page": {
          "type": "integer",
          "description": "Page size; default 25, maximum 100."
        },
        "total": {
          "type": "integer",
          "description": "Number of matching records."
        },
        "has_more": {
          "type": "boolean",
          "description": "Whether a later page exists."
        }
      },
      "required": [
        "page",
        "per_page",
        "total",
        "has_more"
      ]
    },
    "Error": {
      "type": "object",
      "description": "",
      "properties": {
        "success": {
          "const": false
        },
        "error": {
          "type": "object",
          "description": "",
          "properties": {
            "code": {
              "type": "string",
              "description": "Stable error code. Branch on code, not message text."
            },
            "message": {
              "type": "string",
              "description": "Human-readable explanation; wording can change."
            },
            "details": {
              "type": "object",
              "description": "Optional field validation errors; field names map to arrays of messages. May be absent."
            }
          },
          "required": [
            "code",
            "message"
          ]
        }
      },
      "required": [
        "success",
        "error"
      ]
    },
    "CreatePayment": {
      "type": "object",
      "description": "",
      "properties": {
        "amount": {
          "type": "integer",
          "description": "Integer minor-unit amount. NGN 500.00 is 50000; JPY 500 is 500.",
          "minimum": 1
        },
        "currency": {
          "type": "string",
          "description": "Three-letter currency supported by the selected provider.",
          "minLength": 3,
          "maxLength": 3
        },
        "reference": {
          "type": [
            "string",
            "null"
          ],
          "description": "Unique within this environment. Omitted, defaults to the new payment ID.",
          "maxLength": 190
        },
        "description": {
          "type": [
            "string",
            "null"
          ],
          "description": "Payment description.",
          "maxLength": 255
        },
        "callback_url": {
          "type": [
            "string",
            "null"
          ],
          "description": "HTTPS return URL. Verify payment server-side after the redirect.",
          "format": "uri",
          "maxLength": 2048,
          "pattern": "^https://"
        },
        "provider": {
          "type": [
            "string",
            "null"
          ],
          "description": "Provider slug. Omit only when the environment has a default or exactly one active provider.",
          "maxLength": 40
        },
        "customer": {
          "type": "object",
          "description": "",
          "properties": {
            "email": {
              "type": "string",
              "description": "Required for nested customer requests.",
              "format": "email",
              "maxLength": 190
            },
            "name": {
              "type": [
                "string",
                "null"
              ],
              "description": "",
              "maxLength": 190
            },
            "phone": {
              "type": [
                "string",
                "null"
              ],
              "description": "",
              "maxLength": 32
            }
          },
          "required": [
            "email"
          ]
        },
        "customer_email": {
          "type": "string",
          "description": "Legacy flat alternative to customer.email.",
          "format": "email",
          "maxLength": 190
        },
        "customer_name": {
          "type": [
            "string",
            "null"
          ],
          "description": "Legacy flat name.",
          "maxLength": 190
        },
        "customer_phone": {
          "type": [
            "string",
            "null"
          ],
          "description": "Legacy flat phone.",
          "maxLength": 32
        },
        "metadata": {
          "type": [
            "object",
            "array",
            "null"
          ],
          "description": "Your non-sensitive JSON metadata. Objects are recommended; do not store secrets or card details."
        }
      },
      "required": [
        "amount",
        "currency"
      ],
      "allOf": [
        {
          "if": {
            "required": [
              "customer"
            ],
            "properties": {
              "customer": {
                "type": "object"
              }
            }
          },
          "then": {
            "required": [
              "customer"
            ]
          },
          "else": {
            "required": [
              "customer_email"
            ]
          }
        }
      ]
    },
    "CreateCheckoutSession": {
      "type": "object",
      "description": "",
      "properties": {
        "amount": {
          "type": "integer",
          "description": "Integer minor-unit amount. NGN 500.00 is 50000; JPY 500 is 500.",
          "minimum": 1
        },
        "currency": {
          "type": "string",
          "description": "Three-letter currency supported by the selected provider.",
          "minLength": 3,
          "maxLength": 3
        },
        "reference": {
          "type": [
            "string",
            "null"
          ],
          "description": "Order reference; a session can create multiple uniquely referenced payment attempts.",
          "maxLength": 100
        },
        "description": {
          "type": [
            "string",
            "null"
          ],
          "description": "",
          "maxLength": 500
        },
        "customer": {
          "type": "object",
          "description": "",
          "properties": {
            "email": {
              "type": [
                "string",
                "null"
              ],
              "description": "",
              "format": "email",
              "maxLength": 255
            },
            "name": {
              "type": [
                "string",
                "null"
              ],
              "description": "",
              "maxLength": 255
            }
          },
          "required": []
        },
        "metadata": {
          "type": [
            "object",
            "array",
            "null"
          ],
          "description": "Your non-sensitive JSON metadata. Objects are recommended; do not store secrets or card details.",
          "maxProperties": 20,
          "maxItems": 20
        },
        "provider": {
          "type": [
            "string",
            "null"
          ],
          "description": "Gateway selected by your server or project default; the customer chooses a payment method, not the gateway.",
          "maxLength": 40
        },
        "success_url": {
          "type": [
            "string",
            "null"
          ],
          "description": "HTTP or HTTPS return URL. Use HTTPS in production.",
          "format": "uri",
          "maxLength": 2048
        },
        "cancel_url": {
          "type": [
            "string",
            "null"
          ],
          "description": "HTTP or HTTPS cancellation URL. Use HTTPS in production.",
          "format": "uri",
          "maxLength": 2048
        }
      },
      "required": [
        "amount",
        "currency"
      ]
    },
    "CreateRefund": {
      "type": "object",
      "description": "",
      "properties": {
        "amount": {
          "type": "integer",
          "description": "Omit this property to refund the entire remaining refundable amount. Do not send null.",
          "minimum": 1
        },
        "reason": {
          "type": [
            "string",
            "null"
          ],
          "description": "Reason for the refund.",
          "maxLength": 255
        }
      },
      "required": []
    },
    "BrowserCharge": {
      "type": "object",
      "description": "",
      "properties": {
        "method": {
          "type": "string",
          "enum": [
            "card",
            "bank_transfer",
            "ussd",
            "mobile_money"
          ]
        },
        "email": {
          "type": [
            "string",
            "null"
          ],
          "description": "",
          "format": "email",
          "maxLength": 255
        },
        "name": {
          "type": [
            "string",
            "null"
          ],
          "description": "",
          "maxLength": 255
        },
        "phone": {
          "type": [
            "string",
            "null"
          ],
          "description": "",
          "maxLength": 32
        },
        "bank": {
          "type": [
            "string",
            "null"
          ],
          "description": "Bank code returned in the available method options.",
          "maxLength": 10
        },
        "network": {
          "type": [
            "string",
            "null"
          ],
          "description": "Mobile-money network code from the method options.",
          "maxLength": 10
        }
      },
      "required": [
        "method"
      ]
    },
    "BrowserOtp": {
      "type": "object",
      "description": "",
      "properties": {
        "otp": {
          "type": "string",
          "description": "Customer OTP for the current pending provider action.",
          "maxLength": 12
        }
      },
      "required": [
        "otp"
      ]
    },
    "LinkCustomer": {
      "type": "object",
      "description": "",
      "properties": {
        "email": {
          "type": [
            "string",
            "null"
          ],
          "description": "",
          "format": "email",
          "maxLength": 255
        },
        "name": {
          "type": [
            "string",
            "null"
          ],
          "description": "",
          "maxLength": 255
        }
      },
      "required": []
    },
    "PaymentLink": {
      "type": "object",
      "description": "",
      "properties": {
        "id": {
          "type": "string",
          "description": "Payment link ID."
        },
        "object": {
          "const": "payment_link"
        },
        "title": {
          "type": "string",
          "description": ""
        },
        "description": {
          "type": [
            "string",
            "null"
          ],
          "description": ""
        },
        "amount": {
          "type": "integer",
          "description": "Fixed minor-unit amount configured in the dashboard."
        },
        "currency": {
          "type": "string",
          "description": ""
        },
        "merchant": {
          "type": "object",
          "description": "",
          "properties": {
            "name": {
              "type": "string",
              "description": ""
            }
          },
          "required": [
            "name"
          ]
        },
        "sandbox": {
          "type": "boolean"
        }
      },
      "required": [
        "id",
        "object",
        "title",
        "description",
        "amount",
        "currency",
        "merchant",
        "sandbox"
      ],
      "example": {
        "id": "plink_01M6EB66SC61Q3RQYAN0693DGM",
        "object": "payment_link",
        "title": "Order 1001",
        "description": null,
        "amount": 50000,
        "currency": "NGN",
        "merchant": {
          "name": "Example Store"
        },
        "sandbox": true
      }
    },
    "BrowserSession": {
      "type": "object",
      "description": "",
      "properties": {
        "id": {
          "type": "string",
          "description": "Checkout session ID (cs_ prefix)."
        },
        "object": {
          "const": "checkout_session"
        },
        "url": {
          "type": "string",
          "description": "Hosted Veyqo URL; redirect here or open this session using VeyqoCheckout.",
          "format": "uri"
        },
        "status": {
          "type": "string",
          "enum": [
            "open",
            "completed",
            "expired"
          ]
        },
        "source": {
          "type": "string",
          "enum": [
            "api",
            "browser",
            "link"
          ]
        },
        "provider": {
          "type": [
            "object",
            "null"
          ],
          "properties": {
            "slug": {
              "type": "string",
              "description": ""
            },
            "name": {
              "type": "string",
              "description": ""
            }
          },
          "description": "Available provider identity, never secret credentials."
        },
        "amount": {
          "type": "integer",
          "description": "Server-defined amount in minor units."
        },
        "currency": {
          "type": "string",
          "description": "Three-letter currency."
        },
        "reference": {
          "type": [
            "string",
            "null"
          ],
          "description": "Your order reference, when supplied."
        },
        "description": {
          "type": [
            "string",
            "null"
          ],
          "description": "Checkout description."
        },
        "customer_email": {
          "type": [
            "string",
            "null"
          ],
          "description": "Customer email if already supplied."
        },
        "payment": {
          "anyOf": [
            {
              "type": "object",
              "description": "",
              "properties": {
                "id": {
                  "type": "string",
                  "description": ""
                },
                "reference": {
                  "type": "string",
                  "description": ""
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "created",
                    "pending",
                    "processing",
                    "succeeded",
                    "failed",
                    "cancelled",
                    "refunded",
                    "partially_refunded"
                  ]
                },
                "provider": {
                  "type": "string",
                  "description": ""
                }
              },
              "required": [
                "id",
                "reference",
                "status",
                "provider"
              ]
            },
            {
              "type": "null"
            }
          ],
          "description": "Current payment attempt, if any. A session can have multiple attempts over time."
        },
        "success_url": {
          "type": [
            "string",
            "null"
          ],
          "description": "Configured return URL. A redirect is not proof of payment."
        },
        "cancel_url": {
          "type": [
            "string",
            "null"
          ],
          "description": "Configured cancellation URL."
        },
        "expires_at": {
          "type": "string",
          "description": "Session expiry time.",
          "format": "date-time"
        },
        "completed_at": {
          "type": [
            "string",
            "null"
          ],
          "description": "ISO 8601 timestamp.",
          "format": "date-time"
        },
        "created_at": {
          "type": [
            "string",
            "null"
          ],
          "description": "ISO 8601 timestamp.",
          "format": "date-time"
        },
        "merchant": {
          "type": "object",
          "description": "",
          "properties": {
            "name": {
              "type": "string",
              "description": ""
            }
          },
          "required": [
            "name"
          ]
        },
        "sandbox": {
          "type": "boolean"
        },
        "needs_email": {
          "type": "boolean"
        },
        "methods": {
          "type": "array",
          "items": {
            "type": "object"
          },
          "description": "Currency-dependent method descriptions. Use the hosted page/SDK instead of hard-coding this provider-specific payload."
        },
        "next_action": {
          "type": [
            "object",
            "null"
          ],
          "description": "Provider-specific action for the hosted checkout: bank details, USSD instructions, OTP or secure card form. May change per method."
        }
      },
      "required": [
        "id",
        "object",
        "url",
        "status",
        "source",
        "provider",
        "amount",
        "currency",
        "reference",
        "description",
        "customer_email",
        "payment",
        "success_url",
        "cancel_url",
        "expires_at",
        "completed_at",
        "created_at",
        "merchant",
        "sandbox",
        "needs_email",
        "methods",
        "next_action"
      ],
      "example": {
        "id": "cs_01M6EB66SC61Q3RQYAN0693DGM",
        "object": "checkout_session",
        "url": "https://veyqo.org/pay/cs_01M6EB66SC61Q3RQYAN0693DGM",
        "status": "open",
        "source": "api",
        "provider": {
          "slug": "paystack",
          "name": "Paystack"
        },
        "amount": 50000,
        "currency": "NGN",
        "reference": "ORDER-1001",
        "description": "Order 1001",
        "customer_email": "customer@example.com",
        "payment": null,
        "success_url": "https://shop.example.com/thanks",
        "cancel_url": "https://shop.example.com/cart",
        "expires_at": "2026-11-02T13:00:00+00:00",
        "completed_at": null,
        "created_at": "2026-11-02T12:00:00+00:00",
        "merchant": {
          "name": "Example Store"
        },
        "sandbox": true,
        "needs_email": false,
        "methods": [],
        "next_action": null
      }
    }
  },
  "browserEndpoints": [
    {
      "id": "browser.sessions.create",
      "method": "POST",
      "path": "/sessions",
      "summary": "Create a browser checkout session",
      "description": "Starts a browser-defined checkout with a publishable key. The browser can change the amount, so reconcile against your server order. Success/cancel URL hosts must match the request Origin. Prefer server-created checkout for trusted pricing.",
      "scope": null,
      "auth": "publishable",
      "runnable": false,
      "requestSchema": "CreateCheckoutSession",
      "responseSchema": "CheckoutSession",
      "responseExample": {
        "success": true,
        "data": {
          "id": "cs_01M6EB66SC61Q3RQYAN0693DGM",
          "object": "checkout_session",
          "url": "https://veyqo.org/pay/cs_01M6EB66SC61Q3RQYAN0693DGM",
          "status": "open",
          "source": "browser",
          "provider": "paystack",
          "amount": 50000,
          "currency": "NGN",
          "reference": "ORDER-1001",
          "description": "Order 1001",
          "customer_email": "customer@example.com",
          "payment": null,
          "success_url": "https://shop.example.com/thanks",
          "cancel_url": "https://shop.example.com/cart",
          "expires_at": "2026-11-02T13:00:00+00:00",
          "completed_at": null,
          "created_at": "2026-11-02T12:00:00+00:00"
        }
      },
      "example": {
        "amount": 50000,
        "currency": "NGN",
        "reference": "ORDER-1001",
        "provider": "paystack",
        "customer": {
          "email": "customer@example.com"
        }
      },
      "successStatus": 201,
      "parameters": [],
      "errors": [
        "VALIDATION_FAILED",
        "RESOURCE_NOT_FOUND",
        "RATE_LIMIT_EXCEEDED",
        "PROVIDER_UNAVAILABLE",
        "INTERNAL_ERROR",
        "INVALID_API_KEY"
      ]
    },
    {
      "id": "browser.sessions.show",
      "method": "GET",
      "path": "/sessions/{id}",
      "summary": "Read browser checkout state",
      "description": "Possession of the session ID addresses this customer checkout. These endpoints support the hosted page and SDK; prefer those clients over reimplementing provider-specific actions.",
      "scope": null,
      "auth": "session",
      "runnable": false,
      "requestSchema": null,
      "responseSchema": "BrowserSession",
      "responseExample": {
        "success": true,
        "data": {
          "id": "cs_01M6EB66SC61Q3RQYAN0693DGM",
          "object": "checkout_session",
          "url": "https://veyqo.org/pay/cs_01M6EB66SC61Q3RQYAN0693DGM",
          "status": "open",
          "source": "api",
          "provider": {
            "slug": "paystack",
            "name": "Paystack"
          },
          "amount": 50000,
          "currency": "NGN",
          "reference": "ORDER-1001",
          "description": "Order 1001",
          "customer_email": "customer@example.com",
          "payment": null,
          "success_url": "https://shop.example.com/thanks",
          "cancel_url": "https://shop.example.com/cart",
          "expires_at": "2026-11-02T13:00:00+00:00",
          "completed_at": null,
          "created_at": "2026-11-02T12:00:00+00:00",
          "merchant": {
            "name": "Example Store"
          },
          "sandbox": true,
          "needs_email": false,
          "methods": [
            {
              "id": "card"
            },
            {
              "id": "bank_transfer"
            },
            {
              "id": "ussd",
              "banks": [
                {
                  "code": "737",
                  "name": "GTBank"
                },
                {
                  "code": "919",
                  "name": "UBA"
                },
                {
                  "code": "822",
                  "name": "Sterling Bank"
                },
                {
                  "code": "966",
                  "name": "Zenith Bank"
                }
              ]
            }
          ],
          "next_action": null
        }
      },
      "example": null,
      "successStatus": 200,
      "parameters": [],
      "errors": [
        "VALIDATION_FAILED",
        "RESOURCE_NOT_FOUND",
        "RATE_LIMIT_EXCEEDED",
        "PROVIDER_UNAVAILABLE",
        "INTERNAL_ERROR"
      ]
    },
    {
      "id": "browser.sessions.charge",
      "method": "POST",
      "path": "/sessions/{id}/charge",
      "summary": "Start a checkout method",
      "description": "Possession of the session ID addresses this customer checkout. These endpoints support the hosted page and SDK; prefer those clients over reimplementing provider-specific actions.",
      "scope": null,
      "auth": "session",
      "runnable": false,
      "requestSchema": "BrowserCharge",
      "responseSchema": "BrowserSession",
      "responseExample": {
        "success": true,
        "data": {
          "id": "cs_01M6EB66SC61Q3RQYAN0693DGM",
          "object": "checkout_session",
          "url": "https://veyqo.org/pay/cs_01M6EB66SC61Q3RQYAN0693DGM",
          "status": "open",
          "source": "api",
          "provider": {
            "slug": "paystack",
            "name": "Paystack"
          },
          "amount": 50000,
          "currency": "NGN",
          "reference": "ORDER-1001",
          "description": "Order 1001",
          "customer_email": "customer@example.com",
          "payment": null,
          "success_url": "https://shop.example.com/thanks",
          "cancel_url": "https://shop.example.com/cart",
          "expires_at": "2026-11-02T13:00:00+00:00",
          "completed_at": null,
          "created_at": "2026-11-02T12:00:00+00:00",
          "merchant": {
            "name": "Example Store"
          },
          "sandbox": true,
          "needs_email": false,
          "methods": [
            {
              "id": "card"
            },
            {
              "id": "bank_transfer"
            },
            {
              "id": "ussd",
              "banks": [
                {
                  "code": "737",
                  "name": "GTBank"
                },
                {
                  "code": "919",
                  "name": "UBA"
                },
                {
                  "code": "822",
                  "name": "Sterling Bank"
                },
                {
                  "code": "966",
                  "name": "Zenith Bank"
                }
              ]
            }
          ],
          "next_action": null
        }
      },
      "example": {
        "method": "bank_transfer",
        "email": "customer@example.com"
      },
      "successStatus": 200,
      "parameters": [],
      "errors": [
        "VALIDATION_FAILED",
        "RESOURCE_NOT_FOUND",
        "RATE_LIMIT_EXCEEDED",
        "PROVIDER_UNAVAILABLE",
        "INTERNAL_ERROR"
      ]
    },
    {
      "id": "browser.sessions.otp",
      "method": "POST",
      "path": "/sessions/{id}/otp",
      "summary": "Submit a checkout OTP",
      "description": "Possession of the session ID addresses this customer checkout. These endpoints support the hosted page and SDK; prefer those clients over reimplementing provider-specific actions.",
      "scope": null,
      "auth": "session",
      "runnable": false,
      "requestSchema": "BrowserOtp",
      "responseSchema": "BrowserSession",
      "responseExample": {
        "success": true,
        "data": {
          "id": "cs_01M6EB66SC61Q3RQYAN0693DGM",
          "object": "checkout_session",
          "url": "https://veyqo.org/pay/cs_01M6EB66SC61Q3RQYAN0693DGM",
          "status": "open",
          "source": "api",
          "provider": {
            "slug": "paystack",
            "name": "Paystack"
          },
          "amount": 50000,
          "currency": "NGN",
          "reference": "ORDER-1001",
          "description": "Order 1001",
          "customer_email": "customer@example.com",
          "payment": null,
          "success_url": "https://shop.example.com/thanks",
          "cancel_url": "https://shop.example.com/cart",
          "expires_at": "2026-11-02T13:00:00+00:00",
          "completed_at": null,
          "created_at": "2026-11-02T12:00:00+00:00",
          "merchant": {
            "name": "Example Store"
          },
          "sandbox": true,
          "needs_email": false,
          "methods": [
            {
              "id": "card"
            },
            {
              "id": "bank_transfer"
            },
            {
              "id": "ussd",
              "banks": [
                {
                  "code": "737",
                  "name": "GTBank"
                },
                {
                  "code": "919",
                  "name": "UBA"
                },
                {
                  "code": "822",
                  "name": "Sterling Bank"
                },
                {
                  "code": "966",
                  "name": "Zenith Bank"
                }
              ]
            }
          ],
          "next_action": null
        }
      },
      "example": {
        "otp": "123456"
      },
      "successStatus": 200,
      "parameters": [],
      "errors": [
        "VALIDATION_FAILED",
        "RESOURCE_NOT_FOUND",
        "RATE_LIMIT_EXCEEDED",
        "PROVIDER_UNAVAILABLE",
        "INTERNAL_ERROR"
      ]
    },
    {
      "id": "browser.links.show",
      "method": "GET",
      "path": "/links/{id}",
      "summary": "Read a payment link",
      "description": "Possession of the payment link ID addresses this checkout. The fixed amount comes from the dashboard link, never the request body.",
      "scope": null,
      "auth": "link",
      "runnable": false,
      "requestSchema": null,
      "responseSchema": "PaymentLink",
      "responseExample": {
        "success": true,
        "data": {
          "id": "plink_01M6EB66SC61Q3RQYAN0693DGM",
          "object": "payment_link",
          "title": "Order 1001",
          "description": null,
          "amount": 50000,
          "currency": "NGN",
          "merchant": {
            "name": "Example Store"
          },
          "sandbox": true
        }
      },
      "example": null,
      "successStatus": 200,
      "parameters": [],
      "errors": [
        "VALIDATION_FAILED",
        "RESOURCE_NOT_FOUND",
        "RATE_LIMIT_EXCEEDED",
        "PROVIDER_UNAVAILABLE",
        "INTERNAL_ERROR"
      ]
    },
    {
      "id": "browser.links.sessions",
      "method": "POST",
      "path": "/links/{id}/sessions",
      "summary": "Start a payment-link session",
      "description": "Possession of the payment link ID addresses this checkout. The fixed amount comes from the dashboard link, never the request body.",
      "scope": null,
      "auth": "link",
      "runnable": false,
      "requestSchema": "LinkCustomer",
      "responseSchema": "CheckoutSession",
      "responseExample": {
        "success": true,
        "data": {
          "id": "cs_01M6EB66SC61Q3RQYAN0693DGM",
          "object": "checkout_session",
          "url": "https://veyqo.org/pay/cs_01M6EB66SC61Q3RQYAN0693DGM",
          "status": "open",
          "source": "link",
          "provider": "paystack",
          "amount": 50000,
          "currency": "NGN",
          "reference": "ORDER-1001",
          "description": "Order 1001",
          "customer_email": "customer@example.com",
          "payment": null,
          "success_url": "https://shop.example.com/thanks",
          "cancel_url": "https://shop.example.com/cart",
          "expires_at": "2026-11-02T13:00:00+00:00",
          "completed_at": null,
          "created_at": "2026-11-02T12:00:00+00:00"
        }
      },
      "example": {
        "email": "customer@example.com"
      },
      "successStatus": 201,
      "parameters": [],
      "errors": [
        "VALIDATION_FAILED",
        "RESOURCE_NOT_FOUND",
        "RATE_LIMIT_EXCEEDED",
        "PROVIDER_UNAVAILABLE",
        "INTERNAL_ERROR"
      ]
    }
  ],
  "errors": [
    {
      "code": "VALIDATION_FAILED",
      "status": 422,
      "message": "The given data was invalid.",
      "cause": "A field, amount, URL, payment state or capability is invalid.",
      "recovery": "Read error.details when present, correct the named fields and retry only after correction. Validation messages may describe state/capability errors without field details.",
      "retry": "No automatic retry.",
      "surface": "all"
    },
    {
      "code": "UNAUTHENTICATED",
      "status": 401,
      "message": "This request requires authentication.",
      "cause": "A dashboard/admin session or protected session action has no valid authentication.",
      "recovery": "Sign in to the relevant dashboard. Public server API requests should use a secret API key, not session cookies.",
      "retry": "After authenticating.",
      "surface": "dashboard/admin"
    },
    {
      "code": "ORGANIZATION_REQUIRED",
      "status": 400,
      "message": "Name the organization this request acts within.",
      "cause": "A dashboard request did not select an organization.",
      "recovery": "Select an organization or supply its required dashboard context. Public API keys already bind their organization.",
      "retry": "After selecting context.",
      "surface": "dashboard"
    },
    {
      "code": "SESSION_EXPIRED",
      "status": 419,
      "message": "Your session expired. Refresh the page and try again.",
      "cause": "The dashboard/admin CSRF token or browser session expired.",
      "recovery": "Refresh the session and CSRF cookie, then retry the dashboard action. This is not a public API-key error.",
      "retry": "After refreshing the session.",
      "surface": "dashboard/admin"
    },
    {
      "code": "INVALID_API_KEY",
      "status": 401,
      "message": "That API key is not valid.",
      "cause": "The key is absent, malformed, revoked or belongs to the wrong authentication surface.",
      "recovery": "Use a current kc_test_ or kc_live_ secret key on /api/v1. Use a pk_test_ or pk_live_ publishable key only on browser checkout.",
      "retry": "After fixing credentials.",
      "surface": "public/checkout"
    },
    {
      "code": "INSUFFICIENT_PERMISSION",
      "status": 403,
      "message": "You do not have permission to do that.",
      "cause": "The key lacks an endpoint scope, or a signed-in role lacks permission.",
      "recovery": "Grant the required scope or use a suitably scoped key. Dashboard organization roles and staff permissions are separate.",
      "retry": "After permission changes.",
      "surface": "all"
    },
    {
      "code": "EMAIL_NOT_VERIFIED",
      "status": 403,
      "message": "Verify your email address to continue.",
      "cause": "The dashboard user has not verified their email.",
      "recovery": "Complete email verification and refresh the session before managing live integration settings.",
      "retry": "After verification.",
      "surface": "dashboard"
    },
    {
      "code": "TWO_FACTOR_REQUIRED",
      "status": 403,
      "message": "Set up two-factor authentication to continue.",
      "cause": "The protected dashboard/admin operation requires two-factor enrollment.",
      "recovery": "Complete authenticator enrollment using the relevant account. Do not disable two-factor checks in an integration.",
      "retry": "After enrollment.",
      "surface": "dashboard/admin"
    },
    {
      "code": "ENVIRONMENT_MISMATCH",
      "status": 403,
      "message": "That resource belongs to a different environment.",
      "cause": "A known resource is in the other environment of the same project.",
      "recovery": "Use the correct sandbox/live key. Resources outside the key’s project remain not-found instead of disclosing ownership.",
      "retry": "After selecting the correct key.",
      "surface": "public"
    },
    {
      "code": "RESOURCE_NOT_FOUND",
      "status": 404,
      "message": "We could not find what you were looking for.",
      "cause": "The resource does not exist, is inactive or is not visible to this environment.",
      "recovery": "Check the ID, project and environment. Do not guess another project’s IDs. An inactive payment link is also not-found.",
      "retry": "No blind retry.",
      "surface": "all"
    },
    {
      "code": "PAYMENT_NOT_FOUND",
      "status": 404,
      "message": "That payment could not be found.",
      "cause": "No visible payment matches the ID or reference.",
      "recovery": "Use the saved Veyqo payment ID or correctly URL-encoded merchant reference with the original project’s key.",
      "retry": "No blind retry.",
      "surface": "public"
    },
    {
      "code": "DUPLICATE_REFERENCE",
      "status": 409,
      "message": "That reference has already been used in this environment.",
      "cause": "A payment already exists with this reference in the environment.",
      "recovery": "Retrieve that payment and reconcile its state. For a genuinely new attempt, use a new unique reference and operation key; do not create a second charge just because a response was lost.",
      "retry": "Reconcile first.",
      "surface": "public"
    },
    {
      "code": "IDEMPOTENCY_KEY_REUSED",
      "status": 409,
      "message": "That idempotency key was used with a different request body.",
      "cause": "An environment already used this key for a different method/path/body.",
      "recovery": "Reuse the exact original request to recover that operation, or use a new key only for a genuinely different operation.",
      "retry": "Do not retry a changed body with that key.",
      "surface": "public"
    },
    {
      "code": "IDEMPOTENCY_IN_PROGRESS",
      "status": 409,
      "message": "A request with that idempotency key is still in progress.",
      "cause": "Another request still holds this operation key.",
      "recovery": "Wait briefly, retry with the same key and unchanged request, then reconcile by reference if the result remains uncertain.",
      "retry": "Back off with jitter; preserve key/body.",
      "surface": "public"
    },
    {
      "code": "PAYMENT_ALREADY_REFUNDED",
      "status": 409,
      "message": "That payment has already been fully refunded.",
      "cause": "The payment has no refundable amount remaining.",
      "recovery": "Read the payment and refunds, compare amount_refunded to amount, and avoid issuing a duplicate refund.",
      "retry": "No.",
      "surface": "public"
    },
    {
      "code": "INVALID_PROVIDER",
      "status": 422,
      "message": "That provider is not recognised.",
      "cause": "The provider slug is unknown, disabled, or lacks the requested capability.",
      "recovery": "Choose a supported connected provider. Refund/direct-checkout capabilities can differ from simple payment creation.",
      "retry": "After configuration or provider selection changes.",
      "surface": "public"
    },
    {
      "code": "PROVIDER_NOT_CONNECTED",
      "status": 422,
      "message": "That provider is not connected in this environment.",
      "cause": "No eligible provider is assigned to this project environment, or provider selection is ambiguous.",
      "recovery": "Connect a provider, choose the project default, or explicitly pass provider. An account shared with another project still needs its own assignment here.",
      "retry": "After configuration changes.",
      "surface": "public"
    },
    {
      "code": "INVALID_CURRENCY",
      "status": 422,
      "message": "That currency is not supported by the selected provider.",
      "cause": "The selected provider cannot process this currency.",
      "recovery": "Use a supported currency/provider pair. Do not silently convert amounts or currencies.",
      "retry": "After correcting the request.",
      "surface": "public"
    },
    {
      "code": "PROVIDER_AUTHENTICATION_FAILED",
      "status": 502,
      "message": "Unable to authenticate with the selected provider.",
      "cause": "Veyqo could not authenticate with the provider’s stored account credentials.",
      "recovery": "The merchant must check/rotate the provider credentials in the dashboard. Do not expose those secrets to your application users.",
      "retry": "After credential correction; reconcile existing payment first.",
      "surface": "public"
    },
    {
      "code": "PROVIDER_UNAVAILABLE",
      "status": 503,
      "message": "The provider is not responding. Try again shortly.",
      "cause": "A provider timed out, was unreachable, or a checkout method is temporarily unavailable.",
      "recovery": "Check the existing payment and verify its state before starting another attempt. Retry safe reads with backoff; preserve operation identity for retried writes.",
      "retry": "Conditional: reconcile unknown outcomes first.",
      "surface": "public/checkout"
    },
    {
      "code": "PROVIDER_REQUEST_FAILED",
      "status": 422,
      "message": "The provider refused the request.",
      "cause": "The provider rejected an otherwise accepted Veyqo request.",
      "recovery": "Read the safe message, inspect the payment’s failure details and correct the request or provider account. Never repeatedly retry a business rejection.",
      "retry": "Only after resolving the cause.",
      "surface": "public"
    },
    {
      "code": "INVALID_WEBHOOK_SIGNATURE",
      "status": 401,
      "message": "The webhook signature could not be verified.",
      "cause": "A provider ingress signature could not be verified.",
      "recovery": "Check the provider’s webhook secret and the exact incoming account URL. Your own webhook handler must independently validate Veyqo signatures.",
      "retry": "Provider delivery may retry after secret correction.",
      "surface": "provider ingress"
    },
    {
      "code": "PLAN_LIMIT_REACHED",
      "status": 402,
      "message": "Your plan does not include that. Upgrade to continue.",
      "cause": "The organization’s plan does not permit the operation or limit reached.",
      "recovery": "Review the active plan, project/usage allowances and billing status with the organization owner.",
      "retry": "After resolving plan/billing restrictions.",
      "surface": "public/dashboard"
    },
    {
      "code": "RATE_LIMIT_EXCEEDED",
      "status": 429,
      "message": "Too many requests. Please wait a moment and try again.",
      "cause": "The API key or address exceeded a rate limit.",
      "recovery": "Honor Retry-After, use bounded exponential backoff with jitter, and reduce concurrent requests. Read X-RateLimit headers.",
      "retry": "Yes, after Retry-After; preserve write idempotency.",
      "surface": "all"
    },
    {
      "code": "METHOD_NOT_ALLOWED",
      "status": 405,
      "message": "That method is not allowed on this endpoint.",
      "cause": "The path exists but does not accept that HTTP method.",
      "recovery": "Use the method documented for the endpoint, such as POST for verification and refunds.",
      "retry": "After fixing the method.",
      "surface": "all"
    },
    {
      "code": "INTERNAL_ERROR",
      "status": 500,
      "message": "Something went wrong on our end.",
      "cause": "Veyqo encountered an unexpected server error.",
      "recovery": "Record X-Request-Id, timestamp and sanitized request context. Reconcile unknown payment outcomes before retrying a write; contact support if it persists.",
      "retry": "Safe reads: bounded backoff. Writes: reconcile first.",
      "surface": "all"
    }
  ],
  "scopes": [
    {
      "name": "payments:read",
      "description": "Read payments",
      "implies": []
    },
    {
      "name": "payments:write",
      "description": "Create payments",
      "implies": [
        "payments:read"
      ]
    },
    {
      "name": "refunds:read",
      "description": "Read refunds",
      "implies": []
    },
    {
      "name": "refunds:write",
      "description": "Issue refunds",
      "implies": [
        "refunds:read"
      ]
    },
    {
      "name": "events:read",
      "description": "Read events",
      "implies": []
    },
    {
      "name": "webhooks:read",
      "description": "Read webhook endpoints",
      "implies": []
    },
    {
      "name": "webhooks:write",
      "description": "Manage webhook endpoints",
      "implies": [
        "webhooks:read"
      ]
    }
  ],
  "events": [
    {
      "name": "payment.created",
      "description": "A payment was initialized."
    },
    {
      "name": "payment.pending",
      "description": "Awaiting the customer."
    },
    {
      "name": "payment.processing",
      "description": "The provider is settling it."
    },
    {
      "name": "payment.succeeded",
      "description": "Funds were captured."
    },
    {
      "name": "payment.failed",
      "description": "The payment will not complete."
    },
    {
      "name": "refund.created",
      "description": "A refund was requested."
    },
    {
      "name": "refund.succeeded",
      "description": "The refund reached the customer."
    },
    {
      "name": "refund.failed",
      "description": "The provider rejected the refund."
    }
  ],
  "paymentStatuses": [
    "created",
    "pending",
    "processing",
    "succeeded",
    "failed",
    "cancelled",
    "refunded",
    "partially_refunded"
  ],
  "refundStatuses": [
    "pending",
    "succeeded",
    "failed"
  ],
  "currencies": {
    "NGN": {
      "name": "Nigerian Naira",
      "exponent": 2
    },
    "USD": {
      "name": "US Dollar",
      "exponent": 2
    },
    "GHS": {
      "name": "Ghanaian Cedi",
      "exponent": 2
    },
    "KES": {
      "name": "Kenyan Shilling",
      "exponent": 2
    },
    "ZAR": {
      "name": "South African Rand",
      "exponent": 2
    },
    "EUR": {
      "name": "Euro",
      "exponent": 2
    },
    "GBP": {
      "name": "British Pound",
      "exponent": 2
    },
    "CAD": {
      "name": "Canadian Dollar",
      "exponent": 2
    },
    "AUD": {
      "name": "Australian Dollar",
      "exponent": 2
    },
    "SGD": {
      "name": "Singapore Dollar",
      "exponent": 2
    },
    "JPY": {
      "name": "Japanese Yen",
      "exponent": 0
    },
    "UGX": {
      "name": "Ugandan Shilling",
      "exponent": 0
    },
    "TZS": {
      "name": "Tanzanian Shilling",
      "exponent": 0
    }
  },
  "policies": {
    "paginationDefault": 25,
    "paginationMax": 100,
    "apiPerMinute": 100,
    "paymentsPerMinute": 60,
    "idempotencySeconds": 86400,
    "webhookTimestampTolerance": 300,
    "webhookVersion": "2026-09-01",
    "webhookRetryDelays": [
      0,
      60,
      300,
      900,
      3600,
      21600,
      86400
    ],
    "webhookTimeout": 10,
    "webhookRotationGrace": 86400,
    "webhookAutoDisableAfter": 14,
    "checkoutMinutes": 60
  }
}
