{
  "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 collection **and** both environment files (drag all three into Postman at once).\n2. Select **Finomesh Staging** in the environment picker (top right). Build and test there first.\n3. In that environment, set `apiKey` (dashboard → your gateway). For the Cashout folder also set `signingSecret` and `cashoutAddress`.\n4. Run the **Sandbox walkthrough** folder: create → read → simulate → verify, with no blockchain involved.\n\n## Keep your secrets local\n\nEnter `apiKey` and `signingSecret` 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\nSwitching to **Finomesh Production** points every request at the live API with your production key. Cashout requests there move real funds.\n\nFull documentation: https://doc-staging.finomesh.com",
    "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 `apiKey` in the selected environment. 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\": \"{{callbackUrl}}\",\n  \"webhookUrl\": \"{{webhookUrl}}\",\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\nDocs: https://doc-staging.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-staging.finomesh.com/api/public-endpoints"
          }
        },
        {
          "name": "Simulate sandbox 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": "Drives a sandbox payment into a terminal state. `outcome` is one of `success`, `acceptable`, `mismatch`, `expire`.\n\nEverything downstream fires exactly as in production: callback redirect, signed webhook, verify. Rejected for non-sandbox payments.\n\nDocs: https://doc-staging.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-staging.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-staging.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\": \"{{callbackUrl}}\",\n  \"webhookUrl\": \"{{webhookUrl}}\",\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 (an empty value sends no webhook). Add `\"isSandbox\": true` to test without a chain.\n\nDocs: https://doc-staging.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\": \"{{webhookUrl}}\",\n  \"webhookParams\": {\n    \"orderId\": \"ORD-1042\"\n  },\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**, and `callbackUrl` is **forbidden**.\n\nSent as a sandbox payment; remove `isSandbox` for a live one.\n\nDocs: https://doc-staging.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\": \"{{callbackUrl}}\",\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`.\n\n**Only for gateways provisioned for open-amount** — otherwise `403`.\n\nDocs: https://doc-staging.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-staging.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-staging.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-staging.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-staging.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-staging.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-staging.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-staging.finomesh.com/api/public-endpoints"
          }
        },
        {
          "name": "Simulate sandbox 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": "Drives a sandbox payment into a terminal state. `outcome` is one of `success`, `acceptable`, `mismatch`, `expire`.\n\nEverything downstream fires exactly as in production: callback redirect, signed webhook, verify. Rejected for non-sandbox payments.\n\nDocs: https://doc-staging.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 `signingSecret` (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- **In the production environment these requests move real funds.**\n\nDocs: https://doc-staging.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('signingSecret');",
              "  if (!secret) {",
              "    throw new Error('signingSecret is empty — set it in the selected environment.');",
              "  }",
              "  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(signingSecret, 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-staging.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(signingSecret, X-Timestamp + \".\" + rawBody)."
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"assetId\": \"{{assetId}}\",\n  \"amount\": \"20\",\n  \"address\": \"{{cashoutAddress}}\"\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\n`address` must be valid for the asset's chain — set `cashoutAddress` in the environment.\n\nDocs: https://doc-staging.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(signingSecret, X-Timestamp + \".\" + rawBody)."
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"assetId\": \"{{assetId}}\",\n  \"amount\": \"20\",\n  \"address\": \"{{cashoutAddress}}\",\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\n`route`: `GREEN` (default), `AML_HELD`, or `SMART`. Saves `settlementId`.\n\nDocs: https://doc-staging.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(signingSecret, 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-staging.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(signingSecret, 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-staging.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(signingSecret, 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-staging.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(signingSecret, 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-staging.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(signingSecret, 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-staging.finomesh.com/api/cashout#cancel"
          }
        }
      ]
    }
  ],
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://api-staging.finomesh.com/api/v1",
      "description": "Fallback when no environment is selected — the selected environment overrides it."
    },
    {
      "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."
    }
  ]
}
