{
  "openapi": "3.0.0",
  "paths": {
    "/v1/balance": {
      "get": {
        "operationId": "getBalance",
        "summary": "Get platform balance breakdown",
        "description": "Returns tenant ledger totals plus seller obligations (pending + available) and platformAvailableVes.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlatformBalanceDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Balance"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/webhooks": {
      "post": {
        "operationId": "createWebhook",
        "summary": "Register a webhook endpoint",
        "description": "The signing secret is returned only on creation. Delivery currently uses one attempt with a 10-second timeout.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWebhookDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      },
      "get": {
        "operationId": "listWebhooks",
        "summary": "List webhook endpoints",
        "description": "Signing secrets are never included.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookEndpointDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/webhooks/{id}": {
      "patch": {
        "operationId": "updateWebhook",
        "summary": "Update a webhook endpoint",
        "description": "Update url, subscribed events, and/or active status. Providing events replaces the full subscription list. The signing secret cannot be changed.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWebhookDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointDto"
                }
              }
            }
          },
          "400": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      },
      "delete": {
        "operationId": "deleteWebhook",
        "summary": "Delete a webhook endpoint and its delivery history",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteWebhookResponseDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/payouts": {
      "post": {
        "operationId": "create",
        "summary": "Create a simple merchant payout",
        "description": "Credits a verified merchant Pago Móvil method with an exact VES `monto`. `externalRef` is the idempotency key (same payload → 200 replay; conflicting payload → 409 `external_ref_conflict`). Requires an active merchant and a verified payout method.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePayoutDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Idempotent replay of an existing payout with the same externalRef and payload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutResponseDto"
                }
              }
            }
          },
          "201": {
            "description": "Payout created (new externalRef).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "409": {
            "description": "external_ref_conflict, merchant_inactive, or related business conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Payouts"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      },
      "get": {
        "operationId": "list",
        "summary": "List payouts",
        "description": "Cursor-paginated list (`items`, `nextCursor`). Newest-first within the page. Use `status` to filter pending settlements.",
        "parameters": [
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Optional status filter.",
            "schema": {
              "enum": [
                "pending",
                "completed",
                "failed"
              ],
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "required": false,
            "in": "query",
            "description": "Opaque cursor from a previous `nextCursor`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "Page size 1–100 (default 25).",
            "schema": {
              "example": 25,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutListResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Payouts"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/payouts/instant": {
      "post": {
        "operationId": "createInstant",
        "summary": "Instant crédito to the verified tenant payout account",
        "description": "Credits the tenant’s verified Pago Móvil account (see GET /v1/tenant/payout-account). Requires a verified account that is eligible (first verify is immediate; destination changes require a completed 1 business-day cooling period). `monto` is the gross VES withdrawn from available balance; the bank receives monto minus feePercent. Uses ProviderRegistry (R4 preferred).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateInstantPayoutDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Idempotent replay of an existing instant credit with the same externalRef and payload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutResponseDto"
                }
              }
            }
          },
          "201": {
            "description": "Instant credit created (new externalRef).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "409": {
            "description": "external_ref_conflict when the same key is reused with a different payload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Payouts"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/payouts/batch": {
      "post": {
        "operationId": "createBatch",
        "summary": "Create a split payout batch (per-item results)",
        "description": "Creates or replays a batch keyed by batch-level `externalRef`. Each item is processed independently; failures are returned inline with status `failed` and do not abort siblings. Item-level `externalRef` values remain individually idempotent.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePayoutBatchDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Idempotent replay of an existing batch with the same payload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutBatchResponseDto"
                }
              }
            }
          },
          "201": {
            "description": "New batch processed (may include mixed completed/pending/failed items).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutBatchResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "409": {
            "description": "Batch external_ref_conflict when the same batch key is reused with a different payload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Payouts"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/payouts/by-ref/{externalRef}": {
      "get": {
        "operationId": "getByRef",
        "summary": "Get payout details by externalRef",
        "description": "Lookup by the tenant-supplied idempotency / correlation key.",
        "parameters": [
          {
            "name": "externalRef",
            "required": true,
            "in": "path",
            "schema": {
              "example": "po_9c21",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "No payout with that externalRef for this tenant.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Payouts"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/payouts/{id}": {
      "get": {
        "operationId": "getById",
        "summary": "Get payout details and status by id",
        "description": "Use to poll pending payouts until status becomes completed or failed.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Payouts"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/tenant/payout-account": {
      "get": {
        "operationId": "get",
        "summary": "Get the tenant instant-credit payout account",
        "description": "Returns the single Pago Móvil destination used for POST /v1/payouts/instant, including eligibility (`pending_verification` | `verifying` | `cooling` | `eligible` | …). When none is configured yet, returns JSON `null` (HTTP 200) — create one with PUT/POST.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Configured account, or `null` when not set up yet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantPayoutAccountResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Tenant payout account"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      },
      "put": {
        "operationId": "upsert",
        "summary": "Create or update the tenant payout account",
        "description": "Upserts cédula/RIF + phone + bank. Changing any destination field clears verification; the next successful verify applies a 1 business-day cooling period (first-time verify unlocks immediately).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpsertTenantPayoutAccountDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantPayoutAccountResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Tenant payout account"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      },
      "post": {
        "operationId": "upsertPost",
        "summary": "Create or update the tenant payout account (POST alias)",
        "description": "Same as PUT /v1/tenant/payout-account — provided so create flows can use POST.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpsertTenantPayoutAccountDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantPayoutAccountResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Tenant payout account"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/tenant/payout-account/verify/start": {
      "post": {
        "operationId": "startVerify",
        "summary": "Start micro-deposit verification for the tenant payout account",
        "description": "Sends two secret 0.XX crédito inmediato deposits (same pattern as merchant verify). Confirm with POST /v1/tenant/payout-account/verify.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantPayoutAccountVerifyStartResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "409": {
            "description": "already_verified or locked.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "credit_rejected or payout_account_missing (save an account first).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Tenant payout account"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/tenant/payout-account/verify": {
      "post": {
        "operationId": "confirmVerify",
        "summary": "Confirm micro-deposit amounts",
        "description": "On success the account becomes verified. First-time verify is immediately eligible; re-verify after a destination change enters a 1 business-day cooling period (`payoutEligibleAt`).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConfirmTenantPayoutAccountVerifyDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantPayoutAccountVerifyConfirmResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "409": {
            "description": "amounts_mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "410": {
            "description": "window_expired.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "payout_account_missing or not_ready.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Tenant payout account"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/payments/debit/otp": {
      "post": {
        "operationId": "generarOtp",
        "summary": "Send a debit authorization code to the customer",
        "description": "Asks the payer bank to SMS an OTP for débito inmediato. Amounts are in VES. On success the response `code` is typically `202`. Collect the OTP from your customer, then call POST /v1/payments/debit with the same payer fields. Test-mode tenants use a simulated débito (R4 has no bank sandbox) — use the rotating code from Portal → Sandbox.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateDebitOtpDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OTP request accepted by the payer bank (typically code `202`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DebitOtpResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation or business-rule failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "The banking network rejected the operation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "Advanced payments require the R4 provider to be configured for this environment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Advanced payments"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/payments/debit": {
      "post": {
        "operationId": "debitoInmediato",
        "summary": "Execute an immediate debit",
        "description": "Charges the payer after they provide the bank OTP. `ACCP` = accepted (payment.completed webhook). `AC00` = pending — the gateway polls ConsultarOperaciones until ACCP or a reject code, then fires payment.completed or payment.failed. Optional `externalRef` is stored for recovery via GET /v1/payments/by-ref/:externalRef (correlation only — not idempotent). Response always includes `paymentId` for the DEBITO_INMEDIATO payment record. Test-mode tenants simulate débito (R4 has no sandbox). VPOS always uses BNC; for BNC sandbox credentials see Portal → Sandbox.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImmediateDebitDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Network payload plus VEXPay `paymentId` (and `externalRef` when sent).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImmediateDebitResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation or business-rule failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "The banking network rejected the operation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "Advanced payments require the R4 provider to be configured for this environment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Advanced payments"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/payments/operations/{id}": {
      "get": {
        "operationId": "consultarOperacion",
        "summary": "Poll a pending payment operation",
        "description": "Manual ConsultarOperaciones lookup. Prefer relying on gateway auto-poll + webhooks for AC00 débito/crédito. When a PENDING payment transitions, the same payment.* webhooks fire (idempotent). Persist `id`/`Id` from execute responses.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Network operation id from a prior debit/credit response (`id` or `Id`).",
            "schema": {
              "example": "6785d97e-2092-49f0-9f7d-3d5921f0b13f",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current network status for the operation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/R4OperationResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation or business-rule failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "The banking network rejected the operation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "Advanced payments require the R4 provider to be configured for this environment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Advanced payments"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/payments/operations/poll": {
      "post": {
        "operationId": "pollOperation",
        "summary": "Manually poll a pending débito, payout, or verification deposit",
        "description": "Forces one ConsultarOperaciones cycle for a tenant-owned entity. Same settlement path as the gateway minute cron (webhooks fire when status changes). Prefer auto-poll in production.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManualOperationPollDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualOperationPollResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation or business-rule failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Entity not found for this tenant, or missing operation id."
          },
          "422": {
            "description": "The banking network rejected the operation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "Advanced payments require the R4 provider to be configured for this environment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Advanced payments"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/payments/credit": {
      "post": {
        "operationId": "creditoInmediato",
        "summary": "Execute an immediate credit by phone",
        "description": "Credits a beneficiary Pago Móvil destination (banco + cedula + telefono) for a VES `monto`. Response may be `ACCP` or pending `AC00` (auto-polled).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImmediateCreditDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/R4OperationResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation or business-rule failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "The banking network rejected the operation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "Advanced payments require the R4 provider to be configured for this environment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Advanced payments"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/payments/credit/account": {
      "post": {
        "operationId": "creditoCuentas",
        "summary": "Execute a credit to a bank account",
        "description": "Credits a 20-digit Venezuelan account (`cuenta`) for a VES `monto`. Response may be `ACCP` or pending `AC00`.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AccountCreditDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/R4OperationResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation or business-rule failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "The banking network rejected the operation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "Advanced payments require the R4 provider to be configured for this environment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Advanced payments"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/payments/credit/disburse": {
      "post": {
        "operationId": "dispersarCredito",
        "summary": "Disburse credits by phone",
        "description": "Splits a completed inbound PAGO_MOVIL payment (matched by `referencia`) across multiple phone recipients. `monto` must match that payment’s vesAmount; sum of `personas[].montoPart` must equal `monto`. Each recipient is credited via CreditoInmediato. Returns 404 if no matching completed payment; 409 if already dispersed.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreditDisbursementDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreditDisbursementResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation or business-rule failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "No completed PAGO_MOVIL payment found for the given referencia.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "409": {
            "description": "The matched payment was already dispersed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "The banking network rejected the operation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "Advanced payments require the R4 provider to be configured for this environment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Advanced payments"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/payments/payouts": {
      "post": {
        "operationId": "dispersarPagos",
        "summary": "Disburse payments to bank accounts",
        "description": "Account-based multi-beneficiary dispersion (R4pagos). Distinct from merchant payouts at POST /v1/payouts. `fecha` is MM/DD/YYYY; only the last 9 digits of `referencia` are sent to the bank. Sum of `personas[].montoPart` must equal `monto`.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PayoutDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountPayoutDispersionResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation or business-rule failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "The banking network rejected the operation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "Advanced payments require the R4 provider to be configured for this environment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Advanced payments"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/payments/change": {
      "post": {
        "operationId": "ejecutarVuelto",
        "summary": "Send change to a customer",
        "description": "Sends a small VES “vuelto” (change) to the customer’s Pago Móvil destination after a purchase.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChangePaymentDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChangePaymentResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation or business-rule failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "The banking network rejected the operation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "Advanced payments require the R4 provider to be configured for this environment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Advanced payments"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/banks": {
      "get": {
        "operationId": "getBanks",
        "summary": "List supported banks (with logos)",
        "description": "Returns the listed Venezuelan bank catalog: SIMF `code`, `name`, `services`, and `logoUrl`. `logoUrl` is a public 100×100 PNG when available (otherwise null) — use it in bank selectors so customers can recognize their bank. Hidden/unlisted banks are omitted. Prefer this endpoint over hard-coded bank lists.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/BankResponseDto"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or unsupported operation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Payments",
          "Banks"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/quote": {
      "get": {
        "operationId": "getQuote",
        "summary": "Quote a USD amount in VES at the current BCV rate",
        "description": "Returns the authoritative VEX FX BCV rate (bcvRate/vesAmount) used for payment settlement, plus medianRate/medianVesAmount from available BCV sources (VEX FX and bank when configured — R4 MBbcv preferred, BNC BCVRates fallback).",
        "parameters": [
          {
            "name": "usdAmount",
            "required": true,
            "in": "query",
            "description": "Positive USD amount to convert. Must be a finite number greater than zero.",
            "schema": {
              "example": 25,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "bcvRate/vesAmount are authoritative for settlement; medianRate/medianVesAmount are for display. sources includes per-source rates or errors.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuoteResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or unsupported operation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Payments"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/payments/c2p/request": {
      "post": {
        "operationId": "requestC2p",
        "summary": "Create a pending C2P payment intent and request bank OTP when supported",
        "description": "Creates a PENDING intent. When externalRef is provided, any other PENDING C2P intent for the same tenant + externalRef is canceled (superseded) and payment.canceled is fired. Pending C2P intents expire after 15 minutes. For R4, also calls GenerarOtp so the payer bank SMS’s a token to the customer (`otpRequested: true`). Collect that token, then execute with POST /v1/payments/c2p.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/C2pRequestDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/C2pIntentResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or unsupported operation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Payments"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/payments/c2p": {
      "post": {
        "operationId": "executeC2p",
        "summary": "Execute a C2P charge",
        "description": "Charges the customer with the bank-issued token. Prefer including `intentId` from POST /v1/payments/c2p/request. Returns a PaymentReceiptDto; subscribe to payment.completed / payment.failed for async confirmation when applicable. `externalRef` is correlation only — not idempotent.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/C2pPaymentDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Payment receipt (status PENDING or COMPLETED).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentReceiptDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or unsupported operation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "The supplied intent does not exist or is no longer pending.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "The provider rejected the charge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Payments"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/payments/vpos": {
      "post": {
        "operationId": "executeVpos",
        "summary": "Execute a VPOS card charge",
        "description": "BNC only. Submit PAN/CVV only from a PCI-compliant server environment. Pass usdAmount (VES derived at BCV) or vesAmount (locks the bolívar charge; USD derived). Returns PaymentReceiptDto with optional cardLast4 / cardBrand. Never log full card data. Carding defense: if the same cardHolderId (debtorId) has had 3 distinct cards FAILED on VPOS within 30 minutes, further attempts are blocked (429, code CARD_VELOCITY_BLOCKED) without contacting the bank until the window rolls off.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VposPaymentDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentReceiptDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or unsupported operation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "The provider rejected the charge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Carding defense tripped: 3 distinct cards already failed for this payer in the last 30 minutes.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Payments"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/payments/pago-movil/verify": {
      "post": {
        "operationId": "verifyPagoMovil",
        "summary": "Verify a customer-originated Pago Móvil transfer",
        "description": "Matches a customer-supplied bank `reference` (and optional `dateMovement` YYYY-MM-DD) against bank movements for the quoted USD amount. Returns PaymentReceiptDto when found. Routed by the tenant's active provider — BNC queries the bank live; R4 confirms against the R4notifica inbound webhook already received for that reference.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PagoMovilVerifyDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentReceiptDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or unsupported operation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Payments"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/payments/by-ref/{externalRef}": {
      "get": {
        "operationId": "getPaymentByRef",
        "summary": "Find the latest payment with an external reference",
        "description": "externalRef is not unique and does not prevent duplicate payments.",
        "parameters": [
          {
            "name": "externalRef",
            "required": true,
            "in": "path",
            "schema": {
              "example": "order-1042",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentReceiptDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or unsupported operation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Payments"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/payments/{id}": {
      "get": {
        "operationId": "getPayment",
        "summary": "Get a payment by ID",
        "description": "Returns the full PaymentReceiptDto for any method (C2P, VPOS, PAGO_MOVIL, DEBITO_INMEDIATO).",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentReceiptDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or unsupported operation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Payments"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/payments/{id}/reverse": {
      "post": {
        "operationId": "reversePayment",
        "summary": "Reverse a completed C2P payment",
        "description": "Reversal is supported for C2P payments only.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentReceiptDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or unsupported operation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Payments"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/merchants": {
      "post": {
        "operationId": "create",
        "summary": "Register a merchant (optionally with an initial Pago Móvil payout method)",
        "description": "Provide bankCode + phone together to create the first payout method, or omit both to create a merchant shell. `externalRef` is the idempotency key (same payload → 200 replay; conflicting payload → 409 `external_ref_conflict`). Responses with an empty payoutMethods[] include `message` explaining that no payout method exists yet — add one via POST /v1/merchants/:id/payout-methods before verify or payout.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateMerchantDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Idempotent replay or shell update / method attach for an existing externalRef.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MerchantResponseDto"
                }
              }
            }
          },
          "201": {
            "description": "Merchant created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MerchantResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "409": {
            "description": "external_ref_conflict when the same key is reused with a different payload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Merchants"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      },
      "get": {
        "operationId": "listOrGetByRef",
        "summary": "List merchants or lookup by externalRef",
        "description": "Without query params, returns a paginated list (`items`, `nextCursor`). Pass `externalRef` for a single-merchant lookup. Optional filters: `status`, `isActive` (true|false), `cursor`, `limit` (1–100, default 25). For payout pickers use `status=verified&isActive=true`. Each merchant includes `payoutMethods[]`; top-level `bankCode`/`destination` mirror the default method.",
        "parameters": [
          {
            "name": "externalRef",
            "required": false,
            "in": "query",
            "description": "When set, returns a single MerchantResponseDto instead of the paginated list.",
            "schema": {
              "example": "usr_7f3a",
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by mirrored default-method status.",
            "schema": {
              "enum": [
                "pending_verification",
                "verifying",
                "verified",
                "rejected"
              ],
              "type": "string"
            }
          },
          {
            "name": "isActive",
            "required": false,
            "in": "query",
            "description": "Filter by active flag.",
            "schema": {
              "enum": [
                "true",
                "false"
              ],
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "required": false,
            "in": "query",
            "description": "Opaque cursor from a previous `nextCursor`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "Page size 1–100 (default 25). Ignored when externalRef is set.",
            "schema": {
              "example": 25,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated MerchantListResponseDto by default, or a single MerchantResponseDto when `externalRef` is provided.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/MerchantListResponseDto"
                    },
                    {
                      "$ref": "#/components/schemas/MerchantResponseDto"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Returned when externalRef is set and no merchant matches.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Merchants"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/merchants/{id}/payout-methods": {
      "get": {
        "operationId": "listPayoutMethods",
        "summary": "List payout methods for a merchant",
        "description": "Returns every Pago Móvil destination (`items[]`) with status, isDefault, and masked destination. Prefer this over reading only top-level merchant bankCode/destination.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Merchant id.",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutMethodListResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Merchants"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      },
      "post": {
        "operationId": "addPayoutMethod",
        "summary": "Add a Pago Móvil payout method to a merchant",
        "description": "Registers another bankCode + phone. The first method created with the merchant is default; additional methods start as non-default and pending_verification until micro-deposit confirm.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePayoutMethodDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutMethodResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Merchants"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/merchants/{id}/payout-methods/{methodId}/default": {
      "post": {
        "operationId": "setDefaultPayoutMethod",
        "summary": "Set a payout method as the merchant default",
        "description": "Clears isDefault on other methods. Top-level merchant bankCode/destination mirror this method. Payouts without payoutMethodId prefer the default verified method.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "methodId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutMethodResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Merchants"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/merchants/{id}/payout-methods/{methodId}": {
      "delete": {
        "operationId": "deletePayoutMethod",
        "summary": "Delete a payout method",
        "description": "Removes a Pago Móvil destination. If it was the default, another method is promoted (verified preferred). Historical payouts keep bank/phone snapshots; their payoutMethodId is cleared.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "methodId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Payout method deleted."
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Merchants"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/merchants/{id}/payout-methods/{methodId}/verify/start": {
      "post": {
        "operationId": "startVerifyMethod",
        "summary": "Start micro-deposit verification for a payout method",
        "description": "Sends two secret 0.XX micro-deposits to that method’s Pago Móvil destination. Amounts are never returned in the API response, logs, or webhooks. Ask the merchant what they received, then confirm with POST …/verify within 2 days.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "methodId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Verification session started; amounts are intentionally omitted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerifyStartResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "409": {
            "description": "Verification locked or already in progress.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Merchants"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/merchants/{id}/payout-methods/{methodId}/verify": {
      "post": {
        "operationId": "confirmVerifyMethod",
        "summary": "Confirm micro-deposit amounts for a payout method",
        "description": "Submit the two exact 0.XX amounts the merchant received (order-insensitive). On success the method becomes verified and can be selected via payoutMethodId on POST /v1/payouts.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "methodId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConfirmMerchantVerifyDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerifyConfirmResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "409": {
            "description": "Wrong amounts, locked, or no active verification session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Merchants"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/merchants/{id}/balance": {
      "get": {
        "operationId": "getBalance",
        "summary": "Get seller pending/available balance",
        "description": "Returns Connect-style pendingVes and availableVes for the merchant under this platform tenant.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MerchantBalanceDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Merchants"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/merchants/{id}/transfers": {
      "post": {
        "operationId": "transfer",
        "summary": "Transfer platform float to seller pending balance",
        "description": "Debits tenant available (SELLER_TRANSFER) and credits merchant pending. When sellerHoldBusinessDays is 0, funds release to available immediately.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateMerchantTransferDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MerchantBalanceDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Merchants"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/merchants/{id}": {
      "get": {
        "operationId": "getById",
        "summary": "Get merchant details, payout methods, and verification status",
        "description": "Includes payoutMethods[] and top-level bankCode/destination mirrors of the default method.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MerchantResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Merchants"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      },
      "patch": {
        "operationId": "update",
        "summary": "Update merchant flags (active / auto-payout)",
        "description": "Soft off-switch for payouts and optional autoPayoutEnabled for cron payouts from available balance.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMerchantDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MerchantResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Merchants"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      },
      "delete": {
        "operationId": "remove",
        "summary": "Delete a merchant",
        "description": "Hard-deletes the merchant and its payout methods when there is no payout history. Frees externalRef for re-registration. Returns 409 merchant_has_payouts (with payoutCount) if payouts exist — use PATCH isActive:false instead.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteMerchantResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Merchant not found for this tenant.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "409": {
            "description": "merchant_has_payouts — merchant has payout history; deactivate instead.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Merchants"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/merchants/{id}/audit-events": {
      "get": {
        "operationId": "listAuditEvents",
        "summary": "Merchant compliance / lifecycle audit trail",
        "description": "Append-only events (MERCHANT_CREATED, RIF_SUBMITTED, MERCHANT_ACTIVATED, CAPABILITY_ENABLED, MERCHANT_UPDATED, MERCHANT_RESTRICTED, …), oldest first.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MerchantAuditEventListDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Merchants"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/merchants/{id}/verify/start": {
      "post": {
        "operationId": "startVerify",
        "summary": "Start micro-deposit verification (default payout method)",
        "description": "Legacy helper: verifies the default payout method. Prefer POST /v1/merchants/:id/payout-methods/:methodId/verify/start.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerifyStartResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Merchants"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/merchants/{id}/verify": {
      "post": {
        "operationId": "confirmVerify",
        "summary": "Confirm micro-deposit amounts (active / default payout method)",
        "description": "Legacy helper: confirms the active verification session or default method. Prefer POST /v1/merchants/:id/payout-methods/:methodId/verify.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConfirmMerchantVerifyDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerifyConfirmResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Merchants"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/products": {
      "post": {
        "operationId": "create",
        "summary": "Create a product",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateProductDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Products"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      },
      "get": {
        "operationId": "list",
        "summary": "List products (cursor pagination)",
        "parameters": [
          {
            "name": "active",
            "required": false,
            "in": "query",
            "schema": {
              "enum": [
                "true",
                "false"
              ],
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "schema": {
              "example": 25,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductListResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Products"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/products/{id}": {
      "get": {
        "operationId": "get",
        "summary": "Get a product and its payment links",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Products"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      },
      "patch": {
        "operationId": "update",
        "summary": "Update a product",
        "description": "Send only the fields to change. Pass \"\" to clear description / imageUrl.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateProductDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Products"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      },
      "delete": {
        "operationId": "remove",
        "summary": "Delete a product",
        "description": "Hard-deletes the product and its payment links. Returns 409 product_has_sales if any checkout session was paid.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "409": {
            "description": "product_has_sales",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Products"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/products/{id}/links": {
      "post": {
        "operationId": "createLink",
        "summary": "Create a payment link for a product",
        "description": "Omit slug to auto-generate one from the product name. 409 slug_taken if a provided slug is in use.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePaymentLinkDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentLinkResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "409": {
            "description": "slug_taken",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Products"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      },
      "get": {
        "operationId": "listLinks",
        "summary": "List payment links for a product",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentLinkListResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Products"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/payment-links/{id}": {
      "get": {
        "operationId": "get",
        "summary": "Get a payment link",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentLinkResponseDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Products"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      },
      "patch": {
        "operationId": "update",
        "summary": "Update a payment link",
        "description": "Enable/disable it (status), toggle allowQuantity, set maxQuantity or redirectUrl.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePaymentLinkDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentLinkResponseDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Products"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      },
      "delete": {
        "operationId": "remove",
        "summary": "Delete a payment link",
        "description": "Returns 409 product_has_sales if a checkout session on this link was paid — disable it instead.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "401": {
            "description": "Missing or invalid tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "409": {
            "description": "product_has_sales",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Products"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    },
    "/v1/notifications/test": {
      "post": {
        "operationId": "sendTest",
        "summary": "Send a test event to subscribed webhook endpoints",
        "description": "Fires a `notification.test` event to every active webhook endpoint subscribed to that event (or all events, depending on your subscription list). Use this to validate URL reachability and HMAC signature verification before going live. Returns 202 Accepted with `{ sent, event, tenantId }`.",
        "parameters": [],
        "responses": {
          "202": {
            "description": "Test event queued/delivered to matching endpoints.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationTestResponseDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or inactive tenant API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "tenant-api-key": []
          }
        ]
      }
    }
  },
  "info": {
    "title": "VEXPay Tenant API",
    "description": "Tenant-facing API for collecting Venezuelan payments (C2P, VPOS, Pago Móvil, débito inmediato), merchant verification, payouts, and signed webhooks.\n\n## Authentication\nSend `x-api-key: <tenant key>` on every request. Keep the key server-side and rotate it if exposed.\n\n## Interactive reference\nThis OpenAPI document powers Scalar at `/reference` (API) and `/api-reference` (docs portal). Download the raw contract at `/openapi.json`.\n\n## C2P flow\nCreate an intent with `POST /v1/payments/c2p/request` (R4 also requests the bank SMS/OTP), collect the token from your customer, then execute with `POST /v1/payments/c2p`. VEXPay does not message the customer — the payer bank sends the OTP.\n\n## externalRef\nAlways client-supplied (max 64, unique per tenant where required). On **payments** it is optional correlation for lookup — **not** an idempotency key — so reusing it can create duplicate payments. On **merchants** and **payouts** it is required and acts as the idempotency key (same payload → 200 replay; conflicting payload → 409 `external_ref_conflict`).\n\n## Tags\n- **Banks** — listed bank catalog with logos\n- **Payments** — quote, C2P, VPOS, Pago Móvil verify, lookups, reverse\n- **Advanced payments** — débito OTP/execute, credits, disbursements, account dispersion, change (requires R4)\n- **Merchants** — register, verify micro-deposits, manage payout methods\n- **Products** — no-code products and payment links for the hosted checkout\n- **Payouts** — single and batch VES payouts to verified merchants\n- **Webhooks** — endpoint CRUD + test notification",
    "version": "1.0",
    "contact": {}
  },
  "tags": [
    {
      "name": "Banks",
      "description": "Listed Venezuelan bank catalog (SIMF codes, services, logos)."
    },
    {
      "name": "Payments",
      "description": "Quotes, C2P, VPOS, Pago Móvil verification, payment lookups, and C2P reverse."
    },
    {
      "name": "Advanced payments",
      "description": "R4 débitos, créditos, disbursements, account payouts, and change. Returns 503 when R4 is not configured."
    },
    {
      "name": "Merchants",
      "description": "Merchant registration, payout methods, and micro-deposit verification."
    },
    {
      "name": "Products",
      "description": "No-code products and shareable payment links for the hosted checkout (/pay/:slug)."
    },
    {
      "name": "Payouts",
      "description": "Exact-VES merchant payouts with item-level idempotency."
    },
    {
      "name": "Webhooks",
      "description": "Signed webhook endpoints and test delivery."
    }
  ],
  "servers": [
    {
      "url": "/",
      "description": "Current environment"
    }
  ],
  "components": {
    "securitySchemes": {
      "tenant-api-key": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Tenant API key. Keep it server-side and rotate it if exposed."
      }
    },
    "schemas": {
      "ApiErrorDto": {
        "type": "object",
        "properties": {
          "statusCode": {
            "type": "number",
            "example": 400,
            "description": "HTTP status code mirrored in the JSON body (Nest default error shape)."
          },
          "message": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ],
            "description": "Human-readable error detail, or a validation error array.",
            "example": "usdAmount must be a positive number"
          },
          "error": {
            "type": "string",
            "example": "Bad Request",
            "description": "Short error label. Business conflicts may also expose machine codes such as `external_ref_conflict` or `merchant_has_payouts` depending on the route."
          }
        },
        "required": [
          "statusCode",
          "message"
        ]
      },
      "PlatformBalanceDto": {
        "type": "object",
        "properties": {
          "tenantId": {
            "type": "string",
            "format": "uuid"
          },
          "platformId": {
            "type": "string",
            "example": "plt_3fd84b2d9ad14f74a2d90f2f56984db5"
          },
          "collectedVes": {
            "type": "string",
            "example": "10000.00"
          },
          "feesVes": {
            "type": "string",
            "example": "250.00"
          },
          "paidOutVes": {
            "type": "string",
            "example": "1000.00"
          },
          "reserveVes": {
            "type": "string",
            "example": "100.00"
          },
          "ledgerNetVes": {
            "type": "string",
            "example": "8650.00"
          },
          "availableVes": {
            "type": "string",
            "example": "8650.00",
            "description": "Tenant spendable float after reserve (seller obligations already deducted via SELLER_TRANSFER)."
          },
          "platformAvailableVes": {
            "type": "string",
            "example": "8650.00"
          },
          "sellerObligationsVes": {
            "type": "string",
            "example": "1200.00",
            "description": "Sum of seller pending + available obligations."
          },
          "sellerPendingVes": {
            "type": "string",
            "example": "400.00"
          },
          "sellerAvailableVes": {
            "type": "string",
            "example": "800.00"
          },
          "feePercent": {
            "type": "string",
            "example": "2.5000"
          },
          "feeFixedUsd": {
            "type": "string",
            "example": "0.00"
          }
        },
        "required": [
          "tenantId",
          "platformId",
          "collectedVes",
          "feesVes",
          "paidOutVes",
          "reserveVes",
          "ledgerNetVes",
          "availableVes",
          "platformAvailableVes",
          "sellerObligationsVes",
          "sellerPendingVes",
          "sellerAvailableVes",
          "feePercent",
          "feeFixedUsd"
        ]
      },
      "CreateWebhookDto": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "example": "https://merchant.example.com/webhooks/vexpay"
          },
          "secret": {
            "type": "string",
            "description": "Signing secret. If omitted, a random secret is generated and returned once.",
            "example": "replace-with-a-long-random-secret"
          },
          "events": {
            "type": "array",
            "example": [
              "payment.completed",
              "payment.failed"
            ],
            "items": {
              "type": "string",
              "enum": [
                "payment.pending",
                "payment.completed",
                "payment.failed",
                "payment.canceled",
                "payment.reversed",
                "merchant.verified",
                "merchant.rejected",
                "merchant.deactivated",
                "merchant.reactivated",
                "merchant.balance.updated",
                "merchant.created",
                "merchant.activated",
                "merchant.updated",
                "merchant.kyb_required",
                "merchant.restricted",
                "merchant.capability.updated",
                "merchant.wallet_credit",
                "payout.completed",
                "payout.failed",
                "tenant.status_changed",
                "tenant.api_key.created",
                "tenant.api_key.rotated",
                "tenant.api_key.revoked",
                "notification.test"
              ]
            }
          }
        },
        "required": [
          "url",
          "events"
        ]
      },
      "WebhookEndpointDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "tenantId": {
            "type": "string",
            "format": "uuid"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "payment.pending",
                "payment.completed",
                "payment.failed",
                "payment.canceled",
                "payment.reversed",
                "merchant.verified",
                "merchant.rejected",
                "merchant.deactivated",
                "merchant.reactivated",
                "merchant.balance.updated",
                "merchant.created",
                "merchant.activated",
                "merchant.updated",
                "merchant.kyb_required",
                "merchant.restricted",
                "merchant.capability.updated",
                "merchant.wallet_credit",
                "payout.completed",
                "payout.failed",
                "tenant.status_changed",
                "tenant.api_key.created",
                "tenant.api_key.rotated",
                "tenant.api_key.revoked",
                "notification.test"
              ]
            }
          },
          "isActive": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "secret": {
            "type": "string",
            "description": "Returned only when the endpoint is created. Store it securely; list responses omit it."
          }
        },
        "required": [
          "id",
          "tenantId",
          "url",
          "events",
          "isActive",
          "createdAt"
        ]
      },
      "UpdateWebhookDto": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "example": "https://merchant.example.com/webhooks/vexpay"
          },
          "events": {
            "type": "array",
            "example": [
              "payment.completed",
              "payment.failed",
              "payout.completed"
            ],
            "description": "Replaces the full event subscription list when provided.",
            "items": {
              "type": "string",
              "enum": [
                "payment.pending",
                "payment.completed",
                "payment.failed",
                "payment.canceled",
                "payment.reversed",
                "merchant.verified",
                "merchant.rejected",
                "merchant.deactivated",
                "merchant.reactivated",
                "merchant.balance.updated",
                "merchant.created",
                "merchant.activated",
                "merchant.updated",
                "merchant.kyb_required",
                "merchant.restricted",
                "merchant.capability.updated",
                "merchant.wallet_credit",
                "payout.completed",
                "payout.failed",
                "tenant.status_changed",
                "tenant.api_key.created",
                "tenant.api_key.rotated",
                "tenant.api_key.revoked",
                "notification.test"
              ]
            }
          },
          "isActive": {
            "type": "boolean",
            "example": true
          }
        }
      },
      "DeleteWebhookResponseDto": {
        "type": "object",
        "properties": {
          "deleted": {
            "type": "boolean",
            "example": true
          }
        },
        "required": [
          "deleted"
        ]
      },
      "PayoutResponseDto": {
        "type": "object",
        "properties": {
          "payoutId": {
            "type": "string",
            "format": "uuid",
            "description": "Payout id. Empty string only on batch item failures that never created a row."
          },
          "status": {
            "type": "string",
            "enum": [
              "completed",
              "pending",
              "failed"
            ],
            "description": "`pending` means the credit is still reconciling (AC00); subscribe to payout webhooks or poll GET /v1/payouts/:id."
          },
          "reference": {
            "type": "string",
            "nullable": true,
            "description": "Bank reference when available."
          },
          "failureCode": {
            "type": "string",
            "nullable": true,
            "description": "Machine-readable failure when status is failed (e.g. merchant_inactive, payout_method_not_verified)."
          },
          "externalRef": {
            "type": "string",
            "description": "Tenant-supplied idempotency / lookup key."
          },
          "paymentId": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "Funding payment when this payout is a marketplace settlement leg."
          },
          "merchantId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "payoutMethodId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "merchantName": {
            "type": "string"
          },
          "monto": {
            "type": "string",
            "example": "1523.40",
            "description": "Net two-decimal VES amount credited at the bank."
          },
          "grossMonto": {
            "type": "string",
            "example": "100.00",
            "description": "Gross VES withdrawn from the ledger (instant tenant credits only)."
          },
          "feePercent": {
            "type": "string",
            "example": "2.5000",
            "description": "Platform fee percent applied on instant tenant credits."
          },
          "feeVes": {
            "type": "string",
            "example": "2.50",
            "description": "Platform fee in VES retained on instant tenant credits."
          },
          "concepto": {
            "type": "string"
          },
          "bankCode": {
            "type": "string",
            "example": "0134",
            "description": "Destination bank SIMF code."
          },
          "destination": {
            "type": "string",
            "description": "Masked phone destination, e.g. …5555"
          },
          "operationId": {
            "type": "string",
            "nullable": true,
            "description": "Network operation id while pending reconciliation."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "settledAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          }
        },
        "required": [
          "payoutId",
          "status"
        ]
      },
      "PayoutListResponseDto": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PayoutResponseDto"
            }
          },
          "nextCursor": {
            "type": "string",
            "nullable": true,
            "description": "Pass as cursor on the next request when more pages exist"
          }
        },
        "required": [
          "items"
        ]
      },
      "PayoutBatchItemResultDto": {
        "type": "object",
        "properties": {
          "payoutId": {
            "type": "string",
            "format": "uuid",
            "description": "Payout id. Empty string only on batch item failures that never created a row."
          },
          "status": {
            "type": "string",
            "enum": [
              "completed",
              "pending",
              "failed"
            ],
            "description": "`pending` means the credit is still reconciling (AC00); subscribe to payout webhooks or poll GET /v1/payouts/:id."
          },
          "reference": {
            "type": "string",
            "nullable": true,
            "description": "Bank reference when available."
          },
          "failureCode": {
            "type": "string",
            "nullable": true,
            "description": "Machine-readable failure when status is failed (e.g. merchant_inactive, payout_method_not_verified)."
          },
          "externalRef": {
            "type": "string",
            "description": "Echo of the item-level externalRef from the request (idempotency key).",
            "maxLength": 64
          },
          "paymentId": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "Funding payment when this payout is a marketplace settlement leg."
          },
          "merchantId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "payoutMethodId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "merchantName": {
            "type": "string"
          },
          "monto": {
            "type": "string",
            "example": "1523.40",
            "description": "Net two-decimal VES amount credited at the bank."
          },
          "grossMonto": {
            "type": "string",
            "example": "100.00",
            "description": "Gross VES withdrawn from the ledger (instant tenant credits only)."
          },
          "feePercent": {
            "type": "string",
            "example": "2.5000",
            "description": "Platform fee percent applied on instant tenant credits."
          },
          "feeVes": {
            "type": "string",
            "example": "2.50",
            "description": "Platform fee in VES retained on instant tenant credits."
          },
          "concepto": {
            "type": "string"
          },
          "bankCode": {
            "type": "string",
            "example": "0134",
            "description": "Destination bank SIMF code."
          },
          "destination": {
            "type": "string",
            "description": "Masked phone destination, e.g. …5555"
          },
          "operationId": {
            "type": "string",
            "nullable": true,
            "description": "Network operation id while pending reconciliation."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "settledAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          }
        },
        "required": [
          "payoutId",
          "status"
        ]
      },
      "PayoutBatchResponseDto": {
        "type": "object",
        "properties": {
          "batchId": {
            "type": "string",
            "format": "uuid",
            "description": "Batch id. Same payload + batch externalRef replays with 200."
          },
          "paymentId": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "Funding payment when this batch settles a marketplace collection."
          },
          "items": {
            "description": "Per-item results in request order. Failed items include status `failed` and failureCode; they do not abort the rest of the batch.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PayoutBatchItemResultDto"
            }
          }
        },
        "required": [
          "batchId",
          "items"
        ]
      },
      "CreatePayoutDto": {
        "type": "object",
        "properties": {
          "merchantId": {
            "type": "string",
            "format": "uuid",
            "description": "Verified, active merchant that receives the payout."
          },
          "payoutMethodId": {
            "type": "string",
            "format": "uuid",
            "description": "Payout method to credit. Defaults to the merchant’s default verified method when omitted."
          },
          "monto": {
            "type": "string",
            "example": "1523.40",
            "description": "Exact two-decimal VES amount as a string. The gateway never converts FX for payouts."
          },
          "concepto": {
            "type": "string",
            "maxLength": 30,
            "example": "Liquidacion semana 30",
            "description": "Statement concept (max 30 chars)."
          },
          "externalRef": {
            "type": "string",
            "maxLength": 64,
            "example": "po_9c21…",
            "description": "Required idempotency key per tenant. Same payload → 200 replay; conflicting payload → 409 external_ref_conflict."
          },
          "paymentId": {
            "type": "string",
            "format": "uuid",
            "description": "Optional funding payment for marketplace settlement. When set, montos are capped by remaining net (vesAmount − feeVes − PENDING/COMPLETED payouts). Multiple payouts allowed until remaining is 0."
          },
          "fromMerchantBalance": {
            "type": "boolean",
            "description": "When true, debit the seller available balance (tenant float already reserved via SELLER_TRANSFER). Default false = classic tenant-float payout."
          }
        },
        "required": [
          "merchantId",
          "monto",
          "concepto",
          "externalRef"
        ]
      },
      "CreateInstantPayoutDto": {
        "type": "object",
        "properties": {
          "monto": {
            "type": "string",
            "example": "100.00",
            "description": "Gross two-decimal VES amount to withdraw from the tenant ledger. Credits the tenant’s verified payout account (net of feePercent). Requires a verified eligible account (cooling only after destination change)."
          },
          "concepto": {
            "type": "string",
            "maxLength": 30,
            "example": "Retiro tenant",
            "description": "Statement concept (max 30 chars)."
          },
          "externalRef": {
            "type": "string",
            "maxLength": 64,
            "example": "ti_9c21…",
            "description": "Required idempotency key per tenant. Same payload → 200 replay; conflicting payload → 409 external_ref_conflict."
          }
        },
        "required": [
          "monto",
          "concepto",
          "externalRef"
        ]
      },
      "BatchPayoutItemDto": {
        "type": "object",
        "properties": {
          "merchantId": {
            "type": "string",
            "format": "uuid"
          },
          "payoutMethodId": {
            "type": "string",
            "format": "uuid",
            "description": "Payout method to credit. Defaults to the merchant’s default verified method when omitted."
          },
          "monto": {
            "type": "string",
            "example": "1523.40"
          },
          "concepto": {
            "type": "string",
            "maxLength": 30
          },
          "externalRef": {
            "type": "string",
            "maxLength": 64
          },
          "fromMerchantBalance": {
            "type": "boolean",
            "description": "When true, debit the seller available balance instead of tenant float."
          }
        },
        "required": [
          "merchantId",
          "monto",
          "concepto",
          "externalRef"
        ]
      },
      "CreatePayoutBatchDto": {
        "type": "object",
        "properties": {
          "externalRef": {
            "type": "string",
            "maxLength": 64,
            "example": "corte_2026-07-28",
            "description": "Batch-level idempotency key. Same externalRef + identical items → 200 replay; conflict → 409."
          },
          "paymentId": {
            "type": "string",
            "format": "uuid",
            "description": "Optional funding payment for marketplace settlement. Applied to every item. Sum of item montos must fit remaining net for that payment."
          },
          "items": {
            "description": "One or more payout legs. Each item has its own externalRef (also idempotent). Failed items do not roll back successful siblings.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BatchPayoutItemDto"
            }
          }
        },
        "required": [
          "externalRef",
          "items"
        ]
      },
      "TenantPayoutAccountResponseDto": {
        "type": "object",
        "properties": {
          "accountId": {
            "type": "string",
            "format": "uuid"
          },
          "bankCode": {
            "type": "string",
            "example": "0163"
          },
          "destination": {
            "type": "string",
            "description": "Masked phone, e.g. …5555"
          },
          "identification": {
            "type": "string",
            "example": "V12345678"
          },
          "eligibility": {
            "type": "string",
            "enum": [
              "pending_verification",
              "verifying",
              "cooling",
              "eligible",
              "rejected",
              "locked"
            ],
            "description": "UI/API eligibility state. `cooling` = verified after a destination change, still within the 1 business-day wait. `eligible` = may receive instant credits (first verify unlocks immediately)."
          },
          "status": {
            "type": "string",
            "enum": [
              "pending_verification",
              "verifying",
              "verified",
              "rejected"
            ]
          },
          "verifiedAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "payoutEligibleAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time",
            "description": "Instant payouts allowed at/after this timestamp (verifiedAt + 1 business day)."
          },
          "failureCode": {
            "type": "string",
            "nullable": true
          },
          "lockedUntil": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "verifyExpiresAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time",
            "description": "When the current micro-deposit confirm window expires."
          }
        },
        "required": [
          "accountId",
          "bankCode",
          "destination",
          "identification",
          "eligibility",
          "status"
        ]
      },
      "TenantPayoutAccountVerifyStartResponseDto": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "verifying"
            ]
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "accountId": {
            "type": "string",
            "format": "uuid"
          }
        },
        "required": [
          "status",
          "expiresAt",
          "accountId"
        ]
      },
      "TenantPayoutAccountVerifyConfirmResponseDto": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "eligible",
              "cooling"
            ],
            "description": "`eligible` on first successful verify (instant credits allowed immediately). `cooling` after a destination change re-verify (1 business day)."
          },
          "accountId": {
            "type": "string",
            "format": "uuid"
          },
          "payoutEligibleAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "status",
          "accountId",
          "payoutEligibleAt"
        ]
      },
      "UpsertTenantPayoutAccountDto": {
        "type": "object",
        "properties": {
          "banco": {
            "type": "string",
            "example": "0163",
            "description": "Beneficiary bank SIMF code (3–4 digits). Prefer codes from GET /v1/banks."
          },
          "cedula": {
            "type": "string",
            "example": "V12345678",
            "description": "Beneficiary cédula/RIF."
          },
          "telefono": {
            "type": "string",
            "example": "584121234567",
            "description": "Beneficiary Pago Móvil phone (58… or 0…)."
          }
        },
        "required": [
          "banco",
          "cedula",
          "telefono"
        ]
      },
      "ConfirmTenantPayoutAccountVerifyDto": {
        "type": "object",
        "properties": {
          "amount1": {
            "type": "string",
            "example": "0.37",
            "description": "First micro-deposit amount (exact two decimals)."
          },
          "amount2": {
            "type": "string",
            "example": "0.12",
            "description": "Second micro-deposit amount (exact two decimals)."
          }
        },
        "required": [
          "amount1",
          "amount2"
        ]
      },
      "DebitOtpResponseDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "example": "202",
            "description": "Typically `202` when the payer bank accepted the OTP request and will SMS the customer."
          },
          "message": {
            "type": "string",
            "example": "Operación aceptada",
            "description": "Human-readable network message when provided."
          },
          "reference": {
            "type": "string",
            "example": "16142940",
            "description": "Bank reference when the operation settles synchronously."
          },
          "id": {
            "type": "string",
            "example": "6785d97e-2092-49f0-9f7d-3d5921f0b13f",
            "description": "Network operation id. Prefer this over `Id` when both are present. Use with GET /v1/payments/operations/:id."
          },
          "Id": {
            "type": "string",
            "example": "6785d97e-2092-49f0-9f7d-3d5921f0b13f",
            "description": "Alternate casing of the operation id some network responses use."
          },
          "success": {
            "type": "boolean",
            "example": true,
            "description": "Present on some operation responses when the network returns an explicit success flag."
          }
        },
        "required": [
          "code"
        ]
      },
      "ImmediateDebitResponseDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "example": "ACCP",
            "description": "Network status code. Common values: `202` (OTP accepted), `ACCP` (accepted/completed), `AC00` (pending — gateway auto-polls), reject codes on failure."
          },
          "message": {
            "type": "string",
            "example": "Operación aceptada",
            "description": "Human-readable network message when provided."
          },
          "reference": {
            "type": "string",
            "example": "16142940",
            "description": "Bank reference when the operation settles synchronously."
          },
          "id": {
            "type": "string",
            "example": "6785d97e-2092-49f0-9f7d-3d5921f0b13f",
            "description": "Network operation id. Prefer this over `Id` when both are present. Use with GET /v1/payments/operations/:id."
          },
          "Id": {
            "type": "string",
            "example": "6785d97e-2092-49f0-9f7d-3d5921f0b13f",
            "description": "Alternate casing of the operation id some network responses use."
          },
          "success": {
            "type": "boolean",
            "example": true,
            "description": "Present on some operation responses when the network returns an explicit success flag."
          },
          "paymentId": {
            "type": "string",
            "format": "uuid",
            "example": "3fd84b2d-9ad1-4f74-a2d9-0f2f56984db5",
            "description": "VEXPay payment id for this débito inmediato (method DEBITO_INMEDIATO)."
          },
          "externalRef": {
            "type": "string",
            "example": "fine_736a0b42-0b6e-454c-b87e-7f3c0e47057b",
            "description": "Echo of the request externalRef when provided."
          }
        },
        "required": [
          "code",
          "paymentId"
        ]
      },
      "R4OperationResponseDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "example": "ACCP",
            "description": "Network status code. Common values: `202` (OTP accepted), `ACCP` (accepted/completed), `AC00` (pending — gateway auto-polls), reject codes on failure."
          },
          "message": {
            "type": "string",
            "example": "Operación aceptada",
            "description": "Human-readable network message when provided."
          },
          "reference": {
            "type": "string",
            "example": "16142940",
            "description": "Bank reference when the operation settles synchronously."
          },
          "id": {
            "type": "string",
            "example": "6785d97e-2092-49f0-9f7d-3d5921f0b13f",
            "description": "Network operation id. Prefer this over `Id` when both are present. Use with GET /v1/payments/operations/:id."
          },
          "Id": {
            "type": "string",
            "example": "6785d97e-2092-49f0-9f7d-3d5921f0b13f",
            "description": "Alternate casing of the operation id some network responses use."
          },
          "success": {
            "type": "boolean",
            "example": true,
            "description": "Present on some operation responses when the network returns an explicit success flag."
          }
        },
        "required": [
          "code"
        ]
      },
      "CreditDisbursementResponseDto": {
        "type": "object",
        "properties": {
          "paymentId": {
            "type": "string",
            "format": "uuid",
            "description": "Id of the completed PAGO_MOVIL payment that funded this disbursement."
          },
          "referencia": {
            "type": "string",
            "example": "12345678",
            "description": "Normalized bank reference used to locate the inbound payment."
          },
          "credits": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "telefono": {
                  "type": "string",
                  "example": "584121234567"
                },
                "code": {
                  "type": "string",
                  "example": "ACCP"
                },
                "reference": {
                  "type": "string",
                  "example": "16142940"
                },
                "id": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "required": [
                "telefono",
                "code"
              ]
            },
            "description": "Per-recipient credit results in request order."
          }
        },
        "required": [
          "paymentId",
          "referencia",
          "credits"
        ]
      },
      "AccountPayoutDispersionResponseDto": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "example": true,
            "description": "Whether the bank network accepted the dispersion request."
          },
          "message": {
            "type": "string",
            "description": "Network success message when provided."
          },
          "error": {
            "type": "string",
            "description": "Network error detail when success is false."
          },
          "referencia": {
            "type": "string",
            "example": "123456789",
            "description": "9-digit wire reference actually sent to the bank (last 9 digits of the request referencia)."
          }
        },
        "required": [
          "success",
          "referencia"
        ]
      },
      "ChangePaymentResponseDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "example": "ACCP",
            "description": "Network status code. Common values: `202` (OTP accepted), `ACCP` (accepted/completed), `AC00` (pending — gateway auto-polls), reject codes on failure."
          },
          "message": {
            "type": "string",
            "example": "Operación aceptada",
            "description": "Human-readable network message when provided."
          },
          "reference": {
            "type": "string",
            "example": "16142940",
            "description": "Bank reference when the operation settles synchronously."
          },
          "id": {
            "type": "string",
            "example": "6785d97e-2092-49f0-9f7d-3d5921f0b13f",
            "description": "Network operation id. Prefer this over `Id` when both are present. Use with GET /v1/payments/operations/:id."
          },
          "Id": {
            "type": "string",
            "example": "6785d97e-2092-49f0-9f7d-3d5921f0b13f",
            "description": "Alternate casing of the operation id some network responses use."
          },
          "success": {
            "type": "boolean",
            "example": true,
            "description": "Present on some operation responses when the network returns an explicit success flag."
          }
        },
        "required": [
          "code"
        ]
      },
      "ManualOperationPollResponseDto": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "debit",
              "payout",
              "verification_deposit"
            ]
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "operationId": {
            "type": "string",
            "description": "Network operation id that was polled."
          },
          "statusBefore": {
            "type": "string",
            "example": "PENDING"
          },
          "status": {
            "type": "string",
            "example": "COMPLETED"
          },
          "failureCode": {
            "type": "string",
            "nullable": true
          },
          "code": {
            "type": "string",
            "nullable": true,
            "example": "AC00",
            "description": "Latest network code from ConsultarOperaciones when available."
          },
          "message": {
            "type": "string"
          },
          "reference": {
            "type": "string"
          }
        },
        "required": [
          "kind",
          "id",
          "operationId",
          "statusBefore",
          "status"
        ]
      },
      "GenerateDebitOtpDto": {
        "type": "object",
        "properties": {
          "banco": {
            "type": "string",
            "example": "0191",
            "pattern": "^\\d{3,4}$",
            "description": "3–4 digit bank code (padded to 4 digits when sent to the network). Prefer codes from GET /v1/banks."
          },
          "monto": {
            "type": "number",
            "example": 50,
            "minimum": 0.01,
            "maximum": 1000000,
            "description": "Debit amount in VES (not USD)."
          },
          "telefono": {
            "type": "string",
            "example": "584121234567",
            "description": "Payer mobile: 58 + 10 digits, or 0 + 10 digits local form."
          },
          "cedula": {
            "type": "string",
            "example": "V12345678",
            "description": "Payer cédula/RIF (V/E/J/P/G + digits)."
          }
        },
        "required": [
          "banco",
          "monto",
          "telefono",
          "cedula"
        ]
      },
      "ImmediateDebitDto": {
        "type": "object",
        "properties": {
          "banco": {
            "type": "string",
            "example": "0191",
            "pattern": "^\\d{3,4}$",
            "description": "3–4 digit bank code (padded to 4 digits when sent to the network). Prefer codes from GET /v1/banks."
          },
          "monto": {
            "type": "number",
            "example": 50,
            "minimum": 0.01,
            "maximum": 1000000,
            "description": "Debit amount in VES (not USD)."
          },
          "telefono": {
            "type": "string",
            "example": "584121234567",
            "description": "Payer mobile: 58 + 10 digits, or 0 + 10 digits local form."
          },
          "cedula": {
            "type": "string",
            "example": "V12345678",
            "description": "Payer cédula/RIF (V/E/J/P/G + digits)."
          },
          "nombre": {
            "type": "string",
            "example": "Maria Perez",
            "maxLength": 20,
            "description": "Payer display name (max 20 chars, truncated for the bank)."
          },
          "otp": {
            "type": "string",
            "example": "123456",
            "pattern": "^\\d{6,8}$",
            "description": "OTP the payer bank SMS’d after POST /v1/payments/debit/otp."
          },
          "concepto": {
            "type": "string",
            "example": "Pago de factura",
            "maxLength": 30,
            "description": "Statement concept shown to the payer (max 30 chars)."
          },
          "externalRef": {
            "type": "string",
            "maxLength": 64,
            "example": "fine_736a0b42-0b6e-454c-b87e-7f3c0e47057b",
            "description": "Tenant correlation value for recovery lookup (GET /v1/payments/by-ref/:externalRef). Not an idempotency key."
          },
          "merchantId": {
            "type": "string",
            "format": "uuid"
          },
          "applicationFeeVes": {
            "type": "string",
            "example": "50.00",
            "description": "Marketplace application fee in VES retained by the platform."
          },
          "applicationFeePercent": {
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "example": 10
          }
        },
        "required": [
          "banco",
          "monto",
          "telefono",
          "cedula",
          "nombre",
          "otp",
          "concepto"
        ]
      },
      "ManualOperationPollDto": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "debit",
              "payout",
              "verification_deposit"
            ],
            "example": "debit",
            "description": "Which pending entity to reconcile."
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "example": "3fd84b2d-9ad1-4f74-a2d9-0f2f56984db5",
            "description": "Payment, payout, or verification deposit id (not the network operation id)."
          }
        },
        "required": [
          "kind",
          "id"
        ]
      },
      "ImmediateCreditDto": {
        "type": "object",
        "properties": {
          "banco": {
            "type": "string",
            "example": "0191",
            "description": "Beneficiary bank code (3–4 digits). Prefer codes from GET /v1/banks."
          },
          "cedula": {
            "type": "string",
            "example": "V12345678",
            "description": "Beneficiary cédula/RIF."
          },
          "telefono": {
            "type": "string",
            "example": "584121234567",
            "description": "Beneficiary Pago Móvil phone (58… or 0…)."
          },
          "monto": {
            "type": "number",
            "example": 50,
            "minimum": 0.01,
            "maximum": 1000000,
            "description": "Credit amount in VES."
          },
          "concepto": {
            "type": "string",
            "example": "Pago de factura",
            "maxLength": 30,
            "description": "Statement concept (max 30 chars)."
          }
        },
        "required": [
          "banco",
          "cedula",
          "telefono",
          "monto",
          "concepto"
        ]
      },
      "AccountCreditDto": {
        "type": "object",
        "properties": {
          "cedula": {
            "type": "string",
            "example": "V12345678",
            "description": "Account holder cédula/RIF."
          },
          "cuenta": {
            "type": "string",
            "example": "01910000000000000000",
            "minLength": 20,
            "maxLength": 20,
            "description": "20-digit Venezuelan bank account number."
          },
          "monto": {
            "type": "number",
            "example": 50,
            "description": "Credit amount in VES."
          },
          "concepto": {
            "type": "string",
            "example": "Pago de factura",
            "maxLength": 30,
            "description": "Statement concept (max 30 chars)."
          }
        },
        "required": [
          "cedula",
          "cuenta",
          "monto",
          "concepto"
        ]
      },
      "CreditRecipientDto": {
        "type": "object",
        "properties": {
          "banco": {
            "type": "string",
            "example": "0191",
            "description": "Recipient bank code (3–4 digits)."
          },
          "cedula": {
            "type": "string",
            "example": "V12345678",
            "description": "Recipient cédula/RIF."
          },
          "telefono": {
            "type": "string",
            "example": "584121234567",
            "description": "Recipient Pago Móvil phone."
          },
          "montoPart": {
            "type": "number",
            "example": 25,
            "description": "Share of the total disbursement for this recipient (VES). Sum of montoPart must equal monto."
          }
        },
        "required": [
          "banco",
          "cedula",
          "telefono",
          "montoPart"
        ]
      },
      "CreditDisbursementDto": {
        "type": "object",
        "properties": {
          "monto": {
            "type": "number",
            "example": 50,
            "description": "Total VES amount to disburse. Must match a completed PAGO_MOVIL payment’s vesAmount for the given referencia."
          },
          "referencia": {
            "type": "string",
            "example": "123456789",
            "description": "Bank reference of a completed inbound Pago Móvil payment (up to 9 digits). Used to locate and mark that payment as dispersed."
          },
          "concepto": {
            "type": "string",
            "example": "Dispersión",
            "maxLength": 30,
            "description": "Concept applied to each credit leg."
          },
          "personas": {
            "description": "One or more phone recipients. Sum of personas[].montoPart must equal monto.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreditRecipientDto"
            }
          }
        },
        "required": [
          "monto",
          "referencia",
          "concepto",
          "personas"
        ]
      },
      "PayoutRecipientDto": {
        "type": "object",
        "properties": {
          "nombres": {
            "type": "string",
            "example": "Maria Perez",
            "maxLength": 80,
            "description": "Beneficiary legal name."
          },
          "documento": {
            "type": "string",
            "example": "V12345678",
            "description": "Beneficiary documento (V/E/J/P + digits)."
          },
          "destino": {
            "type": "string",
            "example": "01910000000000000000",
            "minLength": 20,
            "maxLength": 20,
            "description": "20-digit destination account number."
          },
          "montoPart": {
            "type": "number",
            "example": 25,
            "description": "Share for this beneficiary (VES). Sum of montoPart must equal monto."
          }
        },
        "required": [
          "nombres",
          "documento",
          "destino",
          "montoPart"
        ]
      },
      "PayoutDto": {
        "type": "object",
        "properties": {
          "monto": {
            "type": "number",
            "example": 50,
            "description": "Total VES amount across all personas."
          },
          "fecha": {
            "type": "string",
            "example": "07/20/2026",
            "pattern": "^\\d{2}/\\d{2}/\\d{4}$",
            "description": "Value date as MM/DD/YYYY."
          },
          "referencia": {
            "type": "string",
            "example": "123456789",
            "description": "Numeric reference (digits only). Only the last 9 digits are sent to the bank network."
          },
          "personas": {
            "description": "Account beneficiaries. Sum of personas[].montoPart must equal monto.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PayoutRecipientDto"
            }
          }
        },
        "required": [
          "monto",
          "fecha",
          "referencia",
          "personas"
        ]
      },
      "ChangePaymentDto": {
        "type": "object",
        "properties": {
          "telefonoDestino": {
            "type": "string",
            "example": "584121234567",
            "description": "Customer phone that receives the change (vuelto)."
          },
          "cedula": {
            "type": "string",
            "example": "V12345678",
            "description": "Customer cédula/RIF."
          },
          "banco": {
            "type": "string",
            "example": "0191",
            "description": "Customer bank code (3–4 digits)."
          },
          "monto": {
            "type": "number",
            "example": 5,
            "description": "Change amount in VES."
          },
          "concepto": {
            "type": "string",
            "example": "Vuelto de compra",
            "maxLength": 30,
            "description": "Optional statement concept (max 30 chars)."
          },
          "ip": {
            "type": "string",
            "example": "203.0.113.10",
            "maxLength": 15,
            "description": "Client IP recorded with the operation. Defaults to R4_DEFAULT_CLIENT_IP when omitted."
          }
        },
        "required": [
          "telefonoDestino",
          "cedula",
          "banco",
          "monto"
        ]
      },
      "BankResponseDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "example": "0102",
            "description": "Canonical four-digit SIMF bank code."
          },
          "name": {
            "type": "string",
            "example": "Banco de Venezuela"
          },
          "services": {
            "description": "Provider-reported services; may be empty.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "logoUrl": {
            "type": "string",
            "nullable": true,
            "example": "https://pub-xxxxx.r2.dev/vebanking/banks/0102.png",
            "description": "Public URL for a 100×100 bank logo image (PNG), or null when not uploaded. Render this next to the bank name in selectors so users can identify their bank quickly."
          }
        },
        "required": [
          "code",
          "name",
          "services",
          "logoUrl"
        ]
      },
      "QuoteResponseDto": {
        "type": "object",
        "properties": {
          "usdAmount": {
            "type": "number",
            "example": 25
          },
          "bcvRate": {
            "type": "number",
            "example": 36.5,
            "description": "Authoritative VEX FX BCV rate used for payment settlement"
          },
          "vesAmount": {
            "type": "number",
            "example": 912.5
          },
          "medianRate": {
            "type": "number",
            "example": 36.55,
            "description": "Median of available BCV sources (VEX FX + bank)"
          },
          "medianVesAmount": {
            "type": "number",
            "example": 913.75,
            "description": "USD amount converted at medianRate"
          },
          "source": {
            "type": "string",
            "example": "bcv"
          },
          "fetchedAt": {
            "type": "string",
            "format": "date-time"
          },
          "sources": {
            "type": "object",
            "additionalProperties": true,
            "example": {
              "vexFx": {
                "rate": 36.5,
                "fetchedAt": "2026-07-23T12:00:00.000Z"
              },
              "bank": {
                "rate": 36.6,
                "fetchedAt": "2026-07-23T12:00:00.000Z"
              }
            },
            "description": "Per-source BCV rates or error objects (e.g. `{ error: \"BANK_NOT_CONFIGURED\" }`). Keys typically include `vexFx` and `bank`. `sources.bank` prefers R4 MBbcv, then falls back to BNC Services/BCVRates (`provider: \"r4\" | \"bnc\"`)."
          }
        },
        "required": [
          "usdAmount",
          "bcvRate",
          "vesAmount",
          "medianRate",
          "medianVesAmount",
          "source",
          "fetchedAt",
          "sources"
        ]
      },
      "C2pRequestDto": {
        "type": "object",
        "properties": {
          "usdAmount": {
            "type": "number",
            "minimum": 0.01,
            "maximum": 100000,
            "example": 25
          },
          "debtorId": {
            "type": "string",
            "example": "V12345678"
          },
          "debtorCellPhone": {
            "type": "string",
            "example": "584121234567",
            "description": "Country code 58 followed by 10 digits."
          },
          "debtorBankCode": {
            "type": "number",
            "example": 102,
            "description": "Venezuelan bank institution code (e.g. 102, 105, 134). Must match a bank from GET /v1/banks."
          },
          "externalRef": {
            "type": "string",
            "maxLength": 64,
            "example": "order-1042",
            "description": "Correlation value; not an idempotency key. When present, any other PENDING C2P intent for this tenant + externalRef is canceled (superseded) before the new intent is created."
          },
          "merchantId": {
            "type": "string",
            "format": "uuid"
          },
          "applicationFeeVes": {
            "type": "string",
            "example": "50.00",
            "description": "Marketplace application fee in VES retained by the platform."
          },
          "applicationFeePercent": {
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "example": 10
          }
        },
        "required": [
          "usdAmount",
          "debtorId",
          "debtorCellPhone",
          "debtorBankCode"
        ]
      },
      "C2pIntentResponseDto": {
        "type": "object",
        "properties": {
          "paymentId": {
            "type": "string",
            "format": "uuid",
            "example": "3fd84b2d-9ad1-4f74-a2d9-0f2f56984db5"
          },
          "externalRef": {
            "type": "string",
            "example": "order-1042",
            "description": "Tenant correlation value; not an idempotency key."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "COMPLETED",
              "FAILED",
              "CANCELED",
              "REVERSED"
            ]
          },
          "method": {
            "type": "string",
            "enum": [
              "C2P",
              "VPOS",
              "PAGO_MOVIL",
              "DEBITO_INMEDIATO"
            ]
          },
          "usdAmount": {
            "type": "number",
            "example": 25
          },
          "vesAmount": {
            "type": "number",
            "example": 912.5
          },
          "bcvRate": {
            "type": "number",
            "example": 36.5
          },
          "feeUsd": {
            "type": "number",
            "example": 0.88,
            "description": "Platform service fee, USD. Clamped 0..usdAmount."
          },
          "feeVes": {
            "type": "number",
            "example": 32.12,
            "description": "Platform service fee, VES. Clamped 0..vesAmount."
          },
          "netVes": {
            "type": "number",
            "example": 880.38,
            "description": "What the seller receives: vesAmount − platform fee − application fee, floored at 0."
          },
          "bankReference": {
            "type": "string",
            "example": "00512673"
          },
          "bankTxId": {
            "type": "number",
            "example": 842901
          },
          "debtorId": {
            "type": "string",
            "example": "V12345678"
          },
          "debtorPhone": {
            "type": "string",
            "example": "584121234567"
          },
          "debtorBankCode": {
            "type": "number",
            "example": 102
          },
          "debtorBankName": {
            "type": "string",
            "example": "Banco de Venezuela"
          },
          "cardLast4": {
            "type": "string",
            "example": "4242"
          },
          "cardBrand": {
            "type": "string",
            "example": "Visa"
          },
          "cardProduct": {
            "type": "string",
            "example": "Crédito"
          },
          "accountTypeLabel": {
            "type": "string",
            "example": "Cuenta corriente"
          },
          "tenantName": {
            "type": "string",
            "example": "Comercio Demo"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "failureCode": {
            "type": "string",
            "example": "MOVEMENT_NOT_FOUND"
          },
          "cancelReason": {
            "type": "string",
            "enum": [
              "superseded",
              "expired"
            ],
            "description": "Present when status is CANCELED. superseded = replaced by a newer intent; expired = abandoned after TTL."
          },
          "reversedAt": {
            "type": "string",
            "format": "date-time"
          },
          "reversalRef": {
            "type": "string",
            "example": "00991420"
          },
          "reversalTxId": {
            "type": "number",
            "example": 842950
          },
          "intentId": {
            "type": "string",
            "format": "uuid",
            "description": "Use this value as intentId when executing the C2P charge."
          },
          "otpRequested": {
            "type": "boolean",
            "description": "true when the provider instructed the payer bank to SMS an OTP to the customer (R4 GenerarOtp). false when the customer must generate the token in their bank app."
          }
        },
        "required": [
          "paymentId",
          "status",
          "method",
          "usdAmount",
          "vesAmount",
          "bcvRate",
          "tenantName",
          "createdAt",
          "intentId",
          "otpRequested"
        ]
      },
      "C2pPaymentDto": {
        "type": "object",
        "properties": {
          "intentId": {
            "type": "string",
            "format": "uuid",
            "description": "Pending intent returned by POST /v1/payments/c2p/request."
          },
          "usdAmount": {
            "type": "number",
            "minimum": 0.01,
            "maximum": 100000,
            "example": 25
          },
          "debtorId": {
            "type": "string",
            "example": "V12345678"
          },
          "debtorCellPhone": {
            "type": "string",
            "example": "584121234567"
          },
          "debtorBankCode": {
            "type": "number",
            "example": 102,
            "description": "Venezuelan bank institution code (e.g. 102, 105, 134). Must match a bank from GET /v1/banks."
          },
          "token": {
            "type": "string",
            "pattern": "^\\d{6,8}$",
            "example": "123456",
            "description": "Bank-issued token collected by the tenant from the customer."
          },
          "externalRef": {
            "type": "string",
            "maxLength": 64,
            "example": "order-1042",
            "description": "Correlation value; not an idempotency key."
          },
          "merchantId": {
            "type": "string",
            "format": "uuid",
            "description": "Seller merchant to auto-credit on payment.completed (net = ves − plan fee − applicationFee)."
          },
          "applicationFeeVes": {
            "type": "string",
            "example": "50.00",
            "description": "Marketplace application fee in VES retained by the platform."
          },
          "applicationFeePercent": {
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "example": 10,
            "description": "Optional percent of vesAmount used when applicationFeeVes is omitted."
          }
        },
        "required": [
          "usdAmount",
          "debtorId",
          "debtorCellPhone",
          "debtorBankCode",
          "token"
        ]
      },
      "PaymentReceiptDto": {
        "type": "object",
        "properties": {
          "paymentId": {
            "type": "string",
            "format": "uuid",
            "example": "3fd84b2d-9ad1-4f74-a2d9-0f2f56984db5"
          },
          "externalRef": {
            "type": "string",
            "example": "order-1042",
            "description": "Tenant correlation value; not an idempotency key."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "COMPLETED",
              "FAILED",
              "CANCELED",
              "REVERSED"
            ]
          },
          "method": {
            "type": "string",
            "enum": [
              "C2P",
              "VPOS",
              "PAGO_MOVIL",
              "DEBITO_INMEDIATO"
            ]
          },
          "usdAmount": {
            "type": "number",
            "example": 25
          },
          "vesAmount": {
            "type": "number",
            "example": 912.5
          },
          "bcvRate": {
            "type": "number",
            "example": 36.5
          },
          "feeUsd": {
            "type": "number",
            "example": 0.88,
            "description": "Platform service fee, USD. Clamped 0..usdAmount."
          },
          "feeVes": {
            "type": "number",
            "example": 32.12,
            "description": "Platform service fee, VES. Clamped 0..vesAmount."
          },
          "netVes": {
            "type": "number",
            "example": 880.38,
            "description": "What the seller receives: vesAmount − platform fee − application fee, floored at 0."
          },
          "bankReference": {
            "type": "string",
            "example": "00512673"
          },
          "bankTxId": {
            "type": "number",
            "example": 842901
          },
          "debtorId": {
            "type": "string",
            "example": "V12345678"
          },
          "debtorPhone": {
            "type": "string",
            "example": "584121234567"
          },
          "debtorBankCode": {
            "type": "number",
            "example": 102
          },
          "debtorBankName": {
            "type": "string",
            "example": "Banco de Venezuela"
          },
          "cardLast4": {
            "type": "string",
            "example": "4242"
          },
          "cardBrand": {
            "type": "string",
            "example": "Visa"
          },
          "cardProduct": {
            "type": "string",
            "example": "Crédito"
          },
          "accountTypeLabel": {
            "type": "string",
            "example": "Cuenta corriente"
          },
          "tenantName": {
            "type": "string",
            "example": "Comercio Demo"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "failureCode": {
            "type": "string",
            "example": "MOVEMENT_NOT_FOUND"
          },
          "cancelReason": {
            "type": "string",
            "enum": [
              "superseded",
              "expired"
            ],
            "description": "Present when status is CANCELED. superseded = replaced by a newer intent; expired = abandoned after TTL."
          },
          "reversedAt": {
            "type": "string",
            "format": "date-time"
          },
          "reversalRef": {
            "type": "string",
            "example": "00991420"
          },
          "reversalTxId": {
            "type": "number",
            "example": 842950
          }
        },
        "required": [
          "paymentId",
          "status",
          "method",
          "usdAmount",
          "vesAmount",
          "bcvRate",
          "tenantName",
          "createdAt"
        ]
      },
      "VposPaymentDto": {
        "type": "object",
        "properties": {
          "usdAmount": {
            "type": "number",
            "minimum": 0.01,
            "maximum": 100000,
            "example": 25,
            "description": "USD amount. Required unless vesAmount is set. When only usdAmount is set, VES is derived at the live BCV rate."
          },
          "vesAmount": {
            "type": "number",
            "minimum": 0.01,
            "maximum": 100000000,
            "example": 50,
            "description": "VES amount charged at the bank. When set, locks the bolívar charge and derives USD at BCV — use this to avoid USD↔VES 2-decimal round-trip drift (e.g. Bs. 50 → $0.07 → Bs. 52.86)."
          },
          "cardNumber": {
            "type": "string",
            "pattern": "^\\d{13,19}$",
            "example": "4111111111111111",
            "description": "Handle only in a PCI-compliant server environment."
          },
          "expirationMonth": {
            "type": "number",
            "minimum": 1,
            "maximum": 12,
            "example": 12
          },
          "expirationYear": {
            "type": "number",
            "minimum": 2020,
            "maximum": 2099,
            "example": 2028
          },
          "cvv": {
            "type": "string",
            "pattern": "^\\d{3,4}$",
            "example": "123",
            "writeOnly": true
          },
          "cardPin": {
            "type": "string",
            "pattern": "^\\d{4}$",
            "example": "1234",
            "writeOnly": true,
            "description": "Card PIN (4 digits). Optional; defaults to 0000 when omitted."
          },
          "cardHolderName": {
            "type": "string",
            "minLength": 2,
            "maxLength": 80,
            "example": "Maria Perez"
          },
          "cardHolderId": {
            "type": "string",
            "example": "V12345678"
          },
          "accountType": {
            "type": "number",
            "enum": [
              0,
              10,
              20
            ],
            "example": 0,
            "description": "0 credit, 10 savings, 20 checking."
          },
          "cardType": {
            "type": "number",
            "enum": [
              1,
              2,
              3
            ],
            "example": 1,
            "description": "Provider card-brand code."
          },
          "externalRef": {
            "type": "string",
            "maxLength": 64,
            "example": "order-1042",
            "description": "Correlation value; not an idempotency key."
          },
          "merchantId": {
            "type": "string",
            "format": "uuid"
          },
          "applicationFeeVes": {
            "type": "string",
            "example": "50.00",
            "description": "Marketplace application fee in VES retained by the platform."
          },
          "applicationFeePercent": {
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "example": 10
          }
        },
        "required": [
          "cardNumber",
          "expirationMonth",
          "expirationYear",
          "cvv",
          "cardHolderName",
          "cardHolderId",
          "accountType",
          "cardType"
        ]
      },
      "PagoMovilVerifyDto": {
        "type": "object",
        "properties": {
          "usdAmount": {
            "type": "number",
            "minimum": 0.01,
            "maximum": 100000,
            "example": 25
          },
          "reference": {
            "type": "string",
            "minLength": 4,
            "maxLength": 32,
            "example": "12345678"
          },
          "dateMovement": {
            "type": "string",
            "format": "date",
            "example": "2026-07-20"
          },
          "externalRef": {
            "type": "string",
            "maxLength": 64,
            "example": "order-1042",
            "description": "Correlation value; not an idempotency key."
          },
          "debtorBankCode": {
            "type": "string",
            "example": "0102",
            "description": "Payer bank SIMF code. Required when the resolved provider is Sofitasa; ignored by R4/BNC."
          },
          "txType": {
            "type": "string",
            "enum": [
              "pago_movil",
              "transferencia",
              "debito_inmediato"
            ],
            "example": "transferencia",
            "description": "Instrument type for providers that need it (Sofitasa). Defaults to transferencia."
          }
        },
        "required": [
          "usdAmount",
          "reference"
        ]
      },
      "PayoutMethodResponseDto": {
        "type": "object",
        "properties": {
          "payoutMethodId": {
            "type": "string",
            "format": "uuid"
          },
          "bankCode": {
            "type": "string",
            "example": "0134"
          },
          "destination": {
            "type": "string",
            "description": "Masked phone destination, e.g. …5555"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending_verification",
              "verifying",
              "verified",
              "rejected"
            ]
          },
          "isDefault": {
            "type": "boolean"
          },
          "failureCode": {
            "type": "string",
            "nullable": true
          },
          "lockedUntil": {
            "type": "string",
            "nullable": true
          },
          "verifiedAt": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string"
          }
        },
        "required": [
          "payoutMethodId",
          "bankCode",
          "destination",
          "status",
          "isDefault"
        ]
      },
      "MerchantResponseDto": {
        "type": "object",
        "properties": {
          "merchantId": {
            "type": "string"
          },
          "accountId": {
            "type": "string",
            "example": "acct_3fd84b2d9ad14f74a2d90f2f56984db5"
          },
          "externalRef": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "maxLength": 20,
            "example": "Maria Perez"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending_verification",
              "verifying",
              "verified",
              "rejected"
            ],
            "description": "Mirrored from the default payout method"
          },
          "isActive": {
            "type": "boolean",
            "description": "When false, merchant cannot receive new payouts"
          },
          "autoPayoutEnabled": {
            "type": "boolean",
            "description": "When true, available balance is auto-paid to the default verified method."
          },
          "bankCode": {
            "type": "string",
            "description": "Default method bank code (compat)"
          },
          "destination": {
            "type": "string",
            "description": "Masked default method phone (compat)"
          },
          "payoutMethods": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PayoutMethodResponseDto"
            }
          },
          "message": {
            "type": "string",
            "description": "Present when the merchant has no payout methods yet (e.g. created without bankCode/phone)",
            "example": "No payout method exists. Add one with POST /v1/merchants/:id/payout-methods before verifying or paying out."
          },
          "failureCode": {
            "type": "string",
            "nullable": true
          },
          "lockedUntil": {
            "type": "string",
            "nullable": true,
            "description": "ISO timestamp; when set and in the future, verification is locked"
          },
          "deactivatedAt": {
            "type": "string",
            "nullable": true,
            "description": "ISO timestamp when the merchant was deactivated"
          },
          "createdAt": {
            "type": "string"
          },
          "verifiedAt": {
            "type": "string",
            "nullable": true
          },
          "ownerType": {
            "type": "string",
            "enum": [
              "tenant",
              "wallet"
            ],
            "description": "How the merchant was created."
          },
          "merchantType": {
            "type": "string",
            "nullable": true,
            "enum": [
              "INDIVIDUAL",
              "COMPANY"
            ]
          },
          "displayName": {
            "type": "string",
            "nullable": true
          },
          "walletUserId": {
            "type": "string",
            "nullable": true,
            "description": "VEX Wallet user id (`ownerType = \"wallet\"`)."
          },
          "rifNumber": {
            "type": "string",
            "nullable": true
          },
          "accountStatus": {
            "type": "string",
            "enum": [
              "active",
              "pending",
              "restricted",
              "rejected"
            ],
            "description": "VEX Pay-owned compliance lifecycle, independent of payout `status`."
          },
          "kybStatus": {
            "type": "string",
            "enum": [
              "not_required",
              "required",
              "pending",
              "verified",
              "rejected"
            ]
          },
          "restrictionReason": {
            "type": "string",
            "nullable": true
          },
          "activatedAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "capabilities": {
            "type": "object",
            "nullable": true,
            "description": "Effective payment capabilities (stored grant AND accountStatus = active). Null for merchants with no capabilities row."
          }
        },
        "required": [
          "merchantId",
          "accountId",
          "externalRef",
          "status",
          "isActive"
        ]
      },
      "MerchantListResponseDto": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MerchantResponseDto"
            }
          },
          "nextCursor": {
            "type": "string",
            "nullable": true,
            "description": "Pass as cursor on the next request when more pages exist"
          }
        },
        "required": [
          "items"
        ]
      },
      "MerchantAuditEventDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "event": {
            "type": "string",
            "example": "MERCHANT_UPDATED",
            "description": "SCREAMING_SNAKE lifecycle event, e.g. MERCHANT_CREATED | MERCHANT_ACTIVATED | RIF_SUBMITTED | CAPABILITY_ENABLED | MERCHANT_UPDATED | MERCHANT_RESTRICTED."
          },
          "actor": {
            "type": "string",
            "example": "wallet:usr_123",
            "description": "\"wallet:<sub>\" | \"system\" | \"platform:<sub>\"."
          },
          "data": {
            "type": "object",
            "nullable": true,
            "description": "Event-specific detail, e.g. { fields: [\"instagram\"] }."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "event",
          "actor",
          "createdAt"
        ]
      },
      "MerchantAuditEventListDto": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MerchantAuditEventDto"
            }
          }
        },
        "required": [
          "items"
        ]
      },
      "DeleteMerchantResponseDto": {
        "type": "object",
        "properties": {
          "deleted": {
            "type": "boolean",
            "example": true
          },
          "merchantId": {
            "type": "string",
            "format": "uuid"
          },
          "externalRef": {
            "type": "string",
            "example": "usr_7f3a"
          }
        },
        "required": [
          "deleted",
          "merchantId",
          "externalRef"
        ]
      },
      "PayoutMethodListResponseDto": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PayoutMethodResponseDto"
            }
          }
        },
        "required": [
          "items"
        ]
      },
      "VerifyStartResponseDto": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "example": "verifying"
          },
          "expiresAt": {
            "type": "string",
            "example": "2026-07-22T02:30:00Z"
          },
          "payoutMethodId": {
            "type": "string",
            "format": "uuid"
          }
        },
        "required": [
          "status",
          "expiresAt"
        ]
      },
      "VerifyConfirmResponseDto": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "example": "verified"
          },
          "payoutMethodId": {
            "type": "string",
            "format": "uuid"
          }
        },
        "required": [
          "status",
          "payoutMethodId"
        ]
      },
      "MerchantBalanceDto": {
        "type": "object",
        "properties": {
          "merchantId": {
            "type": "string",
            "format": "uuid"
          },
          "accountId": {
            "type": "string",
            "example": "acct_3fd84b2d9ad14f74a2d90f2f56984db5"
          },
          "tenantId": {
            "type": "string",
            "format": "uuid"
          },
          "pendingVes": {
            "type": "string",
            "example": "100.00"
          },
          "availableVes": {
            "type": "string",
            "example": "250.00"
          },
          "paidOutVes": {
            "type": "string",
            "example": "50.00"
          },
          "ledgerNetVes": {
            "type": "string",
            "example": "350.00"
          }
        },
        "required": [
          "merchantId",
          "accountId",
          "tenantId",
          "pendingVes",
          "availableVes",
          "paidOutVes",
          "ledgerNetVes"
        ]
      },
      "CreateMerchantDto": {
        "type": "object",
        "properties": {
          "externalRef": {
            "type": "string",
            "maxLength": 64,
            "example": "usr_7f3a…"
          },
          "name": {
            "type": "string",
            "maxLength": 20,
            "example": "Maria Perez"
          },
          "identification": {
            "type": "string",
            "example": "V12345678",
            "description": "V/E+8 or J/G+9"
          },
          "contactEmail": {
            "type": "string",
            "example": "maria@mail.com"
          },
          "contactPhone": {
            "type": "string",
            "example": "04141234567"
          },
          "bankCode": {
            "type": "string",
            "example": "0134",
            "description": "Optional 4-digit SIMF bank code for the first Pago Móvil payout method. Provide together with phone, or omit both to create a merchant shell with no payout method."
          },
          "phone": {
            "type": "string",
            "example": "04145555555",
            "description": "Optional 11-digit local Pago Móvil phone for the first payout method. Provide together with bankCode, or omit both."
          }
        },
        "required": [
          "externalRef",
          "name",
          "identification",
          "contactEmail",
          "contactPhone"
        ]
      },
      "CreatePayoutMethodDto": {
        "type": "object",
        "properties": {
          "bankCode": {
            "type": "string",
            "example": "0134",
            "description": "4-digit SIMF bank code"
          },
          "phone": {
            "type": "string",
            "example": "04145555555",
            "description": "11-digit local Pago Móvil phone"
          }
        },
        "required": [
          "bankCode",
          "phone"
        ]
      },
      "ConfirmMerchantVerifyDto": {
        "type": "object",
        "properties": {
          "amount1": {
            "type": "string",
            "example": "0.37",
            "description": "Exact two-decimal VES amount"
          },
          "amount2": {
            "type": "string",
            "example": "0.82",
            "description": "Exact two-decimal VES amount"
          }
        },
        "required": [
          "amount1",
          "amount2"
        ]
      },
      "CreateMerchantTransferDto": {
        "type": "object",
        "properties": {
          "amountVes": {
            "type": "string",
            "example": "1523.40",
            "description": "Exact two-decimal VES amount to move from platform float → seller pending."
          },
          "transferKey": {
            "type": "string",
            "maxLength": 64,
            "example": "xfer_bid_1042",
            "description": "Idempotency key for this transfer under the merchant."
          },
          "paymentId": {
            "type": "string",
            "format": "uuid",
            "description": "Optional funding payment correlation (does not enforce remaining-net)."
          }
        },
        "required": [
          "amountVes",
          "transferKey"
        ]
      },
      "UpdateMerchantDto": {
        "type": "object",
        "properties": {
          "isActive": {
            "type": "boolean",
            "description": "Soft off-switch for payouts. false = deactivated (history kept)."
          },
          "autoPayoutEnabled": {
            "type": "boolean",
            "description": "When true, a cron job automatically pays available seller balance to the default verified Pago Móvil method."
          }
        }
      },
      "PaymentLinkResponseDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "productId": {
            "type": "string",
            "format": "uuid"
          },
          "slug": {
            "type": "string",
            "example": "camiseta-vexpay"
          },
          "hostedCheckoutPath": {
            "type": "string",
            "example": "/pay/camiseta-vexpay",
            "description": "Path of the hosted checkout page."
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "disabled"
            ]
          },
          "allowQuantity": {
            "type": "boolean"
          },
          "maxQuantity": {
            "type": "number",
            "nullable": true
          },
          "redirectUrl": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "productId",
          "slug",
          "hostedCheckoutPath",
          "status",
          "allowQuantity",
          "createdAt"
        ]
      },
      "ProductResponseDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "imageUrl": {
            "type": "string",
            "nullable": true
          },
          "priceUsd": {
            "type": "string",
            "example": "20.00"
          },
          "active": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "links": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PaymentLinkResponseDto"
            }
          }
        },
        "required": [
          "id",
          "name",
          "priceUsd",
          "active",
          "createdAt",
          "updatedAt"
        ]
      },
      "ProductListResponseDto": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProductResponseDto"
            }
          },
          "nextCursor": {
            "type": "string",
            "nullable": true,
            "description": "Pass as ?cursor= for the next page."
          }
        },
        "required": [
          "items"
        ]
      },
      "PaymentLinkListResponseDto": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PaymentLinkResponseDto"
            }
          }
        },
        "required": [
          "items"
        ]
      },
      "CreateProductDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Camiseta VEXPay",
            "maxLength": 120
          },
          "description": {
            "type": "string",
            "maxLength": 2000
          },
          "imageUrl": {
            "type": "string",
            "example": "https://cdn.example/shirt.png"
          },
          "priceUsd": {
            "type": "string",
            "example": "20.00",
            "description": "Positive USD price, up to 2 decimals."
          },
          "active": {
            "type": "boolean",
            "default": true
          }
        },
        "required": [
          "name",
          "priceUsd"
        ]
      },
      "UpdateProductDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 120
          },
          "description": {
            "type": "string",
            "maxLength": 2000,
            "nullable": true
          },
          "imageUrl": {
            "type": "string",
            "nullable": true
          },
          "priceUsd": {
            "type": "string",
            "example": "25.00"
          },
          "active": {
            "type": "boolean"
          }
        }
      },
      "CreatePaymentLinkDto": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string",
            "description": "URL slug for the hosted checkout. Lowercase letters, digits, hyphens. Auto-generated from the product name when omitted.",
            "example": "camiseta-vexpay"
          },
          "allowQuantity": {
            "type": "boolean",
            "default": false,
            "description": "Let the buyer choose a quantity."
          },
          "maxQuantity": {
            "type": "number",
            "minimum": 1,
            "maximum": 999
          },
          "redirectUrl": {
            "type": "string",
            "description": "Where to send the buyer after a successful payment."
          }
        }
      },
      "UpdatePaymentLinkDto": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "active",
              "disabled"
            ]
          },
          "allowQuantity": {
            "type": "boolean"
          },
          "maxQuantity": {
            "type": "number",
            "minimum": 1,
            "maximum": 999,
            "nullable": true
          },
          "redirectUrl": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "NotificationTestResponseDto": {
        "type": "object",
        "properties": {
          "sent": {
            "type": "boolean",
            "example": true
          },
          "event": {
            "type": "string",
            "example": "notification.test"
          },
          "tenantId": {
            "type": "string",
            "format": "uuid"
          }
        },
        "required": [
          "sent",
          "event",
          "tenantId"
        ]
      }
    }
  }
}
