{
  "info": {
    "_postman_id": "afc012eb-f182-5be3-a3e3-267095c7fdcc",
    "name": "Finomesh Merchant API",
    "description": "The Finomesh merchant API — payments, verification, transaction inquiry, the public payment endpoints, and the signed cashout API.\n\n## Setup\n\n1. Import this file — it is the whole thing, no environment file needed. It points at **staging** (`baseUrl`); build and test there first.\n2. Open the collection's **Variables** tab and set `apiKey` (dashboard → your gateway). For the Cashout folder also set `cashoutSecret`.\n3. Run the **Sandbox walkthrough** folder: create → read → simulate → verify, with no blockchain involved.\n\nThose three — `baseUrl`, `apiKey`, `cashoutSecret` — are the only settings. Per-request values such as `callbackUrl`, `webhookUrl` and the cashout `address` are example values in each request body: edit them there.\n\n## Keep your secrets local\n\nEnter `apiKey` and `cashoutSecret` in the **Current value** column only. The *Initial value* is synced to your Postman workspace and shared with anyone in it.\n\n## IP allowlist\n\nCashout requests and API-mode payments are only accepted from allowlisted source IPs. Use the Postman desktop app (or the web app with the Desktop Agent) and allowlist your own IP in the dashboard. Requests through Postman's Cloud Agent come from Postman's servers and are refused with `403`.\n\n## Production\n\nSet `baseUrl` to `https://api.finomesh.com/api/v1` and `apiKey` to your production key. Every request then hits the live API — cashout requests there move real funds.\n\nFull documentation: https://doc.finomesh.com",
    "version": "1.0.0",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "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": "Sandbox walkthrough",
      "description": "The full payment loop against a sandbox payment, in order: **create → read → simulate → verify**. Run the folder with the Collection Runner, or send the four requests one by one.\n\nNeeds only the `apiKey` collection variable. Nothing touches a blockchain.",
      "item": [
        {
          "name": "Create sandbox payment",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "{",
                  "  pm.test('HTTP 201', () => pm.response.to.have.status(201));",
                  "  const data = (pm.response.json() || {}).data || {};",
                  "  if (data.paymentUid) pm.collectionVariables.set('paymentId', data.paymentUid);",
                  "  // API-mode creates inline the payment object — capture its first offer too.",
                  "  const offers = (data.payment && data.payment.offers) || [];",
                  "  if (offers.length) pm.collectionVariables.set('offerId', offers[0].id);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"currencyCode\": \"USD\",\n  \"amount\": \"49.99\",\n  \"callbackUrl\": \"https://shop.example.com/payment/result\",\n  \"webhookUrl\": \"https://shop.example.com/api/finomesh-webhook\",\n  \"isSandbox\": true\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/payments",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "payments"
              ]
            },
            "description": "Creates a **sandbox** payment: no deposit address, no chain watched. Drive its outcome with *Simulate sandbox outcome*.\n\nSaves `paymentId` for the next requests. Open `paymentUrl` from the response to see the hosted checkout with its simulation buttons.\n\nReplace the example `callbackUrl` / `webhookUrl` with your own result page and webhook endpoint.\n\nDocs: https://doc.finomesh.com/testing/sandbox-overview"
          }
        },
        {
          "name": "Get payment",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "{",
                  "  pm.test('HTTP 200', () => pm.response.to.have.status(200));",
                  "  const data = (pm.response.json() || {}).data || {};",
                  "  const offers = data.offers || [];",
                  "  if (offers.length) pm.collectionVariables.set('offerId', offers[0].id);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/public/payments/{{paymentId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "public",
                "payments",
                "{{paymentId}}"
              ]
            },
            "description": "The redacted payment projection the checkout renders from — amounts, status, and `offers[]`. No API key.\n\nSaves the first offer as `offerId`.\n\n**API-mode payments:** only reachable from an allowlisted source IP (`403` otherwise).\n\nDocs: https://doc.finomesh.com/api/public-endpoints"
          }
        },
        {
          "name": "[Sandbox only] Simulate outcome",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "{",
                  "  pm.test('HTTP 200', () => pm.response.to.have.status(200));",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"outcome\": \"success\",\n  \"offerId\": \"{{offerId}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/public/payments/{{paymentId}}/sandbox/simulate",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "public",
                "payments",
                "{{paymentId}}",
                "sandbox",
                "simulate"
              ]
            },
            "description": "**Sandbox-only** — rejected with `422` on a real (non-sandbox) payment. Drives a sandbox payment into a terminal state. `outcome` is one of `success`, `acceptable`, `mismatch`, `expire`.\n\n`acceptable` and `mismatch` need a payment created with a non-zero tolerance (`overAcceptableDiff` / `underAcceptableDiff`) — otherwise this also returns `422`.\n\nEverything downstream fires exactly as in production: callback redirect, signed webhook, verify.\n\nDocs: https://doc.finomesh.com/api/public-endpoints"
          }
        },
        {
          "name": "Verify payment",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "{",
                  "  pm.test('HTTP 200', () => pm.response.to.have.status(200));",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/payments/{{paymentId}}/verify",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "payments",
                "{{paymentId}}",
                "verify"
              ]
            },
            "description": "Should now report the outcome you simulated.\n\nThe **authoritative** outcome of a payment — fulfil from this response, never from the callback or webhook alone.\n\nIdempotent. `PENDING` is a no-op; `SUCCESS` / `ACCEPTABLE` fulfil; `MISMATCH` needs review; `EXPIRED` cancels.\n\nDocs: https://doc.finomesh.com/api/verify-payment"
          }
        }
      ]
    },
    {
      "name": "Payments",
      "description": "The API-key surface: create payments, verify their outcome, and submit a transaction inquiry. Every request carries `X-Api-Key: {{apiKey}}` (collection-level auth).\n\nDocs: https://doc.finomesh.com/api/overview",
      "item": [
        {
          "name": "Create payment (hosted)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "{",
                  "  pm.test('HTTP 201', () => pm.response.to.have.status(201));",
                  "  const data = (pm.response.json() || {}).data || {};",
                  "  if (data.paymentUid) pm.collectionVariables.set('paymentId', data.paymentUid);",
                  "  // API-mode creates inline the payment object — capture its first offer too.",
                  "  const offers = (data.payment && data.payment.offers) || [];",
                  "  if (offers.length) pm.collectionVariables.set('offerId', offers[0].id);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"currencyCode\": \"USD\",\n  \"amount\": \"49.99\",\n  \"callbackUrl\": \"https://shop.example.com/payment/result\",\n  \"webhookUrl\": \"https://shop.example.com/api/finomesh-webhook\",\n  \"callbackParams\": {\n    \"orderId\": \"ORD-1042\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/payments",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "payments"
              ]
            },
            "description": "Creates a real payment and returns `paymentUid` + `paymentUrl` (the hosted checkout). Saves `paymentId`.\n\n`callbackUrl` is required in hosted mode; `webhookUrl` is optional (delete it to send no webhook). Replace both examples with your own URLs. Add `\"isSandbox\": true` to test without a chain.\n\nDocs: https://doc.finomesh.com/api/create-payment"
          }
        },
        {
          "name": "Create payment (API mode)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "{",
                  "  pm.test('HTTP 201', () => pm.response.to.have.status(201));",
                  "  const data = (pm.response.json() || {}).data || {};",
                  "  if (data.paymentUid) pm.collectionVariables.set('paymentId', data.paymentUid);",
                  "  // API-mode creates inline the payment object — capture its first offer too.",
                  "  const offers = (data.payment && data.payment.offers) || [];",
                  "  if (offers.length) pm.collectionVariables.set('offerId', offers[0].id);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"currencyCode\": \"USD\",\n  \"amount\": \"49.99\",\n  \"checkoutMode\": \"API\",\n  \"webhookUrl\": \"https://shop.example.com/api/finomesh-webhook\",\n  \"webhookParams\": {\n    \"orderId\": \"ORD-1042\"\n  },\n  \"timeoutSeconds\": 3600,\n  \"txFeePayer\": \"CUSTOMER\",\n  \"commissionFeePayer\": \"CUSTOMER\",\n  \"overAcceptableDiff\": \"0.5\",\n  \"underAcceptableDiff\": \"0.5\",\n  \"acceptableDiffKind\": \"PERCENTAGE\",\n  \"isSandbox\": true\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/payments",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "payments"
              ]
            },
            "description": "Embedded checkout: you render the payment page yourself. The response inlines the full `payment` object; saves `paymentId` and the first `offerId`.\n\n**Requirements:** your source IP must be on the gateway allowlist (`403` otherwise, `422` if no allowlist exists), `webhookUrl` is **required** (replace the example with your endpoint), and `callbackUrl` is **forbidden**.\n\nThis example body includes every optional request field so you can see the full shape in one place — delete the ones you don't need. `txFeePayer`/`commissionFeePayer` are ignored on a gateway with monthly fee billing (the tolerance fields still apply there). A platform-billed gateway refuses this call with `403` — it creates open-amount payments only.\n\nSent as a sandbox payment; remove `isSandbox` for a live one.\n\nDocs: https://doc.finomesh.com/accept-payments/embedded-checkout-api-mode"
          }
        },
        {
          "name": "Create open-amount payment",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "{",
                  "  pm.test('HTTP 201', () => pm.response.to.have.status(201));",
                  "  const data = (pm.response.json() || {}).data || {};",
                  "  if (data.paymentUid) pm.collectionVariables.set('paymentId', data.paymentUid);",
                  "  // API-mode creates inline the payment object — capture its first offer too.",
                  "  const offers = (data.payment && data.payment.offers) || [];",
                  "  if (offers.length) pm.collectionVariables.set('offerId', offers[0].id);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"callbackUrl\": \"https://shop.example.com/payment/result\",\n  \"timeoutSeconds\": 604800\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/payments/open-amount",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "payments",
                "open-amount"
              ]
            },
            "description": "A payment with no fixed amount — the payer chooses. Saves `paymentId`. Replace the example `callbackUrl` with your own result page.\n\n**Only for gateways provisioned for open-amount** — otherwise `403`.\n\nDocs: https://doc.finomesh.com/api/create-payment#open-amount-payments"
          }
        },
        {
          "name": "Verify payment",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "{",
                  "  pm.test('HTTP 200', () => pm.response.to.have.status(200));",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/payments/{{paymentId}}/verify",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "payments",
                "{{paymentId}}",
                "verify"
              ]
            },
            "description": "The **authoritative** outcome of a payment — fulfil from this response, never from the callback or webhook alone.\n\nIdempotent. `PENDING` is a no-op; `SUCCESS` / `ACCEPTABLE` fulfil; `MISMATCH` needs review; `EXPIRED` cancels.\n\nDocs: https://doc.finomesh.com/api/verify-payment"
          }
        },
        {
          "name": "Submit transaction inquiry",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "{",
                  "  pm.test('HTTP 200', () => pm.response.to.have.status(200));",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"txHash\": \"0x<customer-reported-tx-hash>\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/payments/{{paymentId}}/inquiry",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "payments",
                "{{paymentId}}",
                "inquiry"
              ]
            },
            "description": "Submits a customer's transaction hash for a payment that never updated on its own. Read `resultCode`, not the HTTP status — verdicts return `200`.\n\n**Attempts are scarce:** 5 per payment, shared with your dashboard. Do not loop this request. Sandbox payments return `sandbox_payment`.\n\nDocs: https://doc.finomesh.com/api/inquiry-payment"
          }
        }
      ]
    },
    {
      "name": "Public payment endpoints",
      "description": "No API key — the payment UUID is the credential. The hosted checkout calls these for you; in API checkout mode your **server** calls them, and every one is then gated to your allowlisted source IPs.\n\nDocs: https://doc.finomesh.com/api/public-endpoints",
      "auth": {
        "type": "noauth"
      },
      "item": [
        {
          "name": "Get payment",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "{",
                  "  pm.test('HTTP 200', () => pm.response.to.have.status(200));",
                  "  const data = (pm.response.json() || {}).data || {};",
                  "  const offers = data.offers || [];",
                  "  if (offers.length) pm.collectionVariables.set('offerId', offers[0].id);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/public/payments/{{paymentId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "public",
                "payments",
                "{{paymentId}}"
              ]
            },
            "description": "The redacted payment projection the checkout renders from — amounts, status, and `offers[]`. No API key.\n\nSaves the first offer as `offerId`.\n\n**API-mode payments:** only reachable from an allowlisted source IP (`403` otherwise).\n\nDocs: https://doc.finomesh.com/api/public-endpoints"
          }
        },
        {
          "name": "Get payment status (slim)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "{",
                  "  pm.test('HTTP 200', () => pm.response.to.have.status(200));",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/public/payments/{{paymentId}}?statusOnly=true",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "public",
                "payments",
                "{{paymentId}}"
              ],
              "query": [
                {
                  "key": "statusOnly",
                  "value": "true",
                  "description": "API-mode payments only; ignored for hosted."
                }
              ]
            },
            "description": "The cheap status poll for **API-mode** payments: `paymentUid`, `status`, `isVerified`, `verifiedAt`. Fulfil only from *Verify payment*.\n\nDocs: https://doc.finomesh.com/api/public-endpoints#slim-status-object"
          }
        },
        {
          "name": "Select offer (API mode)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "{",
                  "  pm.test('HTTP 200 or 202', () => pm.expect(pm.response.code).to.be.oneOf([200, 202]));",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/public/payments/{{paymentId}}/offers/{{offerId}}/select",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "public",
                "payments",
                "{{paymentId}}",
                "offers",
                "{{offerId}}",
                "select"
              ]
            },
            "description": "Assigns the deposit address and exact amount for the chosen offer. **API-mode payments only**, still `PENDING`, from an allowlisted IP.\n\n`202` with `assignmentStatus: \"PENDING\"` means the address is still being derived — send again after `retryAfterMs`.\n\nDocs: https://doc.finomesh.com/api/public-endpoints"
          }
        },
        {
          "name": "Expire payment",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "{",
                  "  pm.test('HTTP 200', () => pm.response.to.have.status(200));",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/public/payments/{{paymentId}}/expire",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "public",
                "payments",
                "{{paymentId}}",
                "expire"
              ]
            },
            "description": "Moves `PENDING → EXPIRED` **only** once the payment is past its deadline; otherwise a no-op that returns the current state. Safe to call at any time.\n\nDocs: https://doc.finomesh.com/api/public-endpoints"
          }
        },
        {
          "name": "[Sandbox only] Simulate outcome",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "{",
                  "  pm.test('HTTP 200', () => pm.response.to.have.status(200));",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"outcome\": \"success\",\n  \"offerId\": \"{{offerId}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/public/payments/{{paymentId}}/sandbox/simulate",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "public",
                "payments",
                "{{paymentId}}",
                "sandbox",
                "simulate"
              ]
            },
            "description": "**Sandbox-only** — rejected with `422` on a real (non-sandbox) payment. Drives a sandbox payment into a terminal state. `outcome` is one of `success`, `acceptable`, `mismatch`, `expire`.\n\n`acceptable` and `mismatch` need a payment created with a non-zero tolerance (`overAcceptableDiff` / `underAcceptableDiff`) — otherwise this also returns `422`.\n\nEverything downstream fires exactly as in production: callback redirect, signed webhook, verify.\n\nDocs: https://doc.finomesh.com/api/public-endpoints"
          }
        }
      ]
    },
    {
      "name": "Cashout",
      "description": "Withdraw your balance programmatically. **Off by default** — ask to have the cashout API enabled for your gateway, then generate a signing secret in the dashboard.\n\n- Every request is **signed** automatically by this folder's pre-request script from `cashoutSecret` (sets `X-Timestamp` / `X-Signature`).\n- Every request must come from an **allowlisted source IP**. Send from the Postman desktop app (or the web app with the Desktop Agent) and allowlist your own IP — requests through Postman's Cloud Agent originate from Postman's servers and get `403`.\n- Money-moving POSTs send a fresh `Idempotency-Key` each time — **clicking Send twice creates two settlements.**\n- **With `baseUrl` pointed at production these requests move real funds.**\n\nDocs: https://doc.finomesh.com/cashout-settlements/overview",
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "{",
              "  // Signs every request in this folder: hex HMAC-SHA256 over X-Timestamp + '.' + rawBody.",
              "  const CryptoJS = require('crypto-js');",
              "  const secret = pm.variables.get('cashoutSecret');",
              "  if (!secret) {",
              "    throw new Error('cashoutSecret is empty — set it in the collection variables (collection → Variables tab).');",
              "  }",
              "  const ts = Math.floor(Date.now() / 1000).toString();",
              "  let body = '';",
              "  if (pm.request.method !== 'GET' && pm.request.body && pm.request.body.mode === 'raw') {",
              "    // Resolve {{variables}} now and send exactly the bytes that were signed.",
              "    body = pm.variables.replaceIn(pm.request.body.raw || '');",
              "    pm.request.body.update({mode: 'raw', raw: body, options: {raw: {language: 'json'}}});",
              "  }",
              "  pm.variables.set('cashoutTimestamp', ts);",
              "  pm.variables.set('cashoutSignature', CryptoJS.HmacSHA256(ts + '.' + body, secret).toString(CryptoJS.enc.Hex));",
              "}"
            ]
          }
        }
      ],
      "item": [
        {
          "name": "Get balances",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "{",
                  "  pm.test('HTTP 200', () => pm.response.to.have.status(200));",
                  "  const data = (pm.response.json() || {}).data || {};",
                  "  const items = data.items || [];",
                  "  if (items.length) pm.collectionVariables.set('assetId', items[0].assetId);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "X-Timestamp",
                "value": "{{cashoutTimestamp}}",
                "description": "Set by the folder pre-request script (Unix seconds)."
              },
              {
                "key": "X-Signature",
                "value": "{{cashoutSignature}}",
                "description": "Set by the folder pre-request script: hex HMAC-SHA256(cashoutSecret, X-Timestamp + \".\" + rawBody)."
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/merchant/settlements/balances",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "merchant",
                "settlements",
                "balances"
              ]
            },
            "description": "Cashout-able balance per asset: `totalAvailable` (withdrawable now), the maturing bucket, and the AML-held pool.\n\nSaves the first item's `assetId` for *Estimate fee* and *Create settlement* — edit the request bodies to pick another asset.\n\nDocs: https://doc.finomesh.com/api/cashout#balances"
          }
        },
        {
          "name": "Estimate fee",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "{",
                  "  pm.test('HTTP 200', () => pm.response.to.have.status(200));",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "X-Timestamp",
                "value": "{{cashoutTimestamp}}",
                "description": "Set by the folder pre-request script (Unix seconds)."
              },
              {
                "key": "X-Signature",
                "value": "{{cashoutSignature}}",
                "description": "Set by the folder pre-request script: hex HMAC-SHA256(cashoutSecret, X-Timestamp + \".\" + rawBody)."
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"assetId\": \"{{assetId}}\",\n  \"amount\": \"20\",\n  \"address\": \"YOUR_DESTINATION_ADDRESS\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/merchant/settlements/estimate-fee",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "merchant",
                "settlements",
                "estimate-fee"
              ]
            },
            "description": "Dry run: returns the exact `feeLocked` and `netAmount` a real create would produce. **Creates nothing** and needs no `Idempotency-Key`.\n\nReplace `YOUR_DESTINATION_ADDRESS` in the body with an address valid for the asset's chain.\n\nDocs: https://doc.finomesh.com/api/cashout#estimate-fee"
          }
        },
        {
          "name": "Create settlement",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "{",
                  "  pm.test('HTTP 200 or 202', () => pm.expect(pm.response.code).to.be.oneOf([200, 202]));",
                  "  const data = (pm.response.json() || {}).data || {};",
                  "  if (data.id) pm.collectionVariables.set('settlementId', data.id);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Fresh UUID on every send. To replay a request safely, replace it with a fixed value and resend."
              },
              {
                "key": "X-Timestamp",
                "value": "{{cashoutTimestamp}}",
                "description": "Set by the folder pre-request script (Unix seconds)."
              },
              {
                "key": "X-Signature",
                "value": "{{cashoutSignature}}",
                "description": "Set by the folder pre-request script: hex HMAC-SHA256(cashoutSecret, X-Timestamp + \".\" + rawBody)."
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"assetId\": \"{{assetId}}\",\n  \"amount\": \"20\",\n  \"address\": \"YOUR_DESTINATION_ADDRESS\",\n  \"route\": \"GREEN\",\n  \"label\": \"postman\",\n  \"metadata\": {\n    \"requester\": \"postman\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/merchant/settlements",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "merchant",
                "settlements"
              ]
            },
            "description": "**Moves funds.** Requests a settlement of an exact amount. The status code is the outcome: `200` claimed, `202` parked (`UNDERFUNDED` / `WAITING_AML_CREDIT`), `409` refused.\n\nReplace `YOUR_DESTINATION_ADDRESS` in the body with an address valid for the asset's chain (a testnet address on staging).\n\n`route`: `GREEN` (default), `AML_HELD`, or `SMART`. Saves `settlementId`.\n\nDocs: https://doc.finomesh.com/api/cashout#create"
          }
        },
        {
          "name": "List settlements",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "{",
                  "  pm.test('HTTP 200', () => pm.response.to.have.status(200));",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "X-Timestamp",
                "value": "{{cashoutTimestamp}}",
                "description": "Set by the folder pre-request script (Unix seconds)."
              },
              {
                "key": "X-Signature",
                "value": "{{cashoutSignature}}",
                "description": "Set by the folder pre-request script: hex HMAC-SHA256(cashoutSecret, X-Timestamp + \".\" + rawBody)."
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/merchant/settlements?limit=20",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "merchant",
                "settlements"
              ],
              "query": [
                {
                  "key": "status",
                  "value": "PENDING_APPROVAL",
                  "description": "PENDING_APPROVAL, UNDERFUNDED, WAITING_AML_CREDIT, REQUESTED, PROCESSING, SETTLED, or REJECTED.",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "20",
                  "description": "Page size."
                },
                {
                  "key": "page",
                  "value": "1",
                  "description": "1-based page number.",
                  "disabled": true
                },
                {
                  "key": "after",
                  "value": "",
                  "description": "Cursor; overrides page when set.",
                  "disabled": true
                }
              ]
            },
            "description": "Your cashouts, newest first, with an optional `status` filter. `data.pagination.total` counts the matches.\n\nDocs: https://doc.finomesh.com/api/cashout#list"
          }
        },
        {
          "name": "Get settlement",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "{",
                  "  pm.test('HTTP 200', () => pm.response.to.have.status(200));",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "X-Timestamp",
                "value": "{{cashoutTimestamp}}",
                "description": "Set by the folder pre-request script (Unix seconds)."
              },
              {
                "key": "X-Signature",
                "value": "{{cashoutSignature}}",
                "description": "Set by the folder pre-request script: hex HMAC-SHA256(cashoutSecret, X-Timestamp + \".\" + rawBody)."
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/merchant/settlements/{{settlementId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "merchant",
                "settlements",
                "{{settlementId}}"
              ]
            },
            "description": "Status of one settlement: `REQUESTED → PROCESSING → SETTLED` (or `REJECTED`); `PENDING_APPROVAL`, `UNDERFUNDED`, and `WAITING_AML_CREDIT` mean accepted but not yet dispatched.\n\nDocs: https://doc.finomesh.com/api/cashout#status"
          }
        },
        {
          "name": "Approve settlement",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "{",
                  "  pm.test('HTTP 200', () => pm.response.to.have.status(200));",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Fresh UUID on every send. To replay a request safely, replace it with a fixed value and resend."
              },
              {
                "key": "X-Timestamp",
                "value": "{{cashoutTimestamp}}",
                "description": "Set by the folder pre-request script (Unix seconds)."
              },
              {
                "key": "X-Signature",
                "value": "{{cashoutSignature}}",
                "description": "Set by the folder pre-request script: hex HMAC-SHA256(cashoutSecret, X-Timestamp + \".\" + rawBody)."
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"totpCode\": \"123456\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/merchant/settlements/{{settlementId}}/approve",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "merchant",
                "settlements",
                "{{settlementId}}",
                "approve"
              ]
            },
            "description": "**Moves funds.** Releases a settlement parked at your approval cap (`PENDING_APPROVAL`). Replace `totpCode` with a fresh code from your authenticator — 2FA must be enabled on your account.\n\nDocs: https://doc.finomesh.com/api/cashout#approve"
          }
        },
        {
          "name": "Retry parked settlement",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "{",
                  "  pm.test('HTTP 200', () => pm.response.to.have.status(200));",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Fresh UUID on every send. To replay a request safely, replace it with a fixed value and resend."
              },
              {
                "key": "X-Timestamp",
                "value": "{{cashoutTimestamp}}",
                "description": "Set by the folder pre-request script (Unix seconds)."
              },
              {
                "key": "X-Signature",
                "value": "{{cashoutSignature}}",
                "description": "Set by the folder pre-request script: hex HMAC-SHA256(cashoutSecret, X-Timestamp + \".\" + rawBody)."
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/merchant/settlements/{{settlementId}}/retry",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "merchant",
                "settlements",
                "{{settlementId}}",
                "retry"
              ]
            },
            "description": "Re-checks the balance of an `UNDERFUNDED` settlement now instead of waiting for the next automatic pass (about once a minute). Optional.\n\nDocs: https://doc.finomesh.com/api/cashout#retry"
          }
        },
        {
          "name": "Cancel parked settlement",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "{",
                  "  pm.test('HTTP 200', () => pm.response.to.have.status(200));",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Fresh UUID on every send. To replay a request safely, replace it with a fixed value and resend."
              },
              {
                "key": "X-Timestamp",
                "value": "{{cashoutTimestamp}}",
                "description": "Set by the folder pre-request script (Unix seconds)."
              },
              {
                "key": "X-Signature",
                "value": "{{cashoutSignature}}",
                "description": "Set by the folder pre-request script: hex HMAC-SHA256(cashoutSecret, X-Timestamp + \".\" + rawBody)."
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/merchant/settlements/{{settlementId}}/cancel",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "merchant",
                "settlements",
                "{{settlementId}}",
                "cancel"
              ]
            },
            "description": "Withdraws a parked (`UNDERFUNDED` / `WAITING_AML_CREDIT`) settlement; it becomes `REJECTED`. A parked settlement claimed nothing, so this releases nothing.\n\nDocs: https://doc.finomesh.com/api/cashout#cancel"
          }
        }
      ]
    }
  ],
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://api-staging.finomesh.com/api/v1",
      "description": "Staging. For production use https://api.finomesh.com/api/v1 (with your production apiKey)."
    },
    {
      "key": "apiKey",
      "value": "",
      "description": "Your gateway API key. Set the current value only."
    },
    {
      "key": "cashoutSecret",
      "value": "",
      "description": "Cashout signing secret (Cashout folder only). Set the current value only."
    },
    {
      "key": "paymentId",
      "value": "",
      "description": "Set by the create-payment requests."
    },
    {
      "key": "offerId",
      "value": "",
      "description": "Set by Get payment / API-mode create."
    },
    {
      "key": "assetId",
      "value": "",
      "description": "Set by Get balances (first item)."
    },
    {
      "key": "settlementId",
      "value": "",
      "description": "Set by Create settlement."
    }
  ]
}
