{
  "info": {
    "_postman_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "name": "VEXPay — Marketplace Settlement (Split)",
    "description": "End-to-end local flow to test marketplace settlement / split payouts.\n\n**Flow**\n1. Merchants — register + verify payout methods (skip if already done)\n2. Collect — fund tenant float via Débito Inmediato (happy path `monto` 100.00)\n3. Settle — single payout or batch split\n4. USDT — balance, deposit addresses, hosted USDT checkout, USDT payouts\n5. Convert VES → USDT — quote, convert, track or cancel\n\n**Auth:** `x-api-key` collection/environment variable. Default `baseUrl` is `https://api.pay.vexwallet.co` — replace `apiKey` with your tenant key.\n\n**Docs:** /postman · /marketplace-settlement · /debito-inmediato",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "variable": [
    { "key": "baseUrl", "value": "https://api.pay.vexwallet.co" },
    { "key": "apiKey", "value": "vk_live_replace_me" },
    { "key": "merchantId", "value": "" },
    { "key": "merchantId2", "value": "" },
    { "key": "merchantExternalRef", "value": "seller_split_demo_001" },
    { "key": "merchantExternalRef2", "value": "partner_split_demo_001" },
    { "key": "payoutMethodId", "value": "" },
    { "key": "payoutMethodId2", "value": "" },
    { "key": "operationId", "value": "" },
    { "key": "paymentId", "value": "" },
    { "key": "paymentExternalRef", "value": "bid_split_demo_001" },
    { "key": "payoutId", "value": "" },
    { "key": "payoutExternalRef", "value": "po_split_smoke_001" },
    { "key": "batchExternalRef", "value": "settle_split_demo_001" },
    { "key": "verifyAmount1", "value": "0.37" },
    { "key": "verifyAmount2", "value": "0.82" },
    { "key": "usdtCustomerRef", "value": "user_123" },
    { "key": "usdtCheckoutSessionId", "value": "" },
    { "key": "usdtIdempotencyKey", "value": "" },
    { "key": "usdtPayoutId", "value": "" },
    { "key": "conversionQuoteId", "value": "" },
    { "key": "conversionId", "value": "" },
    { "key": "conversionIdempotencyKey", "value": "" }
  ],
  "auth": {
    "type": "apikey",
    "apikey": [
      { "key": "key", "value": "x-api-key", "type": "string" },
      { "key": "value", "value": "{{apiKey}}", "type": "string" },
      { "key": "in", "value": "header", "type": "string" }
    ]
  },
  "item": [
    {
      "name": "0. Helpers",
      "item": [
        {
          "name": "List banks",
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{baseUrl}}/v1/banks",
            "description": "Use 4-digit SIMF (`code` padded, e.g. `0134`) as `banco` on Débito Inmediato and as `bankCode` on merchant payout methods."
          }
        },
        {
          "name": "Get FX quote",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/quote?usdAmount=12.50",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "quote"
              ],
              "query": [
                { "key": "usdAmount", "value": "12.50" }
              ]
            },
            "description": "Optional: preview VES for a USD amount. Débito Inmediato `monto` is already in Bs. (VES)."
          }
        }
      ]
    },
    {
      "name": "1. Merchants",
      "item": [
        {
          "name": "List merchants",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const json = pm.response.json();",
                  "if (json.items && json.items.length > 0) {",
                  "  const verified = json.items.filter(m => m.status === 'verified' && m.isActive);",
                  "  if (verified[0]) pm.collectionVariables.set('merchantId', verified[0].merchantId);",
                  "  if (verified[1]) pm.collectionVariables.set('merchantId2', verified[1].merchantId);",
                  "  if (verified[0]) console.log('merchantId =', verified[0].merchantId);",
                  "  if (verified[1]) console.log('merchantId2 =', verified[1].merchantId);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/merchants?limit=25",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "merchants"
              ],
              "query": [
                { "key": "limit", "value": "25" }
              ]
            },
            "description": "Lists merchants. Test script auto-fills `merchantId` / `merchantId2` from the first two verified active merchants."
          }
        },
        {
          "name": "Create merchant (seller)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const json = pm.response.json();",
                  "if (json.merchantId) {",
                  "  pm.collectionVariables.set('merchantId', json.merchantId);",
                  "  console.log('merchantId =', json.merchantId);",
                  "}",
                  "if (json.externalRef) {",
                  "  pm.collectionVariables.set('merchantExternalRef', json.externalRef);",
                  "}",
                  "if (json.payoutMethods && json.payoutMethods[0]) {",
                  "  pm.collectionVariables.set('payoutMethodId', json.payoutMethods[0].payoutMethodId);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"externalRef\": \"seller_split_demo_001\",\n  \"name\": \"Maria Perez\",\n  \"identification\": \"V12345678\",\n  \"contactEmail\": \"maria@mail.com\",\n  \"contactPhone\": \"04141234567\",\n  \"bankCode\": \"0134\",\n  \"phone\": \"04145555555\"\n}"
            },
            "url": "{{baseUrl}}/v1/merchants",
            "description": "Registers a merchant and first Pago Móvil payout method. Replace identification/phone with real values. Saves `merchantId`."
          }
        },
        {
          "name": "Create merchant (partner)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const json = pm.response.json();",
                  "if (json.merchantId) {",
                  "  pm.collectionVariables.set('merchantId2', json.merchantId);",
                  "  console.log('merchantId2 =', json.merchantId);",
                  "}",
                  "if (json.externalRef) {",
                  "  pm.collectionVariables.set('merchantExternalRef2', json.externalRef);",
                  "}",
                  "if (json.payoutMethods && json.payoutMethods[0]) {",
                  "  pm.collectionVariables.set('payoutMethodId2', json.payoutMethods[0].payoutMethodId);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"externalRef\": \"partner_split_demo_001\",\n  \"name\": \"Jose Partner\",\n  \"identification\": \"V87654321\",\n  \"contactEmail\": \"jose@mail.com\",\n  \"contactPhone\": \"04149876543\",\n  \"bankCode\": \"0102\",\n  \"phone\": \"04141234567\"\n}"
            },
            "url": "{{baseUrl}}/v1/merchants",
            "description": "Second verified merchant needed for a real batch split. Saves `merchantId2`."
          }
        },
        {
          "name": "Get merchant",
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{baseUrl}}/v1/merchants/{{merchantId}}",
            "description": "Fetch by gateway UUID. Prefer **Get merchant by externalRef** when your system stores the seller/user id instead of `merchantId`."
          }
        },
        {
          "name": "Get merchant by externalRef",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const json = pm.response.json();",
                  "if (json.merchantId) {",
                  "  pm.collectionVariables.set('merchantId', json.merchantId);",
                  "  console.log('merchantId =', json.merchantId, 'externalRef =', json.externalRef);",
                  "}",
                  "if (json.payoutMethods && json.payoutMethods[0]) {",
                  "  pm.collectionVariables.set('payoutMethodId', json.payoutMethods[0].payoutMethodId);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/merchants?externalRef={{merchantExternalRef}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "merchants"
              ],
              "query": [
                {
                  "key": "externalRef",
                  "value": "{{merchantExternalRef}}",
                  "description": "Your tenant-scoped seller/user id from POST /v1/merchants"
                }
              ]
            },
            "description": "Look up a merchant for the authenticated tenant by the `externalRef` you registered (unique per tenant).\n\n- Auth: `x-api-key` scopes the search to that tenant only.\n- Returns the same single-merchant detail as GET /v1/merchants/:id (including `payoutMethods[]`).\n- 404 if the ref does not exist under this tenant.\n- Without `externalRef`, GET /v1/merchants returns a paginated list instead.\n\nSet `merchantExternalRef` (default matches Create merchant seller: `seller_split_demo_001`). Partner: use `merchantExternalRef2`."
          }
        },
        {
          "name": "Get merchant (partner) by externalRef",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const json = pm.response.json();",
                  "if (json.merchantId) {",
                  "  pm.collectionVariables.set('merchantId2', json.merchantId);",
                  "  console.log('merchantId2 =', json.merchantId, 'externalRef =', json.externalRef);",
                  "}",
                  "if (json.payoutMethods && json.payoutMethods[0]) {",
                  "  pm.collectionVariables.set('payoutMethodId2', json.payoutMethods[0].payoutMethodId);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/merchants?externalRef={{merchantExternalRef2}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "merchants"
              ],
              "query": [
                {
                  "key": "externalRef",
                  "value": "{{merchantExternalRef2}}",
                  "description": "Partner merchant externalRef"
                }
              ]
            },
            "description": "Same as **Get merchant by externalRef**, for the partner seller (`partner_split_demo_001`). Saves `merchantId2` / `payoutMethodId2`."
          }
        },
        {
          "name": "List payout methods",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const json = pm.response.json();",
                  "const items = json.items || json;",
                  "if (Array.isArray(items) && items[0]) {",
                  "  pm.collectionVariables.set('payoutMethodId', items[0].payoutMethodId);",
                  "  console.log('payoutMethodId =', items[0].payoutMethodId);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{baseUrl}}/v1/merchants/{{merchantId}}/payout-methods",
            "description": "Saves the first method as `payoutMethodId`."
          }
        },
        {
          "name": "Add payout method",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const json = pm.response.json();",
                  "if (json.payoutMethodId) {",
                  "  pm.collectionVariables.set('payoutMethodId2', json.payoutMethodId);",
                  "  pm.collectionVariables.set('payoutMethodId', json.payoutMethodId);",
                  "  console.log('Created payoutMethodId =', json.payoutMethodId, '(also saved as payoutMethodId2)');",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"bankCode\": \"0105\",\n  \"phone\": \"04145551234\"\n}"
            },
            "url": "{{baseUrl}}/v1/merchants/{{merchantId}}/payout-methods",
            "description": "Register another Pago Móvil destination on an existing merchant.\n\n1. Set `merchantId` (from Register / Get merchant).\n2. Edit `bankCode` + `phone` in the body to the real Pago Móvil destination.\n3. Send — saves the new id into `payoutMethodId` and `payoutMethodId2`.\n4. Run **Start verify payout method** → **Confirm verify payout method**.\n\nStarts as `pending_verification`. Duplicate bankCode+phone → 409 `payout_method_exists`."
          }
        },
        {
          "name": "Start verify payout method",
          "request": {
            "method": "POST",
            "header": [],
            "url": "{{baseUrl}}/v1/merchants/{{merchantId}}/payout-methods/{{payoutMethodId}}/verify/start",
            "description": "Triggers micro-deposits (Crédito Inmediato) for `payoutMethodId` (set by List or Add). Merchant reads amount1/amount2 from their phone (never returned by API)."
          }
        },
        {
          "name": "Confirm verify payout method",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount1\": \"{{verifyAmount1}}\",\n  \"amount2\": \"{{verifyAmount2}}\"\n}"
            },
            "url": "{{baseUrl}}/v1/merchants/{{merchantId}}/payout-methods/{{payoutMethodId}}/verify",
            "description": "Set `verifyAmount1` / `verifyAmount2` collection vars to the exact 0.XX amounts from the merchant's phone."
          }
        },
        {
          "name": "Set default payout method",
          "request": {
            "method": "POST",
            "header": [],
            "url": "{{baseUrl}}/v1/merchants/{{merchantId}}/payout-methods/{{payoutMethodId}}/default",
            "description": "Marks `payoutMethodId` as default. Top-level merchant bankCode/destination mirror it; payouts without payoutMethodId prefer the default verified method."
          }
        },
        {
          "name": "Delete payout method",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": "{{baseUrl}}/v1/merchants/{{merchantId}}/payout-methods/{{payoutMethodId}}",
            "description": "Removes the method in `payoutMethodId` (204). If it was default, another method is promoted (verified preferred). Historical payouts keep bank/phone snapshots.\n\nTip: run **List payout methods** first, or paste the id you want to remove into the `payoutMethodId` collection variable."
          }
        },
        {
          "name": "Deactivate merchant",
          "request": {
            "method": "PATCH",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"isActive\": false\n}"
            },
            "url": "{{baseUrl}}/v1/merchants/{{merchantId}}",
            "description": "Soft off-switch. Blocks new payouts but keeps history and externalRef. Re-activate with `{ \"isActive\": true }` (no re-verification).\n\nUse this when the merchant already has payout history — DELETE will return 409 `merchant_has_payouts`."
          }
        },
        {
          "name": "Delete merchant",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": "{{baseUrl}}/v1/merchants/{{merchantId}}",
            "description": "Hard-deletes the merchant and its payout methods when there is **no payout history**. Frees `externalRef` for re-registration.\n\n**200** `{ \"deleted\": true, \"merchantId\", \"externalRef\" }`\n**409** `{ \"error\": \"merchant_has_payouts\", \"payoutCount\": N }` — use **Deactivate merchant** instead.\n**404** merchant not found for this tenant.\n\nDocs: /merchants-payouts#delete-merchant"
          }
        },
        {
          "name": "Start verify (legacy default method)",
          "request": {
            "method": "POST",
            "header": [],
            "url": "{{baseUrl}}/v1/merchants/{{merchantId}}/verify/start",
            "description": "Legacy shortcut that verifies the merchant's default payout method."
          }
        },
        {
          "name": "Confirm verify (legacy default method)",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount1\": \"{{verifyAmount1}}\",\n  \"amount2\": \"{{verifyAmount2}}\"\n}"
            },
            "url": "{{baseUrl}}/v1/merchants/{{merchantId}}/verify"
          }
        }
      ]
    },
    {
      "name": "2. Collect (fund float)",
      "item": [
        {
          "name": "Debit OTP (request bank code)",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"banco\": \"0102\",\n  \"monto\": 100.00,\n  \"telefono\": \"584121234567\",\n  \"cedula\": \"V87654321\"\n}"
            },
            "url": "{{baseUrl}}/v1/payments/debit/otp",
            "description": "Asks the payer bank to SMS a 6–8 digit OTP.\n\n`banco` = 4-digit SIMF (from GET /v1/banks). `telefono` = 58 + 10 digits. `monto` is Bs. (VES). Happy-path sample uses 100.00 so a small platform fixed USD fee still leaves float for a Bs 10 payout.\n\nTypical success: `code` 202. Then collect the OTP from the customer and run Débito Inmediato."
          }
        },
        {
          "name": "Débito Inmediato",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const json = pm.response.json();",
                  "if (json.paymentId) {",
                  "  pm.collectionVariables.set('paymentId', json.paymentId);",
                  "  console.log('paymentId =', json.paymentId, 'code =', json.code);",
                  "}",
                  "const opId = json.Id || json.id;",
                  "if (json.code === 'AC00' && opId) {",
                  "  pm.collectionVariables.set('operationId', opId);",
                  "  console.log('AC00 pending — operationId =', opId);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"banco\": \"0102\",\n  \"monto\": 100.00,\n  \"telefono\": \"584121234567\",\n  \"cedula\": \"V87654321\",\n  \"nombre\": \"Jose Partner\",\n  \"otp\": \"123456\",\n  \"concepto\": \"Fund float demo\",\n  \"externalRef\": \"{{paymentExternalRef}}\"\n}"
            },
            "url": "{{baseUrl}}/v1/payments/debit",
            "description": "Replace `otp` with the real bank SMS code. Use the same payer fields as Debit OTP.\n\n- `ACCP` — accepted; float funded; `payment.completed` webhook\n- `AC00` — pending; gateway auto-polls; optional manual poll via GET /v1/payments/operations/:id\n\nOn success, tenant available balance increases by `monto` minus platform ledger fees. With Local Dev fees 2.5% + $0.05 fixed and reserve 0, expect roughly Bs 63–66 available after a 100.00 collect."
          }
        },
        {
          "name": "Poll pending operation (AC00)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const json = pm.response.json();",
                  "console.log('operation poll code =', json.code, 'reference =', json.reference);",
                  "if (json.paymentId) {",
                  "  pm.collectionVariables.set('paymentId', json.paymentId);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{baseUrl}}/v1/payments/operations/{{operationId}}",
            "description": "Optional. Only needed when Débito Inmediato returned `AC00` and you want a manual status check. Prefer waiting for `payment.completed` / `payment.failed` webhooks."
          }
        },
        {
          "name": "Get payment by externalRef",
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{baseUrl}}/v1/payments/by-ref/{{paymentExternalRef}}",
            "description": "Confirm `method` is DEBITO_INMEDIATO and `status` is completed before settling payouts."
          }
        },
        {
          "name": "Get payment by id",
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{baseUrl}}/v1/payments/{{paymentId}}"
          }
        }
      ]
    },
    {
      "name": "3. Settle (payouts / split)",
      "item": [
        {
          "name": "Single payout (smoke test)",
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const stamp = Date.now().toString(36);",
                  "pm.collectionVariables.set('payoutExternalRef', 'po_split_smoke_' + stamp);"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const json = pm.response.json();",
                  "if (json.payoutId) {",
                  "  pm.collectionVariables.set('payoutId', json.payoutId);",
                  "  console.log('payoutId =', json.payoutId, 'status =', json.status);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"merchantId\": \"{{merchantId}}\",\n  \"paymentId\": \"{{paymentId}}\",\n  \"monto\": \"10.00\",\n  \"concepto\": \"Split smoke test\",\n  \"externalRef\": \"{{payoutExternalRef}}\"\n}"
            },
            "url": "{{baseUrl}}/v1/payouts",
            "description": "Pays one verified merchant linked to the funding payment. `monto` must be exact two-decimal VES string. `paymentId` is set by the Débito collect step — omit it only for float-only payouts.\n\nPre-request script generates a unique `externalRef` each run. Optional: add `\"payoutMethodId\": \"{{payoutMethodId}}\"`."
          }
        },
        {
          "name": "Batch split (multi-merchant)",
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const stamp = Date.now().toString(36);",
                  "pm.collectionVariables.set('batchExternalRef', 'settle_split_' + stamp);",
                  "pm.collectionVariables.set('payoutExternalRef', 'po_seller_' + stamp);",
                  "pm.variables.set('partnerExternalRef', 'po_partner_' + stamp);"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"externalRef\": \"{{batchExternalRef}}\",\n  \"paymentId\": \"{{paymentId}}\",\n  \"items\": [\n    {\n      \"merchantId\": \"{{merchantId}}\",\n      \"monto\": \"40.00\",\n      \"concepto\": \"Seller net\",\n      \"externalRef\": \"{{payoutExternalRef}}\"\n    },\n    {\n      \"merchantId\": \"{{merchantId2}}\",\n      \"monto\": \"30.00\",\n      \"concepto\": \"Partner share\",\n      \"externalRef\": \"{{partnerExternalRef}}\"\n    }\n  ]\n}"
            },
            "url": "{{baseUrl}}/v1/payouts/batch",
            "description": "Splits settlement across multiple verified merchants against the funding `paymentId`. Remaining net = vesAmount − feeVes − PENDING/COMPLETED legs. Results are **per item** (not all-or-nothing).\n\n1. Run collect so `paymentId` is set, then **List merchants** for `merchantId` / `merchantId2`\n2. Ensure available balance ≥ sum of montos and sum ≤ remaining for that payment\n3. Adjust montos to fit (defaults assume Débito ~100.00 after platform fee)\n\nMarketplace app fee = money you do **not** include in any item."
          }
        },
        {
          "name": "List payouts",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/payouts?status=completed&limit=25",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "payouts"
              ],
              "query": [
                { "key": "status", "value": "completed" },
                { "key": "limit", "value": "25" }
              ]
            }
          }
        },
        {
          "name": "Get payout by externalRef",
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{baseUrl}}/v1/payouts/by-ref/{{payoutExternalRef}}"
          }
        },
        {
          "name": "Get payout by id",
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{baseUrl}}/v1/payouts/{{payoutId}}"
          }
        }
      ]
    },
    {
      "name": "4. USDT",
      "description": "USDT settles in USDT — never converted to VES — into your VEXPay USDT balance. USDT must be enabled on your account; otherwise these return 403 `method_not_allowed`.\n\n**Pricing:** pay-ins 2.5 % + 0.50 USDT (capped at the amount received); payouts charge the network fee shown by *List networks*.\n\n**Webhooks:** `payment.completed` for pay-ins (with `amountUsdt`, `feeUsdt`, `network`, `txHashes`, `customerRef`, `underpaid`), `payout.completed` / `payout.failed` for payouts (with `txHash` or `failureReason`).\n\n**Docs:** /usdt",
      "item": [
        {
          "name": "Get USDT balance",
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{baseUrl}}/v1/crypto/balance",
            "description": "Available and pending USDT, plus payouts in flight."
          }
        },
        {
          "name": "List networks",
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{baseUrl}}/v1/crypto/networks?amountUsdt=50.00",
            "description": "Enabled networks with `receiveEnabled`, `payoutEnabled`, the payout fee, the minimum payout, whether a memo/tag is required, and whether a payout of `amountUsdt` can be sent now."
          }
        },
        {
          "name": "Get or create deposit address",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "url": "{{baseUrl}}/v1/crypto/deposit-addresses",
            "description": "Static address per customer and network — calling again returns the same address. Every deposit fires `payment.completed` with this `customerRef`. For TON, send the returned `tag` as the memo.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"customerRef\": \"{{usdtCustomerRef}}\",\n  \"network\": \"BEP20\"\n}"
            }
          }
        },
        {
          "name": "Create USDT checkout session",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "url": "{{baseUrl}}/v1/checkout/sessions",
            "description": "Hosted checkout limited to USDT: redirect the buyer to `url`; the page shows the deposit address on the network they choose. The `payment.completed` webhook carries `checkoutSession.reference` so you can match your order. `underpaid: true` means less than `amountUsd` arrived — do not fulfil.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amountUsd\": 25,\n  \"reference\": \"order_1042\",\n  \"description\": \"Order #1042\",\n  \"methods\": [\n    \"usdt\"\n  ],\n  \"successUrl\": \"https://shop.example/gracias\",\n  \"cancelUrl\": \"https://shop.example/checkout\",\n  \"expiresInMinutes\": 60\n}"
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const json = pm.response.json();",
                  "if (json.id) {",
                  "  pm.collectionVariables.set('usdtCheckoutSessionId', json.id);",
                  "  console.log('checkout url =', json.url);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Get checkout session",
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{baseUrl}}/v1/checkout/sessions/{{usdtCheckoutSessionId}}",
            "description": "`status` is `paid` once the transfer is confirmed; `paymentId` points to the payment."
          }
        },
        {
          "name": "Create USDT payout",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "url": "{{baseUrl}}/v1/crypto/payouts",
            "description": "Debits `amountUsdt` + network fee from your USDT balance. `idempotencyKey` makes retries safe (same key + same body replays with 200). Payouts over your limits wait for review (`pending`). A payout to one of your own deposit addresses settles instantly with no network fee.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"network\": \"POLYGON\",\n  \"address\": \"0x0000000000000000000000000000000000000000\",\n  \"amountUsdt\": \"10.00\",\n  \"idempotencyKey\": \"{{usdtIdempotencyKey}}\",\n  \"customerRef\": \"{{usdtCustomerRef}}\"\n}"
            }
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.collectionVariables.set('usdtIdempotencyKey', 'usdt_po_' + Date.now().toString(36));"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const json = pm.response.json();",
                  "if (json.id) {",
                  "  pm.collectionVariables.set('usdtPayoutId', json.id);",
                  "  console.log('usdtPayoutId =', json.id, 'status =', json.status);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Get USDT payout",
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{baseUrl}}/v1/crypto/payouts/{{usdtPayoutId}}",
            "description": "`processing` → `completed` (with `txHash`) or `failed` (amount + fee refunded, with `failureReason`)."
          }
        }
      ]
    },
    {
      "name": "5. Convert VES / COP → USDT",
      "description": "Turn available VES or COP into your USDT balance (COP also needs COP enabled). On for every account with USDT enabled (403 `conversions_not_enabled` otherwise). With a test key, conversions complete immediately.",
      "item": [
        {
          "name": "Quote (by VES amount)",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "url": "{{baseUrl}}/v1/conversions/quotes",
            "description": "Locks a rate for 60 seconds: market USDT/VES rate plus your spread. Send `sourceAmountVes` or `targetAmountUsdt` (exactly one). USDT rounds down, VES rounds up.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"sourceAmountVes\": \"10000.00\"\n}"
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const json = pm.response.json();",
                  "if (json.id) {",
                  "  pm.collectionVariables.set('conversionQuoteId', json.id);",
                  "  console.log('quote', json.id, json.sourceAmountVes, 'VES →', json.targetAmountUsdt, 'USDT at', json.rate);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Quote (by USDT amount)",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "url": "{{baseUrl}}/v1/conversions/quotes",
            "description": "Same as above, fixing the USDT you want to receive.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"targetAmountUsdt\": \"50.00\"\n}"
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const json = pm.response.json();",
                  "if (json.id) pm.collectionVariables.set('conversionQuoteId', json.id);"
                ]
              }
            }
          ]
        },
        {
          "name": "Quote (by COP amount)",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "url": "{{baseUrl}}/v1/conversions/quotes",
            "description": "Colombian pesos: market USDT/COP rate plus your COP spread. `sourceAmount` is whole pesos (or send `targetAmountUsdt`). Needs COP enabled. COP rounds up to the peso, USDT down to the cent.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"sourceCurrency\": \"COP\",\n  \"sourceAmount\": \"1000000\"\n}"
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const json = pm.response.json();",
                  "if (json.id) {",
                  "  pm.collectionVariables.set('conversionQuoteId', json.id);",
                  "  console.log('quote', json.id, json.sourceAmount, json.sourceCurrency, '→', json.targetAmountUsdt, 'USDT at', json.rate);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Convert (accept quote)",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" },
              { "key": "Idempotency-Key", "value": "{{conversionIdempotencyKey}}" }
            ],
            "url": "{{baseUrl}}/v1/conversions",
            "description": "Debits the VES from your available balance and returns a `PENDING` conversion (test mode: `COMPLETED`). 410 `quote_expired` after 60 s; 409 `quote_used` if already accepted.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"quoteId\": \"{{conversionQuoteId}}\",\n  \"reference\": \"postman-conversion\"\n}"
            }
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.collectionVariables.set('conversionIdempotencyKey', 'conv_' + Date.now().toString(36));"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const json = pm.response.json();",
                  "if (json.id) {",
                  "  pm.collectionVariables.set('conversionId', json.id);",
                  "  console.log('conversionId =', json.id, 'status =', json.status);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Get conversion",
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{baseUrl}}/v1/conversions/{{conversionId}}"
          }
        },
        {
          "name": "List pending conversions",
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{baseUrl}}/v1/conversions?status=PENDING&limit=25",
            "description": "Newest first; pass `nextCursor` as `cursor` for the next page."
          }
        },
        {
          "name": "Cancel conversion",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "url": "{{baseUrl}}/v1/conversions/{{conversionId}}/cancel",
            "description": "Only while `PENDING`; the VES or COP returns to your available balance (409 `conversion_not_cancelable` otherwise)."
          }
        },
        {
          "name": "Get conversion settings",
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{baseUrl}}/v1/conversions/settings",
            "description": "Your spreads, minimum, daily limits, which currencies you can convert from, and COP auto-convert."
          }
        },
        {
          "name": "Turn on COP auto-convert (50%)",
          "request": {
            "method": "PATCH",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "url": "{{baseUrl}}/v1/conversions/settings",
            "description": "Converts 50% of each completed COP payment (after the fee) to USDT. Send 0 to turn it off. Only `autoConvert` can be changed through the API.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"autoConvert\": { \"COP\": { \"percent\": 50 } }\n}"
            }
          }
        }
      ]
    }
  ]
}
