{
  "openapi": "3.1.0",
  "info": {
    "title": "Veyqo Public Integration API",
    "version": "2026-11-02",
    "description": "Server API and separate browser checkout surface. All examples are illustrative. Configure provider accounts and outgoing webhooks in the dashboard.",
    "contact": {
      "url": "https://veyqo.org/contact"
    }
  },
  "servers": [
    {
      "url": "https://api.veyqo.org/api/v1"
    }
  ],
  "paths": {
    "/payments": {
      "post": {
        "operationId": "payments_create",
        "tags": [
          "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.",
        "security": [
          {
            "SecretKey": []
          }
        ],
        "x-required-scope": "payments:write",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Persist one key per operation and reuse it unchanged on retries. Recommended for every create/refund.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePayment"
              },
              "example": {
                "amount": 50000,
                "currency": "NGN",
                "reference": "ORDER-1001",
                "provider": "paystack",
                "customer": {
                  "email": "customer@example.com",
                  "name": "Ada Lovelace"
                },
                "metadata": {
                  "order_id": "1001"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful request. Inspect resource status before fulfilment.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                },
                "description": "Support correlation ID."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Payment"
                    }
                  }
                },
                "example": {
                  "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"
                  }
                }
              }
            }
          },
          "401": {
            "description": "INVALID_API_KEY: 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. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INVALID_API_KEY": {
                    "summary": "The key is absent, malformed, revoked or belongs to the wrong authentication surface.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INVALID_API_KEY",
                        "message": "That API key is not valid."
                      }
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "PLAN_LIMIT_REACHED: Review the active plan, project/usage allowances and billing status with the organization owner. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "PLAN_LIMIT_REACHED": {
                    "summary": "The organization’s plan does not permit the operation or limit reached.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "PLAN_LIMIT_REACHED",
                        "message": "Your plan does not include that. Upgrade to continue."
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "INSUFFICIENT_PERMISSION: Grant the required scope or use a suitably scoped key. Dashboard organization roles and staff permissions are separate. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INSUFFICIENT_PERMISSION": {
                    "summary": "The key lacks an endpoint scope, or a signed-in role lacks permission.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INSUFFICIENT_PERMISSION",
                        "message": "You do not have permission to do that."
                      }
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: Use the method documented for the endpoint, such as POST for verification and refunds. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "METHOD_NOT_ALLOWED": {
                    "summary": "The path exists but does not accept that HTTP method.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "METHOD_NOT_ALLOWED",
                        "message": "That method is not allowed on this endpoint."
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "DUPLICATE_REFERENCE: 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. IDEMPOTENCY_KEY_REUSED: Reuse the exact original request to recover that operation, or use a new key only for a genuinely different operation. IDEMPOTENCY_IN_PROGRESS: Wait briefly, retry with the same key and unchanged request, then reconcile by reference if the result remains uncertain. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "DUPLICATE_REFERENCE": {
                    "summary": "A payment already exists with this reference in the environment.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "DUPLICATE_REFERENCE",
                        "message": "That reference has already been used in this environment."
                      }
                    }
                  },
                  "IDEMPOTENCY_KEY_REUSED": {
                    "summary": "An environment already used this key for a different method/path/body.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "IDEMPOTENCY_KEY_REUSED",
                        "message": "That idempotency key was used with a different request body."
                      }
                    }
                  },
                  "IDEMPOTENCY_IN_PROGRESS": {
                    "summary": "Another request still holds this operation key.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "IDEMPOTENCY_IN_PROGRESS",
                        "message": "A request with that idempotency key is still in progress."
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "VALIDATION_FAILED: Read error.details when present, correct the named fields and retry only after correction. Validation messages may describe state/capability errors without field details. PROVIDER_NOT_CONNECTED: Connect a provider, choose the project default, or explicitly pass provider. An account shared with another project still needs its own assignment here. INVALID_PROVIDER: Choose a supported connected provider. Refund/direct-checkout capabilities can differ from simple payment creation. INVALID_CURRENCY: Use a supported currency/provider pair. Do not silently convert amounts or currencies. PROVIDER_REQUEST_FAILED: Read the safe message, inspect the payment’s failure details and correct the request or provider account. Never repeatedly retry a business rejection. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "VALIDATION_FAILED": {
                    "summary": "A field, amount, URL, payment state or capability is invalid.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "VALIDATION_FAILED",
                        "message": "The given data was invalid."
                      }
                    }
                  },
                  "PROVIDER_NOT_CONNECTED": {
                    "summary": "No eligible provider is assigned to this project environment, or provider selection is ambiguous.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "PROVIDER_NOT_CONNECTED",
                        "message": "That provider is not connected in this environment."
                      }
                    }
                  },
                  "INVALID_PROVIDER": {
                    "summary": "The provider slug is unknown, disabled, or lacks the requested capability.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INVALID_PROVIDER",
                        "message": "That provider is not recognised."
                      }
                    }
                  },
                  "INVALID_CURRENCY": {
                    "summary": "The selected provider cannot process this currency.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INVALID_CURRENCY",
                        "message": "That currency is not supported by the selected provider."
                      }
                    }
                  },
                  "PROVIDER_REQUEST_FAILED": {
                    "summary": "The provider rejected an otherwise accepted Veyqo request.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "PROVIDER_REQUEST_FAILED",
                        "message": "The provider refused the request."
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMIT_EXCEEDED: Honor Retry-After, use bounded exponential backoff with jitter, and reduce concurrent requests. Read X-RateLimit headers. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RATE_LIMIT_EXCEEDED": {
                    "summary": "The API key or address exceeded a rate limit.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RATE_LIMIT_EXCEEDED",
                        "message": "Too many requests. Please wait a moment and try again."
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying."
              }
            }
          },
          "500": {
            "description": "INTERNAL_ERROR: Record X-Request-Id, timestamp and sanitized request context. Reconcile unknown payment outcomes before retrying a write; contact support if it persists. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INTERNAL_ERROR": {
                    "summary": "Veyqo encountered an unexpected server error.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INTERNAL_ERROR",
                        "message": "Something went wrong on our end."
                      }
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "PROVIDER_AUTHENTICATION_FAILED: The merchant must check/rotate the provider credentials in the dashboard. Do not expose those secrets to your application users. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "PROVIDER_AUTHENTICATION_FAILED": {
                    "summary": "Veyqo could not authenticate with the provider’s stored account credentials.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "PROVIDER_AUTHENTICATION_FAILED",
                        "message": "Unable to authenticate with the selected provider."
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "PROVIDER_UNAVAILABLE: Check the existing payment and verify its state before starting another attempt. Retry safe reads with backoff; preserve operation identity for retried writes. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "PROVIDER_UNAVAILABLE": {
                    "summary": "A provider timed out, was unreachable, or a checkout method is temporarily unavailable.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "PROVIDER_UNAVAILABLE",
                        "message": "The provider is not responding. Try again shortly."
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "payments_list",
        "tags": [
          "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.",
        "security": [
          {
            "SecretKey": []
          }
        ],
        "x-required-scope": "payments:read",
        "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"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful request. Inspect resource status before fulfilment.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                },
                "description": "Support correlation ID."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Payment"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Pagination"
                    }
                  }
                },
                "example": {
                  "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
                  }
                }
              }
            }
          },
          "401": {
            "description": "INVALID_API_KEY: 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. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INVALID_API_KEY": {
                    "summary": "The key is absent, malformed, revoked or belongs to the wrong authentication surface.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INVALID_API_KEY",
                        "message": "That API key is not valid."
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "INSUFFICIENT_PERMISSION: Grant the required scope or use a suitably scoped key. Dashboard organization roles and staff permissions are separate. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INSUFFICIENT_PERMISSION": {
                    "summary": "The key lacks an endpoint scope, or a signed-in role lacks permission.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INSUFFICIENT_PERMISSION",
                        "message": "You do not have permission to do that."
                      }
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: Use the method documented for the endpoint, such as POST for verification and refunds. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "METHOD_NOT_ALLOWED": {
                    "summary": "The path exists but does not accept that HTTP method.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "METHOD_NOT_ALLOWED",
                        "message": "That method is not allowed on this endpoint."
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMIT_EXCEEDED: Honor Retry-After, use bounded exponential backoff with jitter, and reduce concurrent requests. Read X-RateLimit headers. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RATE_LIMIT_EXCEEDED": {
                    "summary": "The API key or address exceeded a rate limit.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RATE_LIMIT_EXCEEDED",
                        "message": "Too many requests. Please wait a moment and try again."
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying."
              }
            }
          },
          "500": {
            "description": "INTERNAL_ERROR: Record X-Request-Id, timestamp and sanitized request context. Reconcile unknown payment outcomes before retrying a write; contact support if it persists. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INTERNAL_ERROR": {
                    "summary": "Veyqo encountered an unexpected server error.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INTERNAL_ERROR",
                        "message": "Something went wrong on our end."
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/payments/{id}": {
      "get": {
        "operationId": "payments_show",
        "tags": [
          "Payments"
        ],
        "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.",
        "security": [
          {
            "SecretKey": []
          }
        ],
        "x-required-scope": "payments:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Use a resource ID returned by your own request. Payment endpoints also accept merchant references; URL-encode them.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful request. Inspect resource status before fulfilment.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                },
                "description": "Support correlation ID."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Payment"
                    }
                  }
                },
                "example": {
                  "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"
                  }
                }
              }
            }
          },
          "401": {
            "description": "INVALID_API_KEY: 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. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INVALID_API_KEY": {
                    "summary": "The key is absent, malformed, revoked or belongs to the wrong authentication surface.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INVALID_API_KEY",
                        "message": "That API key is not valid."
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "INSUFFICIENT_PERMISSION: Grant the required scope or use a suitably scoped key. Dashboard organization roles and staff permissions are separate. ENVIRONMENT_MISMATCH: Use the correct sandbox/live key. Resources outside the key’s project remain not-found instead of disclosing ownership. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INSUFFICIENT_PERMISSION": {
                    "summary": "The key lacks an endpoint scope, or a signed-in role lacks permission.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INSUFFICIENT_PERMISSION",
                        "message": "You do not have permission to do that."
                      }
                    }
                  },
                  "ENVIRONMENT_MISMATCH": {
                    "summary": "A known resource is in the other environment of the same project.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "ENVIRONMENT_MISMATCH",
                        "message": "That resource belongs to a different environment."
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "PAYMENT_NOT_FOUND: Use the saved Veyqo payment ID or correctly URL-encoded merchant reference with the original project’s key. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "PAYMENT_NOT_FOUND": {
                    "summary": "No visible payment matches the ID or reference.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "PAYMENT_NOT_FOUND",
                        "message": "That payment could not be found."
                      }
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: Use the method documented for the endpoint, such as POST for verification and refunds. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "METHOD_NOT_ALLOWED": {
                    "summary": "The path exists but does not accept that HTTP method.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "METHOD_NOT_ALLOWED",
                        "message": "That method is not allowed on this endpoint."
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMIT_EXCEEDED: Honor Retry-After, use bounded exponential backoff with jitter, and reduce concurrent requests. Read X-RateLimit headers. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RATE_LIMIT_EXCEEDED": {
                    "summary": "The API key or address exceeded a rate limit.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RATE_LIMIT_EXCEEDED",
                        "message": "Too many requests. Please wait a moment and try again."
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying."
              }
            }
          },
          "500": {
            "description": "INTERNAL_ERROR: Record X-Request-Id, timestamp and sanitized request context. Reconcile unknown payment outcomes before retrying a write; contact support if it persists. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INTERNAL_ERROR": {
                    "summary": "Veyqo encountered an unexpected server error.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INTERNAL_ERROR",
                        "message": "Something went wrong on our end."
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/payments/{id}/verify": {
      "post": {
        "operationId": "payments_verify",
        "tags": [
          "Payments"
        ],
        "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.",
        "security": [
          {
            "SecretKey": []
          }
        ],
        "x-required-scope": "payments:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Use a resource ID returned by your own request. Payment endpoints also accept merchant references; URL-encode them.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful request. Inspect resource status before fulfilment.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                },
                "description": "Support correlation ID."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Payment"
                    }
                  }
                },
                "example": {
                  "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"
                  }
                }
              }
            }
          },
          "401": {
            "description": "INVALID_API_KEY: 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. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INVALID_API_KEY": {
                    "summary": "The key is absent, malformed, revoked or belongs to the wrong authentication surface.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INVALID_API_KEY",
                        "message": "That API key is not valid."
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "INSUFFICIENT_PERMISSION: Grant the required scope or use a suitably scoped key. Dashboard organization roles and staff permissions are separate. ENVIRONMENT_MISMATCH: Use the correct sandbox/live key. Resources outside the key’s project remain not-found instead of disclosing ownership. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INSUFFICIENT_PERMISSION": {
                    "summary": "The key lacks an endpoint scope, or a signed-in role lacks permission.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INSUFFICIENT_PERMISSION",
                        "message": "You do not have permission to do that."
                      }
                    }
                  },
                  "ENVIRONMENT_MISMATCH": {
                    "summary": "A known resource is in the other environment of the same project.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "ENVIRONMENT_MISMATCH",
                        "message": "That resource belongs to a different environment."
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "PAYMENT_NOT_FOUND: Use the saved Veyqo payment ID or correctly URL-encoded merchant reference with the original project’s key. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "PAYMENT_NOT_FOUND": {
                    "summary": "No visible payment matches the ID or reference.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "PAYMENT_NOT_FOUND",
                        "message": "That payment could not be found."
                      }
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: Use the method documented for the endpoint, such as POST for verification and refunds. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "METHOD_NOT_ALLOWED": {
                    "summary": "The path exists but does not accept that HTTP method.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "METHOD_NOT_ALLOWED",
                        "message": "That method is not allowed on this endpoint."
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "PROVIDER_REQUEST_FAILED: Read the safe message, inspect the payment’s failure details and correct the request or provider account. Never repeatedly retry a business rejection. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "PROVIDER_REQUEST_FAILED": {
                    "summary": "The provider rejected an otherwise accepted Veyqo request.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "PROVIDER_REQUEST_FAILED",
                        "message": "The provider refused the request."
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMIT_EXCEEDED: Honor Retry-After, use bounded exponential backoff with jitter, and reduce concurrent requests. Read X-RateLimit headers. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RATE_LIMIT_EXCEEDED": {
                    "summary": "The API key or address exceeded a rate limit.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RATE_LIMIT_EXCEEDED",
                        "message": "Too many requests. Please wait a moment and try again."
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying."
              }
            }
          },
          "500": {
            "description": "INTERNAL_ERROR: Record X-Request-Id, timestamp and sanitized request context. Reconcile unknown payment outcomes before retrying a write; contact support if it persists. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INTERNAL_ERROR": {
                    "summary": "Veyqo encountered an unexpected server error.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INTERNAL_ERROR",
                        "message": "Something went wrong on our end."
                      }
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "PROVIDER_AUTHENTICATION_FAILED: The merchant must check/rotate the provider credentials in the dashboard. Do not expose those secrets to your application users. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "PROVIDER_AUTHENTICATION_FAILED": {
                    "summary": "Veyqo could not authenticate with the provider’s stored account credentials.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "PROVIDER_AUTHENTICATION_FAILED",
                        "message": "Unable to authenticate with the selected provider."
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "PROVIDER_UNAVAILABLE: Check the existing payment and verify its state before starting another attempt. Retry safe reads with backoff; preserve operation identity for retried writes. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "PROVIDER_UNAVAILABLE": {
                    "summary": "A provider timed out, was unreachable, or a checkout method is temporarily unavailable.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "PROVIDER_UNAVAILABLE",
                        "message": "The provider is not responding. Try again shortly."
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/payments/{id}/refunds": {
      "post": {
        "operationId": "refunds_create",
        "tags": [
          "Payments"
        ],
        "summary": "Refund a payment",
        "description": "Full or partial. Omit `amount` to refund everything still refundable.",
        "security": [
          {
            "SecretKey": []
          }
        ],
        "x-required-scope": "refunds:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Use a resource ID returned by your own request. Payment endpoints also accept merchant references; URL-encode them.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Persist one key per operation and reuse it unchanged on retries. Recommended for every create/refund.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateRefund"
              },
              "example": {
                "amount": 25000,
                "reason": "requested_by_customer"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful request. Inspect resource status before fulfilment.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                },
                "description": "Support correlation ID."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Refund"
                    }
                  }
                },
                "example": {
                  "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"
                  }
                }
              }
            }
          },
          "401": {
            "description": "INVALID_API_KEY: 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. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INVALID_API_KEY": {
                    "summary": "The key is absent, malformed, revoked or belongs to the wrong authentication surface.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INVALID_API_KEY",
                        "message": "That API key is not valid."
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "INSUFFICIENT_PERMISSION: Grant the required scope or use a suitably scoped key. Dashboard organization roles and staff permissions are separate. ENVIRONMENT_MISMATCH: Use the correct sandbox/live key. Resources outside the key’s project remain not-found instead of disclosing ownership. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INSUFFICIENT_PERMISSION": {
                    "summary": "The key lacks an endpoint scope, or a signed-in role lacks permission.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INSUFFICIENT_PERMISSION",
                        "message": "You do not have permission to do that."
                      }
                    }
                  },
                  "ENVIRONMENT_MISMATCH": {
                    "summary": "A known resource is in the other environment of the same project.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "ENVIRONMENT_MISMATCH",
                        "message": "That resource belongs to a different environment."
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "PAYMENT_NOT_FOUND: Use the saved Veyqo payment ID or correctly URL-encoded merchant reference with the original project’s key. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "PAYMENT_NOT_FOUND": {
                    "summary": "No visible payment matches the ID or reference.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "PAYMENT_NOT_FOUND",
                        "message": "That payment could not be found."
                      }
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: Use the method documented for the endpoint, such as POST for verification and refunds. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "METHOD_NOT_ALLOWED": {
                    "summary": "The path exists but does not accept that HTTP method.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "METHOD_NOT_ALLOWED",
                        "message": "That method is not allowed on this endpoint."
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "PAYMENT_ALREADY_REFUNDED: Read the payment and refunds, compare amount_refunded to amount, and avoid issuing a duplicate refund. IDEMPOTENCY_KEY_REUSED: Reuse the exact original request to recover that operation, or use a new key only for a genuinely different operation. IDEMPOTENCY_IN_PROGRESS: Wait briefly, retry with the same key and unchanged request, then reconcile by reference if the result remains uncertain. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "PAYMENT_ALREADY_REFUNDED": {
                    "summary": "The payment has no refundable amount remaining.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "PAYMENT_ALREADY_REFUNDED",
                        "message": "That payment has already been fully refunded."
                      }
                    }
                  },
                  "IDEMPOTENCY_KEY_REUSED": {
                    "summary": "An environment already used this key for a different method/path/body.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "IDEMPOTENCY_KEY_REUSED",
                        "message": "That idempotency key was used with a different request body."
                      }
                    }
                  },
                  "IDEMPOTENCY_IN_PROGRESS": {
                    "summary": "Another request still holds this operation key.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "IDEMPOTENCY_IN_PROGRESS",
                        "message": "A request with that idempotency key is still in progress."
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "VALIDATION_FAILED: Read error.details when present, correct the named fields and retry only after correction. Validation messages may describe state/capability errors without field details. INVALID_PROVIDER: Choose a supported connected provider. Refund/direct-checkout capabilities can differ from simple payment creation. PROVIDER_REQUEST_FAILED: Read the safe message, inspect the payment’s failure details and correct the request or provider account. Never repeatedly retry a business rejection. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "VALIDATION_FAILED": {
                    "summary": "A field, amount, URL, payment state or capability is invalid.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "VALIDATION_FAILED",
                        "message": "The given data was invalid."
                      }
                    }
                  },
                  "INVALID_PROVIDER": {
                    "summary": "The provider slug is unknown, disabled, or lacks the requested capability.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INVALID_PROVIDER",
                        "message": "That provider is not recognised."
                      }
                    }
                  },
                  "PROVIDER_REQUEST_FAILED": {
                    "summary": "The provider rejected an otherwise accepted Veyqo request.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "PROVIDER_REQUEST_FAILED",
                        "message": "The provider refused the request."
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMIT_EXCEEDED: Honor Retry-After, use bounded exponential backoff with jitter, and reduce concurrent requests. Read X-RateLimit headers. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RATE_LIMIT_EXCEEDED": {
                    "summary": "The API key or address exceeded a rate limit.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RATE_LIMIT_EXCEEDED",
                        "message": "Too many requests. Please wait a moment and try again."
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying."
              }
            }
          },
          "500": {
            "description": "INTERNAL_ERROR: Record X-Request-Id, timestamp and sanitized request context. Reconcile unknown payment outcomes before retrying a write; contact support if it persists. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INTERNAL_ERROR": {
                    "summary": "Veyqo encountered an unexpected server error.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INTERNAL_ERROR",
                        "message": "Something went wrong on our end."
                      }
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "PROVIDER_AUTHENTICATION_FAILED: The merchant must check/rotate the provider credentials in the dashboard. Do not expose those secrets to your application users. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "PROVIDER_AUTHENTICATION_FAILED": {
                    "summary": "Veyqo could not authenticate with the provider’s stored account credentials.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "PROVIDER_AUTHENTICATION_FAILED",
                        "message": "Unable to authenticate with the selected provider."
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "PROVIDER_UNAVAILABLE: Check the existing payment and verify its state before starting another attempt. Retry safe reads with backoff; preserve operation identity for retried writes. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "PROVIDER_UNAVAILABLE": {
                    "summary": "A provider timed out, was unreachable, or a checkout method is temporarily unavailable.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "PROVIDER_UNAVAILABLE",
                        "message": "The provider is not responding. Try again shortly."
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/refunds/{id}": {
      "get": {
        "operationId": "refunds_show",
        "tags": [
          "Payments"
        ],
        "summary": "Retrieve a refund",
        "description": "The refund and the payment it belongs to.",
        "security": [
          {
            "SecretKey": []
          }
        ],
        "x-required-scope": "refunds:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Use a resource ID returned by your own request. Payment endpoints also accept merchant references; URL-encode them.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful request. Inspect resource status before fulfilment.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                },
                "description": "Support correlation ID."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Refund"
                    }
                  }
                },
                "example": {
                  "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"
                  }
                }
              }
            }
          },
          "401": {
            "description": "INVALID_API_KEY: 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. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INVALID_API_KEY": {
                    "summary": "The key is absent, malformed, revoked or belongs to the wrong authentication surface.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INVALID_API_KEY",
                        "message": "That API key is not valid."
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "INSUFFICIENT_PERMISSION: Grant the required scope or use a suitably scoped key. Dashboard organization roles and staff permissions are separate. ENVIRONMENT_MISMATCH: Use the correct sandbox/live key. Resources outside the key’s project remain not-found instead of disclosing ownership. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INSUFFICIENT_PERMISSION": {
                    "summary": "The key lacks an endpoint scope, or a signed-in role lacks permission.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INSUFFICIENT_PERMISSION",
                        "message": "You do not have permission to do that."
                      }
                    }
                  },
                  "ENVIRONMENT_MISMATCH": {
                    "summary": "A known resource is in the other environment of the same project.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "ENVIRONMENT_MISMATCH",
                        "message": "That resource belongs to a different environment."
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "RESOURCE_NOT_FOUND: Check the ID, project and environment. Do not guess another project’s IDs. An inactive payment link is also not-found. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RESOURCE_NOT_FOUND": {
                    "summary": "The resource does not exist, is inactive or is not visible to this environment.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RESOURCE_NOT_FOUND",
                        "message": "We could not find what you were looking for."
                      }
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: Use the method documented for the endpoint, such as POST for verification and refunds. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "METHOD_NOT_ALLOWED": {
                    "summary": "The path exists but does not accept that HTTP method.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "METHOD_NOT_ALLOWED",
                        "message": "That method is not allowed on this endpoint."
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMIT_EXCEEDED: Honor Retry-After, use bounded exponential backoff with jitter, and reduce concurrent requests. Read X-RateLimit headers. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RATE_LIMIT_EXCEEDED": {
                    "summary": "The API key or address exceeded a rate limit.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RATE_LIMIT_EXCEEDED",
                        "message": "Too many requests. Please wait a moment and try again."
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying."
              }
            }
          },
          "500": {
            "description": "INTERNAL_ERROR: Record X-Request-Id, timestamp and sanitized request context. Reconcile unknown payment outcomes before retrying a write; contact support if it persists. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INTERNAL_ERROR": {
                    "summary": "Veyqo encountered an unexpected server error.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INTERNAL_ERROR",
                        "message": "Something went wrong on our end."
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/events": {
      "get": {
        "operationId": "events_list",
        "tags": [
          "Events"
        ],
        "summary": "List events",
        "description": "Every event Veyqo produced in this environment, newest first. Filter by `type`.",
        "security": [
          {
            "SecretKey": []
          }
        ],
        "x-required-scope": "events:read",
        "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"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful request. Inspect resource status before fulfilment.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                },
                "description": "Support correlation ID."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Event"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Pagination"
                    }
                  }
                },
                "example": {
                  "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
                  }
                }
              }
            }
          },
          "401": {
            "description": "INVALID_API_KEY: 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. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INVALID_API_KEY": {
                    "summary": "The key is absent, malformed, revoked or belongs to the wrong authentication surface.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INVALID_API_KEY",
                        "message": "That API key is not valid."
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "INSUFFICIENT_PERMISSION: Grant the required scope or use a suitably scoped key. Dashboard organization roles and staff permissions are separate. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INSUFFICIENT_PERMISSION": {
                    "summary": "The key lacks an endpoint scope, or a signed-in role lacks permission.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INSUFFICIENT_PERMISSION",
                        "message": "You do not have permission to do that."
                      }
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: Use the method documented for the endpoint, such as POST for verification and refunds. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "METHOD_NOT_ALLOWED": {
                    "summary": "The path exists but does not accept that HTTP method.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "METHOD_NOT_ALLOWED",
                        "message": "That method is not allowed on this endpoint."
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "VALIDATION_FAILED: Read error.details when present, correct the named fields and retry only after correction. Validation messages may describe state/capability errors without field details. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "VALIDATION_FAILED": {
                    "summary": "A field, amount, URL, payment state or capability is invalid.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "VALIDATION_FAILED",
                        "message": "The given data was invalid."
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMIT_EXCEEDED: Honor Retry-After, use bounded exponential backoff with jitter, and reduce concurrent requests. Read X-RateLimit headers. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RATE_LIMIT_EXCEEDED": {
                    "summary": "The API key or address exceeded a rate limit.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RATE_LIMIT_EXCEEDED",
                        "message": "Too many requests. Please wait a moment and try again."
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying."
              }
            }
          },
          "500": {
            "description": "INTERNAL_ERROR: Record X-Request-Id, timestamp and sanitized request context. Reconcile unknown payment outcomes before retrying a write; contact support if it persists. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INTERNAL_ERROR": {
                    "summary": "Veyqo encountered an unexpected server error.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INTERNAL_ERROR",
                        "message": "Something went wrong on our end."
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/events/{id}": {
      "get": {
        "operationId": "events_show",
        "tags": [
          "Events"
        ],
        "summary": "Retrieve an event",
        "description": "The normalized event, identical in shape whichever provider caused it.",
        "security": [
          {
            "SecretKey": []
          }
        ],
        "x-required-scope": "events:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Use a resource ID returned by your own request. Payment endpoints also accept merchant references; URL-encode them.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful request. Inspect resource status before fulfilment.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                },
                "description": "Support correlation ID."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Event"
                    }
                  }
                },
                "example": {
                  "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"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "INVALID_API_KEY: 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. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INVALID_API_KEY": {
                    "summary": "The key is absent, malformed, revoked or belongs to the wrong authentication surface.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INVALID_API_KEY",
                        "message": "That API key is not valid."
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "INSUFFICIENT_PERMISSION: Grant the required scope or use a suitably scoped key. Dashboard organization roles and staff permissions are separate. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INSUFFICIENT_PERMISSION": {
                    "summary": "The key lacks an endpoint scope, or a signed-in role lacks permission.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INSUFFICIENT_PERMISSION",
                        "message": "You do not have permission to do that."
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "RESOURCE_NOT_FOUND: Check the ID, project and environment. Do not guess another project’s IDs. An inactive payment link is also not-found. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RESOURCE_NOT_FOUND": {
                    "summary": "The resource does not exist, is inactive or is not visible to this environment.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RESOURCE_NOT_FOUND",
                        "message": "We could not find what you were looking for."
                      }
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: Use the method documented for the endpoint, such as POST for verification and refunds. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "METHOD_NOT_ALLOWED": {
                    "summary": "The path exists but does not accept that HTTP method.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "METHOD_NOT_ALLOWED",
                        "message": "That method is not allowed on this endpoint."
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMIT_EXCEEDED: Honor Retry-After, use bounded exponential backoff with jitter, and reduce concurrent requests. Read X-RateLimit headers. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RATE_LIMIT_EXCEEDED": {
                    "summary": "The API key or address exceeded a rate limit.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RATE_LIMIT_EXCEEDED",
                        "message": "Too many requests. Please wait a moment and try again."
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying."
              }
            }
          },
          "500": {
            "description": "INTERNAL_ERROR: Record X-Request-Id, timestamp and sanitized request context. Reconcile unknown payment outcomes before retrying a write; contact support if it persists. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INTERNAL_ERROR": {
                    "summary": "Veyqo encountered an unexpected server error.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INTERNAL_ERROR",
                        "message": "Something went wrong on our end."
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/checkout/sessions": {
      "post": {
        "operationId": "checkout_sessions_create",
        "tags": [
          "Checkout"
        ],
        "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`.",
        "security": [
          {
            "SecretKey": []
          }
        ],
        "x-required-scope": "payments:write",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Persist one key per operation and reuse it unchanged on retries. Recommended for every create/refund.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCheckoutSession"
              },
              "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"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful request. Inspect resource status before fulfilment.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                },
                "description": "Support correlation ID."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/CheckoutSession"
                    }
                  }
                },
                "example": {
                  "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"
                  }
                }
              }
            }
          },
          "401": {
            "description": "INVALID_API_KEY: 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. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INVALID_API_KEY": {
                    "summary": "The key is absent, malformed, revoked or belongs to the wrong authentication surface.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INVALID_API_KEY",
                        "message": "That API key is not valid."
                      }
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "PLAN_LIMIT_REACHED: Review the active plan, project/usage allowances and billing status with the organization owner. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "PLAN_LIMIT_REACHED": {
                    "summary": "The organization’s plan does not permit the operation or limit reached.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "PLAN_LIMIT_REACHED",
                        "message": "Your plan does not include that. Upgrade to continue."
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "INSUFFICIENT_PERMISSION: Grant the required scope or use a suitably scoped key. Dashboard organization roles and staff permissions are separate. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INSUFFICIENT_PERMISSION": {
                    "summary": "The key lacks an endpoint scope, or a signed-in role lacks permission.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INSUFFICIENT_PERMISSION",
                        "message": "You do not have permission to do that."
                      }
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: Use the method documented for the endpoint, such as POST for verification and refunds. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "METHOD_NOT_ALLOWED": {
                    "summary": "The path exists but does not accept that HTTP method.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "METHOD_NOT_ALLOWED",
                        "message": "That method is not allowed on this endpoint."
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "IDEMPOTENCY_KEY_REUSED: Reuse the exact original request to recover that operation, or use a new key only for a genuinely different operation. IDEMPOTENCY_IN_PROGRESS: Wait briefly, retry with the same key and unchanged request, then reconcile by reference if the result remains uncertain. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "IDEMPOTENCY_KEY_REUSED": {
                    "summary": "An environment already used this key for a different method/path/body.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "IDEMPOTENCY_KEY_REUSED",
                        "message": "That idempotency key was used with a different request body."
                      }
                    }
                  },
                  "IDEMPOTENCY_IN_PROGRESS": {
                    "summary": "Another request still holds this operation key.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "IDEMPOTENCY_IN_PROGRESS",
                        "message": "A request with that idempotency key is still in progress."
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "VALIDATION_FAILED: Read error.details when present, correct the named fields and retry only after correction. Validation messages may describe state/capability errors without field details. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "VALIDATION_FAILED": {
                    "summary": "A field, amount, URL, payment state or capability is invalid.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "VALIDATION_FAILED",
                        "message": "The given data was invalid."
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMIT_EXCEEDED: Honor Retry-After, use bounded exponential backoff with jitter, and reduce concurrent requests. Read X-RateLimit headers. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RATE_LIMIT_EXCEEDED": {
                    "summary": "The API key or address exceeded a rate limit.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RATE_LIMIT_EXCEEDED",
                        "message": "Too many requests. Please wait a moment and try again."
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying."
              }
            }
          },
          "500": {
            "description": "INTERNAL_ERROR: Record X-Request-Id, timestamp and sanitized request context. Reconcile unknown payment outcomes before retrying a write; contact support if it persists. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INTERNAL_ERROR": {
                    "summary": "Veyqo encountered an unexpected server error.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INTERNAL_ERROR",
                        "message": "Something went wrong on our end."
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/checkout/sessions/{id}": {
      "get": {
        "operationId": "checkout_sessions_show",
        "tags": [
          "Checkout"
        ],
        "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.",
        "security": [
          {
            "SecretKey": []
          }
        ],
        "x-required-scope": "payments:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Use a resource ID returned by your own request. Payment endpoints also accept merchant references; URL-encode them.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful request. Inspect resource status before fulfilment.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                },
                "description": "Support correlation ID."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/CheckoutSession"
                    }
                  }
                },
                "example": {
                  "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"
                  }
                }
              }
            }
          },
          "401": {
            "description": "INVALID_API_KEY: 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. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INVALID_API_KEY": {
                    "summary": "The key is absent, malformed, revoked or belongs to the wrong authentication surface.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INVALID_API_KEY",
                        "message": "That API key is not valid."
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "INSUFFICIENT_PERMISSION: Grant the required scope or use a suitably scoped key. Dashboard organization roles and staff permissions are separate. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INSUFFICIENT_PERMISSION": {
                    "summary": "The key lacks an endpoint scope, or a signed-in role lacks permission.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INSUFFICIENT_PERMISSION",
                        "message": "You do not have permission to do that."
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "RESOURCE_NOT_FOUND: Check the ID, project and environment. Do not guess another project’s IDs. An inactive payment link is also not-found. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RESOURCE_NOT_FOUND": {
                    "summary": "The resource does not exist, is inactive or is not visible to this environment.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RESOURCE_NOT_FOUND",
                        "message": "We could not find what you were looking for."
                      }
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: Use the method documented for the endpoint, such as POST for verification and refunds. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "METHOD_NOT_ALLOWED": {
                    "summary": "The path exists but does not accept that HTTP method.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "METHOD_NOT_ALLOWED",
                        "message": "That method is not allowed on this endpoint."
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMIT_EXCEEDED: Honor Retry-After, use bounded exponential backoff with jitter, and reduce concurrent requests. Read X-RateLimit headers. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RATE_LIMIT_EXCEEDED": {
                    "summary": "The API key or address exceeded a rate limit.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RATE_LIMIT_EXCEEDED",
                        "message": "Too many requests. Please wait a moment and try again."
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying."
              }
            }
          },
          "500": {
            "description": "INTERNAL_ERROR: Record X-Request-Id, timestamp and sanitized request context. Reconcile unknown payment outcomes before retrying a write; contact support if it persists. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INTERNAL_ERROR": {
                    "summary": "Veyqo encountered an unexpected server error.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INTERNAL_ERROR",
                        "message": "Something went wrong on our end."
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "PROVIDER_UNAVAILABLE: Check the existing payment and verify its state before starting another attempt. Retry safe reads with backoff; preserve operation identity for retried writes. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "PROVIDER_UNAVAILABLE": {
                    "summary": "A provider timed out, was unreachable, or a checkout method is temporarily unavailable.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "PROVIDER_UNAVAILABLE",
                        "message": "The provider is not responding. Try again shortly."
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/providers": {
      "get": {
        "operationId": "providers_list",
        "tags": [
          "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.",
        "security": [
          {
            "SecretKey": []
          }
        ],
        "x-required-scope": "payments:read",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Successful request. Inspect resource status before fulfilment.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                },
                "description": "Support correlation ID."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Provider"
                      }
                    }
                  }
                },
                "example": {
                  "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"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "INVALID_API_KEY: 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. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INVALID_API_KEY": {
                    "summary": "The key is absent, malformed, revoked or belongs to the wrong authentication surface.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INVALID_API_KEY",
                        "message": "That API key is not valid."
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "INSUFFICIENT_PERMISSION: Grant the required scope or use a suitably scoped key. Dashboard organization roles and staff permissions are separate. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INSUFFICIENT_PERMISSION": {
                    "summary": "The key lacks an endpoint scope, or a signed-in role lacks permission.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INSUFFICIENT_PERMISSION",
                        "message": "You do not have permission to do that."
                      }
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED: Use the method documented for the endpoint, such as POST for verification and refunds. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "METHOD_NOT_ALLOWED": {
                    "summary": "The path exists but does not accept that HTTP method.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "METHOD_NOT_ALLOWED",
                        "message": "That method is not allowed on this endpoint."
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMIT_EXCEEDED: Honor Retry-After, use bounded exponential backoff with jitter, and reduce concurrent requests. Read X-RateLimit headers. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RATE_LIMIT_EXCEEDED": {
                    "summary": "The API key or address exceeded a rate limit.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RATE_LIMIT_EXCEEDED",
                        "message": "Too many requests. Please wait a moment and try again."
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying."
              }
            }
          },
          "500": {
            "description": "INTERNAL_ERROR: Record X-Request-Id, timestamp and sanitized request context. Reconcile unknown payment outcomes before retrying a write; contact support if it persists. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INTERNAL_ERROR": {
                    "summary": "Veyqo encountered an unexpected server error.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INTERNAL_ERROR",
                        "message": "Something went wrong on our end."
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/checkout/v1/sessions": {
      "post": {
        "operationId": "browser_sessions_create",
        "tags": [
          "Browser checkout"
        ],
        "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.",
        "security": [
          {
            "PublishableKey": []
          },
          {
            "PublishableHeader": []
          }
        ],
        "servers": [
          {
            "url": "https://api.veyqo.org"
          }
        ],
        "x-required-scope": null,
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCheckoutSession"
              },
              "example": {
                "amount": 50000,
                "currency": "NGN",
                "reference": "ORDER-1001",
                "provider": "paystack",
                "customer": {
                  "email": "customer@example.com"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful request. Inspect resource status before fulfilment.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                },
                "description": "Support correlation ID."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/CheckoutSession"
                    }
                  }
                },
                "example": {
                  "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"
                  }
                }
              }
            }
          },
          "401": {
            "description": "INVALID_API_KEY: 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. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INVALID_API_KEY": {
                    "summary": "The key is absent, malformed, revoked or belongs to the wrong authentication surface.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INVALID_API_KEY",
                        "message": "That API key is not valid."
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "RESOURCE_NOT_FOUND: Check the ID, project and environment. Do not guess another project’s IDs. An inactive payment link is also not-found. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RESOURCE_NOT_FOUND": {
                    "summary": "The resource does not exist, is inactive or is not visible to this environment.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RESOURCE_NOT_FOUND",
                        "message": "We could not find what you were looking for."
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "VALIDATION_FAILED: Read error.details when present, correct the named fields and retry only after correction. Validation messages may describe state/capability errors without field details. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "VALIDATION_FAILED": {
                    "summary": "A field, amount, URL, payment state or capability is invalid.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "VALIDATION_FAILED",
                        "message": "The given data was invalid."
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMIT_EXCEEDED: Honor Retry-After, use bounded exponential backoff with jitter, and reduce concurrent requests. Read X-RateLimit headers. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RATE_LIMIT_EXCEEDED": {
                    "summary": "The API key or address exceeded a rate limit.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RATE_LIMIT_EXCEEDED",
                        "message": "Too many requests. Please wait a moment and try again."
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying."
              }
            }
          },
          "500": {
            "description": "INTERNAL_ERROR: Record X-Request-Id, timestamp and sanitized request context. Reconcile unknown payment outcomes before retrying a write; contact support if it persists. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INTERNAL_ERROR": {
                    "summary": "Veyqo encountered an unexpected server error.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INTERNAL_ERROR",
                        "message": "Something went wrong on our end."
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "PROVIDER_UNAVAILABLE: Check the existing payment and verify its state before starting another attempt. Retry safe reads with backoff; preserve operation identity for retried writes. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "PROVIDER_UNAVAILABLE": {
                    "summary": "A provider timed out, was unreachable, or a checkout method is temporarily unavailable.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "PROVIDER_UNAVAILABLE",
                        "message": "The provider is not responding. Try again shortly."
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/checkout/v1/sessions/{id}": {
      "get": {
        "operationId": "browser_sessions_show",
        "tags": [
          "Browser checkout"
        ],
        "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.",
        "security": [],
        "servers": [
          {
            "url": "https://api.veyqo.org"
          }
        ],
        "x-required-scope": null,
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Use a resource ID returned by your own request. Payment endpoints also accept merchant references; URL-encode them.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful request. Inspect resource status before fulfilment.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                },
                "description": "Support correlation ID."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/BrowserSession"
                    }
                  }
                },
                "example": {
                  "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
                  }
                }
              }
            }
          },
          "404": {
            "description": "RESOURCE_NOT_FOUND: Check the ID, project and environment. Do not guess another project’s IDs. An inactive payment link is also not-found. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RESOURCE_NOT_FOUND": {
                    "summary": "The resource does not exist, is inactive or is not visible to this environment.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RESOURCE_NOT_FOUND",
                        "message": "We could not find what you were looking for."
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "VALIDATION_FAILED: Read error.details when present, correct the named fields and retry only after correction. Validation messages may describe state/capability errors without field details. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "VALIDATION_FAILED": {
                    "summary": "A field, amount, URL, payment state or capability is invalid.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "VALIDATION_FAILED",
                        "message": "The given data was invalid."
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMIT_EXCEEDED: Honor Retry-After, use bounded exponential backoff with jitter, and reduce concurrent requests. Read X-RateLimit headers. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RATE_LIMIT_EXCEEDED": {
                    "summary": "The API key or address exceeded a rate limit.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RATE_LIMIT_EXCEEDED",
                        "message": "Too many requests. Please wait a moment and try again."
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying."
              }
            }
          },
          "500": {
            "description": "INTERNAL_ERROR: Record X-Request-Id, timestamp and sanitized request context. Reconcile unknown payment outcomes before retrying a write; contact support if it persists. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INTERNAL_ERROR": {
                    "summary": "Veyqo encountered an unexpected server error.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INTERNAL_ERROR",
                        "message": "Something went wrong on our end."
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "PROVIDER_UNAVAILABLE: Check the existing payment and verify its state before starting another attempt. Retry safe reads with backoff; preserve operation identity for retried writes. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "PROVIDER_UNAVAILABLE": {
                    "summary": "A provider timed out, was unreachable, or a checkout method is temporarily unavailable.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "PROVIDER_UNAVAILABLE",
                        "message": "The provider is not responding. Try again shortly."
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/checkout/v1/sessions/{id}/charge": {
      "post": {
        "operationId": "browser_sessions_charge",
        "tags": [
          "Browser checkout"
        ],
        "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.",
        "security": [],
        "servers": [
          {
            "url": "https://api.veyqo.org"
          }
        ],
        "x-required-scope": null,
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Use a resource ID returned by your own request. Payment endpoints also accept merchant references; URL-encode them.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BrowserCharge"
              },
              "example": {
                "method": "bank_transfer",
                "email": "customer@example.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful request. Inspect resource status before fulfilment.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                },
                "description": "Support correlation ID."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/BrowserSession"
                    }
                  }
                },
                "example": {
                  "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
                  }
                }
              }
            }
          },
          "404": {
            "description": "RESOURCE_NOT_FOUND: Check the ID, project and environment. Do not guess another project’s IDs. An inactive payment link is also not-found. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RESOURCE_NOT_FOUND": {
                    "summary": "The resource does not exist, is inactive or is not visible to this environment.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RESOURCE_NOT_FOUND",
                        "message": "We could not find what you were looking for."
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "VALIDATION_FAILED: Read error.details when present, correct the named fields and retry only after correction. Validation messages may describe state/capability errors without field details. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "VALIDATION_FAILED": {
                    "summary": "A field, amount, URL, payment state or capability is invalid.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "VALIDATION_FAILED",
                        "message": "The given data was invalid."
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMIT_EXCEEDED: Honor Retry-After, use bounded exponential backoff with jitter, and reduce concurrent requests. Read X-RateLimit headers. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RATE_LIMIT_EXCEEDED": {
                    "summary": "The API key or address exceeded a rate limit.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RATE_LIMIT_EXCEEDED",
                        "message": "Too many requests. Please wait a moment and try again."
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying."
              }
            }
          },
          "500": {
            "description": "INTERNAL_ERROR: Record X-Request-Id, timestamp and sanitized request context. Reconcile unknown payment outcomes before retrying a write; contact support if it persists. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INTERNAL_ERROR": {
                    "summary": "Veyqo encountered an unexpected server error.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INTERNAL_ERROR",
                        "message": "Something went wrong on our end."
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "PROVIDER_UNAVAILABLE: Check the existing payment and verify its state before starting another attempt. Retry safe reads with backoff; preserve operation identity for retried writes. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "PROVIDER_UNAVAILABLE": {
                    "summary": "A provider timed out, was unreachable, or a checkout method is temporarily unavailable.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "PROVIDER_UNAVAILABLE",
                        "message": "The provider is not responding. Try again shortly."
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/checkout/v1/sessions/{id}/otp": {
      "post": {
        "operationId": "browser_sessions_otp",
        "tags": [
          "Browser checkout"
        ],
        "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.",
        "security": [],
        "servers": [
          {
            "url": "https://api.veyqo.org"
          }
        ],
        "x-required-scope": null,
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Use a resource ID returned by your own request. Payment endpoints also accept merchant references; URL-encode them.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BrowserOtp"
              },
              "example": {
                "otp": "123456"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful request. Inspect resource status before fulfilment.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                },
                "description": "Support correlation ID."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/BrowserSession"
                    }
                  }
                },
                "example": {
                  "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
                  }
                }
              }
            }
          },
          "404": {
            "description": "RESOURCE_NOT_FOUND: Check the ID, project and environment. Do not guess another project’s IDs. An inactive payment link is also not-found. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RESOURCE_NOT_FOUND": {
                    "summary": "The resource does not exist, is inactive or is not visible to this environment.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RESOURCE_NOT_FOUND",
                        "message": "We could not find what you were looking for."
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "VALIDATION_FAILED: Read error.details when present, correct the named fields and retry only after correction. Validation messages may describe state/capability errors without field details. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "VALIDATION_FAILED": {
                    "summary": "A field, amount, URL, payment state or capability is invalid.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "VALIDATION_FAILED",
                        "message": "The given data was invalid."
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMIT_EXCEEDED: Honor Retry-After, use bounded exponential backoff with jitter, and reduce concurrent requests. Read X-RateLimit headers. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RATE_LIMIT_EXCEEDED": {
                    "summary": "The API key or address exceeded a rate limit.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RATE_LIMIT_EXCEEDED",
                        "message": "Too many requests. Please wait a moment and try again."
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying."
              }
            }
          },
          "500": {
            "description": "INTERNAL_ERROR: Record X-Request-Id, timestamp and sanitized request context. Reconcile unknown payment outcomes before retrying a write; contact support if it persists. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INTERNAL_ERROR": {
                    "summary": "Veyqo encountered an unexpected server error.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INTERNAL_ERROR",
                        "message": "Something went wrong on our end."
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "PROVIDER_UNAVAILABLE: Check the existing payment and verify its state before starting another attempt. Retry safe reads with backoff; preserve operation identity for retried writes. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "PROVIDER_UNAVAILABLE": {
                    "summary": "A provider timed out, was unreachable, or a checkout method is temporarily unavailable.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "PROVIDER_UNAVAILABLE",
                        "message": "The provider is not responding. Try again shortly."
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/checkout/v1/links/{id}": {
      "get": {
        "operationId": "browser_links_show",
        "tags": [
          "Browser checkout"
        ],
        "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.",
        "security": [],
        "servers": [
          {
            "url": "https://api.veyqo.org"
          }
        ],
        "x-required-scope": null,
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Use a resource ID returned by your own request. Payment endpoints also accept merchant references; URL-encode them.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful request. Inspect resource status before fulfilment.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                },
                "description": "Support correlation ID."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/PaymentLink"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "plink_01M6EB66SC61Q3RQYAN0693DGM",
                    "object": "payment_link",
                    "title": "Order 1001",
                    "description": null,
                    "amount": 50000,
                    "currency": "NGN",
                    "merchant": {
                      "name": "Example Store"
                    },
                    "sandbox": true
                  }
                }
              }
            }
          },
          "404": {
            "description": "RESOURCE_NOT_FOUND: Check the ID, project and environment. Do not guess another project’s IDs. An inactive payment link is also not-found. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RESOURCE_NOT_FOUND": {
                    "summary": "The resource does not exist, is inactive or is not visible to this environment.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RESOURCE_NOT_FOUND",
                        "message": "We could not find what you were looking for."
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "VALIDATION_FAILED: Read error.details when present, correct the named fields and retry only after correction. Validation messages may describe state/capability errors without field details. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "VALIDATION_FAILED": {
                    "summary": "A field, amount, URL, payment state or capability is invalid.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "VALIDATION_FAILED",
                        "message": "The given data was invalid."
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMIT_EXCEEDED: Honor Retry-After, use bounded exponential backoff with jitter, and reduce concurrent requests. Read X-RateLimit headers. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RATE_LIMIT_EXCEEDED": {
                    "summary": "The API key or address exceeded a rate limit.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RATE_LIMIT_EXCEEDED",
                        "message": "Too many requests. Please wait a moment and try again."
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying."
              }
            }
          },
          "500": {
            "description": "INTERNAL_ERROR: Record X-Request-Id, timestamp and sanitized request context. Reconcile unknown payment outcomes before retrying a write; contact support if it persists. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INTERNAL_ERROR": {
                    "summary": "Veyqo encountered an unexpected server error.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INTERNAL_ERROR",
                        "message": "Something went wrong on our end."
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "PROVIDER_UNAVAILABLE: Check the existing payment and verify its state before starting another attempt. Retry safe reads with backoff; preserve operation identity for retried writes. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "PROVIDER_UNAVAILABLE": {
                    "summary": "A provider timed out, was unreachable, or a checkout method is temporarily unavailable.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "PROVIDER_UNAVAILABLE",
                        "message": "The provider is not responding. Try again shortly."
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/checkout/v1/links/{id}/sessions": {
      "post": {
        "operationId": "browser_links_sessions",
        "tags": [
          "Browser checkout"
        ],
        "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.",
        "security": [],
        "servers": [
          {
            "url": "https://api.veyqo.org"
          }
        ],
        "x-required-scope": null,
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Use a resource ID returned by your own request. Payment endpoints also accept merchant references; URL-encode them.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LinkCustomer"
              },
              "example": {
                "email": "customer@example.com"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful request. Inspect resource status before fulfilment.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                },
                "description": "Support correlation ID."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/CheckoutSession"
                    }
                  }
                },
                "example": {
                  "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"
                  }
                }
              }
            }
          },
          "404": {
            "description": "RESOURCE_NOT_FOUND: Check the ID, project and environment. Do not guess another project’s IDs. An inactive payment link is also not-found. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RESOURCE_NOT_FOUND": {
                    "summary": "The resource does not exist, is inactive or is not visible to this environment.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RESOURCE_NOT_FOUND",
                        "message": "We could not find what you were looking for."
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "VALIDATION_FAILED: Read error.details when present, correct the named fields and retry only after correction. Validation messages may describe state/capability errors without field details. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "VALIDATION_FAILED": {
                    "summary": "A field, amount, URL, payment state or capability is invalid.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "VALIDATION_FAILED",
                        "message": "The given data was invalid."
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMIT_EXCEEDED: Honor Retry-After, use bounded exponential backoff with jitter, and reduce concurrent requests. Read X-RateLimit headers. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "RATE_LIMIT_EXCEEDED": {
                    "summary": "The API key or address exceeded a rate limit.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "RATE_LIMIT_EXCEEDED",
                        "message": "Too many requests. Please wait a moment and try again."
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying."
              }
            }
          },
          "500": {
            "description": "INTERNAL_ERROR: Record X-Request-Id, timestamp and sanitized request context. Reconcile unknown payment outcomes before retrying a write; contact support if it persists. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "INTERNAL_ERROR": {
                    "summary": "Veyqo encountered an unexpected server error.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "INTERNAL_ERROR",
                        "message": "Something went wrong on our end."
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "PROVIDER_UNAVAILABLE: Check the existing payment and verify its state before starting another attempt. Retry safe reads with backoff; preserve operation identity for retried writes. ",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "PROVIDER_UNAVAILABLE": {
                    "summary": "A provider timed out, was unreachable, or a checkout method is temporarily unavailable.",
                    "value": {
                      "success": false,
                      "error": {
                        "code": "PROVIDER_UNAVAILABLE",
                        "message": "The provider is not responding. Try again shortly."
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "SecretKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Server-only kc_test_ or kc_live_ Veyqo API key."
      },
      "PublishableKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Browser-only Veyqo pk_test_ or pk_live_ publishable key."
      },
      "PublishableHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Veyqo-Key",
        "description": "Alternative publishable-key header for browser session creation."
      }
    },
    "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
        }
      }
    }
  }
}
