{
  "info": {
    "name": "Frag — FragmentPay API",
    "description": "Accept payment from any token on any chain. Settle in one asset.\n\nBase URL is set via the `baseUrl` collection variable (default `https://frag.cash`). Authenticate every `/api/public/v1/*` request with your secret key via the `Authorization: Bearer {{secretKey}}` header — `sk_test_…` for test mode, `sk_live_…` for live.\n\nAll `POST` requests support `Idempotency-Key`. Retries with the same key and body return the original response; a same-key/different-body retry returns `409 conflict`.\n\nImport into Postman or Bruno (both read v2.1). Every request ships with an example response and a test script that pins status code + response shape and stores useful ids into collection variables so you can chain requests without editing them.\n\n📚 **Docs hub:** https://frag.cash/docs/api — every request below links to its section.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
    "_postman_id": "f8a1c9f0-1a2b-4c3d-9e0f-fragmentpay0001"
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://frag.cash",
      "type": "string"
    },
    {
      "key": "secretKey",
      "value": "sk_test_replace_me",
      "type": "string"
    },
    {
      "key": "merchantWallet",
      "value": "MERCHANT_SOLANA_WALLET",
      "type": "string"
    },
    {
      "key": "intentId",
      "value": "",
      "type": "string"
    },
    {
      "key": "refundId",
      "value": "",
      "type": "string"
    },
    {
      "key": "payoutId",
      "value": "",
      "type": "string"
    },
    {
      "key": "webhookEndpointId",
      "value": "",
      "type": "string"
    },
    {
      "key": "webhookSigningSecret",
      "value": "",
      "type": "string"
    }
  ],
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{secretKey}}",
        "type": "string"
      }
    ]
  },
  "event": [
    {
      "listen": "test",
      "script": {
        "type": "text/javascript",
        "exec": [
          "// Global sanity checks applied to every request.",
          "pm.test('response has JSON content-type', function () {",
          "  const ct = pm.response.headers.get('Content-Type') || '';",
          "  pm.expect(ct.toLowerCase()).to.include('application/json');",
          "});",
          "pm.test('response body is valid JSON', function () {",
          "  pm.response.json();",
          "});"
        ]
      }
    }
  ],
  "item": [
    {
      "name": "Payment Intents",
      "description": "Create, retrieve, list, and cancel invoices. Every POST is idempotent when you send an `Idempotency-Key`.",
      "item": [
        {
          "name": "Create PaymentIntent",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Same key + same body ⇒ cached response. Different body ⇒ 409."
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/public/v1/payment-intents",
              "host": ["{{baseUrl}}"],
              "path": ["api", "public", "v1", "payment-intents"]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": 99,\n  \"currency\": \"USD\",\n  \"settlement_chain\": \"solana\",\n  \"settlement_token\": \"USDC\",\n  \"settlement_address\": \"{{merchantWallet}}\",\n  \"customer_email\": \"buyer@example.com\",\n  \"metadata\": { \"orderId\": \"order_8841\" },\n  \"expires_in_seconds\": 1800\n}"
            },
            "description": "Create a new PaymentIntent. `settlement_*` fields default to the merchant's dashboard settings when omitted.\n\n---\n📖 Docs: [Payment Intents · Create PaymentIntent](https://frag.cash/docs/api#create-paymentintent) — `POST /api/public/v1/payment-intents`"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status is 200 or 201', () => pm.expect([200, 201]).to.include(pm.response.code));",
                  "const body = pm.response.json();",
                  "pm.test('has intent id', () => pm.expect(body.id, 'body.id').to.be.a('string'));",
                  "pm.test('status is created/quoted', () => pm.expect(['created','quoted']).to.include(body.status));",
                  "pm.test('has checkout_url', () => pm.expect(body.checkout_url).to.match(/^https?:\\/\\//));",
                  "if (body.id) pm.collectionVariables.set('intentId', body.id);"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "201 Created",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/payment-intents"
                },
                "body": {
                  "mode": "raw",
                  "raw": "{ \"amount\": 99, \"currency\": \"USD\" }"
                }
              },
              "status": "Created",
              "code": 201,
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"id\": \"pi_11111111-1111-1111-1111-111111111111\",\n  \"merchant_id\": \"m_00000000-0000-0000-0000-000000000000\",\n  \"amount\": \"99.00\",\n  \"currency\": \"USD\",\n  \"status\": \"created\",\n  \"settlement_chain\": \"solana\",\n  \"settlement_token\": \"USDC\",\n  \"settlement_address\": \"MERCHANT_SOLANA_WALLET\",\n  \"checkout_url\": \"https://frag.cash/checkout/pi_11111111-1111-1111-1111-111111111111\",\n  \"expires_at\": \"2026-07-18T18:52:00Z\",\n  \"created_at\": \"2026-07-18T18:22:00Z\",\n  \"metadata\": { \"orderId\": \"order_8841\" }\n}",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Create PaymentIntent → 201 Created](https://frag.cash/docs/api#create-paymentintent-201-created)\n\n---\n📖 Docs: [Create PaymentIntent → 201 Created](https://frag.cash/docs/api#create-paymentintent-201-created)"
            },
            {
              "name": "400 invalid input",
              "originalRequest": {
                "method": "POST",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/payment-intents"
                },
                "body": {
                  "mode": "raw",
                  "raw": "{}"
                }
              },
              "status": "Bad Request",
              "code": 400,
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{ \"error\": \"invalid input\", \"details\": { \"fieldErrors\": { \"amount\": [\"Required\"] } } }",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Create PaymentIntent → 400 invalid input](https://frag.cash/docs/api#create-paymentintent-400-invalid-input)\n\n---\n📖 Docs: [Create PaymentIntent → 400 invalid input](https://frag.cash/docs/api#create-paymentintent-400-invalid-input)"
            },
            {
              "name": "401 unauthorized",
              "originalRequest": {
                "method": "POST",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/payment-intents"
                }
              },
              "status": "Unauthorized",
              "code": 401,
              "body": "{ \"error\": \"unauthorized\" }",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Create PaymentIntent → 401 unauthorized](https://frag.cash/docs/api#create-paymentintent-401-unauthorized)\n\n---\n📖 Docs: [Create PaymentIntent → 401 unauthorized](https://frag.cash/docs/api#create-paymentintent-401-unauthorized)"
            },
            {
              "name": "409 idempotency reused",
              "originalRequest": {
                "method": "POST",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/payment-intents"
                }
              },
              "status": "Conflict",
              "code": 409,
              "body": "{ \"error\": \"idempotency key reused with different body\" }",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Create PaymentIntent → 409 idempotency reused](https://frag.cash/docs/api#create-paymentintent-409-idempotency-reused)\n\n---\n📖 Docs: [Create PaymentIntent → 409 idempotency reused](https://frag.cash/docs/api#create-paymentintent-409-idempotency-reused)"
            }
          ]
        },
        {
          "name": "List PaymentIntents",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/public/v1/payment-intents?limit=25&status=settled",
              "host": ["{{baseUrl}}"],
              "path": ["api", "public", "v1", "payment-intents"],
              "query": [
                {
                  "key": "limit",
                  "value": "25",
                  "description": "1–200, default 50"
                },
                {
                  "key": "status",
                  "value": "settled",
                  "description": "Optional filter — created|quoted|executing|settled|failed|expired|cancelled|refunded"
                }
              ]
            },
            "description": "---\n📖 Docs: [Payment Intents · List PaymentIntents](https://frag.cash/docs/api#list-paymentintents) — `GET /api/public/v1/payment-intents?limit=25&status=settled`"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', () => pm.response.to.have.status(200));",
                  "const body = pm.response.json();",
                  "pm.test('data is array', () => pm.expect(body.data).to.be.an('array'));"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "GET",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/payment-intents"
                }
              },
              "status": "OK",
              "code": 200,
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{ \"data\": [ { \"id\": \"pi_11111111-1111-1111-1111-111111111111\", \"amount\": \"99.00\", \"currency\": \"USD\", \"status\": \"settled\", \"created_at\": \"2026-07-18T18:22:00Z\" } ] }",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [List PaymentIntents → 200 OK](https://frag.cash/docs/api#list-paymentintents-200-ok)\n\n---\n📖 Docs: [List PaymentIntents → 200 OK](https://frag.cash/docs/api#list-paymentintents-200-ok)"
            }
          ]
        },
        {
          "name": "Retrieve PaymentIntent",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/public/v1/payment-intents/{{intentId}}",
              "host": ["{{baseUrl}}"],
              "path": ["api", "public", "v1", "payment-intents", "{{intentId}}"]
            },
            "description": "---\n📖 Docs: [Payment Intents · Retrieve PaymentIntent](https://frag.cash/docs/api#retrieve-paymentintent) — `GET /api/public/v1/payment-intents/{{intentId}}`"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', () => pm.response.to.have.status(200));",
                  "const body = pm.response.json();",
                  "pm.test('id matches request', () => pm.expect(body.id).to.eql(pm.collectionVariables.get('intentId')));"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "GET",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/payment-intents/{{intentId}}"
                }
              },
              "status": "OK",
              "code": 200,
              "body": "{\n  \"id\": \"pi_11111111-1111-1111-1111-111111111111\",\n  \"amount\": \"99.00\",\n  \"currency\": \"USD\",\n  \"status\": \"settled\",\n  \"settlement_chain\": \"solana\",\n  \"settlement_token\": \"USDC\",\n  \"amount_received_usd\": \"100.00\",\n  \"platform_fee_usd\": \"1.00\",\n  \"net_settlement_usd\": \"99.00\",\n  \"settled_at\": \"2026-07-18T18:34:00Z\",\n  \"metadata\": { \"orderId\": \"order_8841\" }\n}",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Retrieve PaymentIntent → 200 OK](https://frag.cash/docs/api#retrieve-paymentintent-200-ok)\n\n---\n📖 Docs: [Retrieve PaymentIntent → 200 OK](https://frag.cash/docs/api#retrieve-paymentintent-200-ok)"
            },
            {
              "name": "404 not found",
              "originalRequest": {
                "method": "GET",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/payment-intents/pi_missing"
                }
              },
              "status": "Not Found",
              "code": 404,
              "body": "{ \"error\": \"not found\" }",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Retrieve PaymentIntent → 404 not found](https://frag.cash/docs/api#retrieve-paymentintent-404-not-found)\n\n---\n📖 Docs: [Retrieve PaymentIntent → 404 not found](https://frag.cash/docs/api#retrieve-paymentintent-404-not-found)"
            }
          ]
        },
        {
          "name": "Cancel PaymentIntent",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{baseUrl}}/api/public/v1/payment-intents/{{intentId}}/cancel",
              "host": ["{{baseUrl}}"],
              "path": ["api", "public", "v1", "payment-intents", "{{intentId}}", "cancel"]
            },
            "description": "---\n📖 Docs: [Payment Intents · Cancel PaymentIntent](https://frag.cash/docs/api#cancel-paymentintent) — `POST /api/public/v1/payment-intents/{{intentId}}/cancel`"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', () => pm.response.to.have.status(200));",
                  "const body = pm.response.json();",
                  "pm.test('status is cancelled', () => pm.expect(body.status).to.eql('cancelled'));"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "200 cancelled",
              "originalRequest": {
                "method": "POST",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/payment-intents/{{intentId}}/cancel"
                }
              },
              "status": "OK",
              "code": 200,
              "body": "{ \"id\": \"pi_11111111-1111-1111-1111-111111111111\", \"status\": \"cancelled\" }",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Cancel PaymentIntent → 200 cancelled](https://frag.cash/docs/api#cancel-paymentintent-200-cancelled)\n\n---\n📖 Docs: [Cancel PaymentIntent → 200 cancelled](https://frag.cash/docs/api#cancel-paymentintent-200-cancelled)"
            },
            {
              "name": "409 cannot cancel",
              "originalRequest": {
                "method": "POST",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/payment-intents/{{intentId}}/cancel"
                }
              },
              "status": "Conflict",
              "code": 409,
              "body": "{ \"error\": \"cannot cancel intent in status settled\" }",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Cancel PaymentIntent → 409 cannot cancel](https://frag.cash/docs/api#cancel-paymentintent-409-cannot-cancel)\n\n---\n📖 Docs: [Cancel PaymentIntent → 409 cannot cancel](https://frag.cash/docs/api#cancel-paymentintent-409-cannot-cancel)"
            }
          ]
        },
        {
          "name": "Routing candidates",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/public/v1/payment-intents/{{intentId}}/routing",
              "host": ["{{baseUrl}}"],
              "path": ["api", "public", "v1", "payment-intents", "{{intentId}}", "routing"]
            },
            "description": "Audit trail — every quote the router considered, which one was chosen, which one the AI picked, and the estimated savings.\n\n---\n📖 Docs: [Payment Intents · Routing candidates](https://frag.cash/docs/api#routing-candidates) — `GET /api/public/v1/payment-intents/{{intentId}}/routing`"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', () => pm.response.to.have.status(200));",
                  "const body = pm.response.json();",
                  "pm.test('data is array', () => pm.expect(body.data).to.be.an('array'));"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "GET",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/payment-intents/{{intentId}}/routing"
                }
              },
              "status": "OK",
              "code": 200,
              "body": "{\n  \"data\": [\n    { \"id\": \"qc_1\", \"provider\": \"lifi\", \"chosen\": true, \"ai_pick\": true, \"score\": 0.94, \"from_chain\": \"base\", \"to_chain\": \"solana\", \"from_token\": \"USDC\", \"to_token\": \"USDC\", \"to_amount_usd\": \"99.10\", \"fee_usd\": \"0.14\", \"gas_usd\": \"0.06\", \"duration_sec\": 42, \"reason\": \"best net after fees\" },\n    { \"id\": \"qc_2\", \"provider\": \"jupiter-direct\", \"chosen\": false, \"ai_pick\": false, \"score\": 0.87, \"from_token\": \"SOL\", \"to_token\": \"USDC\", \"to_amount_usd\": \"98.72\", \"fee_usd\": \"0.19\", \"gas_usd\": \"0.00\", \"duration_sec\": 12 }\n  ]\n}",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Routing candidates → 200 OK](https://frag.cash/docs/api#routing-candidates-200-ok)\n\n---\n📖 Docs: [Routing candidates → 200 OK](https://frag.cash/docs/api#routing-candidates-200-ok)"
            }
          ]
        },
        {
          "name": "Intent transactions",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/public/v1/payment-intents/{{intentId}}/transactions",
              "host": ["{{baseUrl}}"],
              "path": ["api", "public", "v1", "payment-intents", "{{intentId}}", "transactions"]
            },
            "description": "On-chain legs (swaps, bridges, settlement transfer) for this intent, in execution order.\n\n---\n📖 Docs: [Payment Intents · Intent transactions](https://frag.cash/docs/api#intent-transactions) — `GET /api/public/v1/payment-intents/{{intentId}}/transactions`"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', () => pm.response.to.have.status(200));",
                  "const body = pm.response.json();",
                  "pm.test('data is array', () => pm.expect(body.data).to.be.an('array'));"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "GET",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/payment-intents/{{intentId}}/transactions"
                }
              },
              "status": "OK",
              "code": 200,
              "body": "{ \"data\": [ { \"id\": \"tx_1\", \"kind\": \"swap\", \"chain\": \"base\", \"tx_hash\": \"0xabc…\", \"amount_usd\": \"99.10\", \"status\": \"confirmed\", \"created_at\": \"2026-07-18T18:33:00Z\" } ] }",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Intent transactions → 200 OK](https://frag.cash/docs/api#intent-transactions-200-ok)\n\n---\n📖 Docs: [Intent transactions → 200 OK](https://frag.cash/docs/api#intent-transactions-200-ok)"
            }
          ]
        }
      ]
    },
    {
      "name": "Refunds",
      "description": "Issue partial or full refunds against a settled intent. Balance-capped — creating a refund that would exceed the settled amount returns 422.",
      "item": [
        {
          "name": "Create Refund",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/public/v1/refunds",
              "host": ["{{baseUrl}}"],
              "path": ["api", "public", "v1", "refunds"]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"intent_id\": \"{{intentId}}\",\n  \"amount_usd\": 25.00,\n  \"destination\": \"CUSTOMER_WALLET_ADDRESS\",\n  \"reason\": \"customer_request\"\n}"
            },
            "description": "---\n📖 Docs: [Refunds · Create Refund](https://frag.cash/docs/api#create-refund) — `POST /api/public/v1/refunds`"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 201', () => pm.response.to.have.status(201));",
                  "const body = pm.response.json();",
                  "pm.test('has refund id', () => pm.expect(body.id).to.be.a('string'));",
                  "pm.test('status pending', () => pm.expect(body.status).to.eql('pending'));",
                  "if (body.id) pm.collectionVariables.set('refundId', body.id);"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "201 Created",
              "originalRequest": {
                "method": "POST",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/refunds"
                }
              },
              "status": "Created",
              "code": 201,
              "body": "{\n  \"id\": \"rf_22222222-2222-2222-2222-222222222222\",\n  \"payment_intent_id\": \"pi_11111111-1111-1111-1111-111111111111\",\n  \"amount_usd\": \"25.00\",\n  \"chain\": \"solana\",\n  \"token\": \"USDC\",\n  \"destination\": \"CUSTOMER_WALLET_ADDRESS\",\n  \"reason\": \"customer_request\",\n  \"status\": \"pending\",\n  \"created_at\": \"2026-07-18T18:40:00Z\"\n}",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Create Refund → 201 Created](https://frag.cash/docs/api#create-refund-201-created)\n\n---\n📖 Docs: [Create Refund → 201 Created](https://frag.cash/docs/api#create-refund-201-created)"
            },
            {
              "name": "422 exceeds refundable balance",
              "originalRequest": {
                "method": "POST",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/refunds"
                }
              },
              "status": "Unprocessable Entity",
              "code": 422,
              "body": "{ \"error\": \"refund exceeds refundable balance\", \"remaining\": 12.5 }",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Create Refund → 422 exceeds refundable balance](https://frag.cash/docs/api#create-refund-422-exceeds-refundable-balance)\n\n---\n📖 Docs: [Create Refund → 422 exceeds refundable balance](https://frag.cash/docs/api#create-refund-422-exceeds-refundable-balance)"
            },
            {
              "name": "409 intent not refundable",
              "originalRequest": {
                "method": "POST",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/refunds"
                }
              },
              "status": "Conflict",
              "code": 409,
              "body": "{ \"error\": \"cannot refund intent in status=executing\" }",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Create Refund → 409 intent not refundable](https://frag.cash/docs/api#create-refund-409-intent-not-refundable)\n\n---\n📖 Docs: [Create Refund → 409 intent not refundable](https://frag.cash/docs/api#create-refund-409-intent-not-refundable)"
            }
          ]
        },
        {
          "name": "List Refunds",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/public/v1/refunds?limit=50&payment_intent_id={{intentId}}",
              "host": ["{{baseUrl}}"],
              "path": ["api", "public", "v1", "refunds"],
              "query": [
                {
                  "key": "limit",
                  "value": "50"
                },
                {
                  "key": "payment_intent_id",
                  "value": "{{intentId}}",
                  "description": "Optional — filter to one intent"
                }
              ]
            },
            "description": "---\n📖 Docs: [Refunds · List Refunds](https://frag.cash/docs/api#list-refunds) — `GET /api/public/v1/refunds?limit=50&payment_intent_id={{intentId}}`"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', () => pm.response.to.have.status(200));",
                  "const body = pm.response.json();",
                  "pm.test('data is array', () => pm.expect(body.data).to.be.an('array'));"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "GET",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/refunds"
                }
              },
              "status": "OK",
              "code": 200,
              "body": "{ \"data\": [ { \"id\": \"rf_22222222-2222-2222-2222-222222222222\", \"amount_usd\": \"25.00\", \"status\": \"paid\", \"tx_hash\": \"5s4…\", \"paid_at\": \"2026-07-18T18:42:00Z\" } ] }",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [List Refunds → 200 OK](https://frag.cash/docs/api#list-refunds-200-ok)\n\n---\n📖 Docs: [List Refunds → 200 OK](https://frag.cash/docs/api#list-refunds-200-ok)"
            }
          ]
        },
        {
          "name": "Retrieve Refund",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/public/v1/refunds/{{refundId}}",
              "host": ["{{baseUrl}}"],
              "path": ["api", "public", "v1", "refunds", "{{refundId}}"]
            },
            "description": "---\n📖 Docs: [Refunds · Retrieve Refund](https://frag.cash/docs/api#retrieve-refund) — `GET /api/public/v1/refunds/{{refundId}}`"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', () => pm.response.to.have.status(200));",
                  "const body = pm.response.json();",
                  "pm.test('id matches', () => pm.expect(body.id).to.eql(pm.collectionVariables.get('refundId')));"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "GET",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/refunds/{{refundId}}"
                }
              },
              "status": "OK",
              "code": 200,
              "body": "{ \"id\": \"rf_22222222-2222-2222-2222-222222222222\", \"payment_intent_id\": \"pi_11111111-1111-1111-1111-111111111111\", \"amount_usd\": \"25.00\", \"chain\": \"solana\", \"token\": \"USDC\", \"destination\": \"CUSTOMER_WALLET_ADDRESS\", \"reason\": \"customer_request\", \"status\": \"paid\", \"tx_hash\": \"5s4…\", \"paid_at\": \"2026-07-18T18:42:00Z\", \"failure_reason\": null }",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Retrieve Refund → 200 OK](https://frag.cash/docs/api#retrieve-refund-200-ok)\n\n---\n📖 Docs: [Retrieve Refund → 200 OK](https://frag.cash/docs/api#retrieve-refund-200-ok)"
            }
          ]
        },
        {
          "name": "Refund Public Status (unauthenticated)",
          "request": {
            "method": "GET",
            "auth": { "type": "noauth" },
            "url": {
              "raw": "{{baseUrl}}/api/public/refunds/{{refundId}}/status",
              "host": ["{{baseUrl}}"],
              "path": ["api", "public", "refunds", "{{refundId}}", "status"]
            },
            "description": "Payer-facing safe status view. No auth required. Destination address is redacted to the last 6 chars; no merchant PII.\n\n---\n📖 Docs: [Refunds · Public Status](https://frag.cash/docs/refunds#payer-facing-status-page) — `GET /api/public/refunds/{{refundId}}/status`"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', () => pm.response.to.have.status(200));",
                  "const body = pm.response.json();",
                  "pm.test('has terminal flag', () => pm.expect(body.terminal).to.be.a('boolean'));",
                  "pm.test('destination is redacted', () => pm.expect(body.destination_tail).to.match(/^…|^$/));"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "GET",
                "url": { "raw": "{{baseUrl}}/api/public/refunds/{{refundId}}/status" }
              },
              "status": "OK",
              "code": 200,
              "body": "{ \"id\": \"rf_22222222-2222-2222-2222-222222222222\", \"payment_intent_id\": \"pi_11111111-1111-1111-1111-111111111111\", \"amount_usd\": 25, \"chain\": \"solana\", \"token\": \"USDC\", \"destination_tail\": \"…a1b2c3\", \"reason\": \"customer_request\", \"status\": \"succeeded\", \"tx_hash\": \"5s4…\", \"failure_reason\": null, \"attempts\": 1, \"paid_at\": \"2026-07-18T18:42:00Z\", \"terminal\": true }",
              "_postman_previewlanguage": "json"
            }
          ]
        }
      ]
    },
    {
      "name": "Payouts",
      "description": "Merchant off-ramp / settlement rail. Payouts are enqueued automatically when an intent settles. Use these endpoints to audit status or replay a failed dispatch.",
      "item": [
        {
          "name": "List Payouts",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/public/v1/payouts?limit=50&status=paid",
              "host": ["{{baseUrl}}"],
              "path": ["api", "public", "v1", "payouts"],
              "query": [
                {
                  "key": "limit",
                  "value": "50"
                },
                {
                  "key": "status",
                  "value": "paid",
                  "description": "pending|dispatched|paid|failed|cancelled"
                },
                {
                  "key": "payment_intent_id",
                  "value": "",
                  "disabled": true
                }
              ]
            },
            "description": "---\n📖 Docs: [Payouts · List Payouts](https://frag.cash/docs/api#list-payouts) — `GET /api/public/v1/payouts?limit=50&status=paid`"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', () => pm.response.to.have.status(200));",
                  "const body = pm.response.json();",
                  "pm.test('data is array', () => pm.expect(body.data).to.be.an('array'));",
                  "if (Array.isArray(body.data) && body.data.length) {",
                  "  pm.collectionVariables.set('payoutId', body.data[0].id);",
                  "}"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "GET",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/payouts"
                }
              },
              "status": "OK",
              "code": 200,
              "body": "{ \"data\": [ { \"id\": \"po_33333333-3333-3333-3333-333333333333\", \"payment_intent_id\": \"pi_11111111-1111-1111-1111-111111111111\", \"rail\": \"self_custody\", \"chain\": \"solana\", \"token\": \"USDC\", \"amount\": \"99.00\", \"currency\": \"USD\", \"status\": \"paid\", \"tx_hash\": \"5s4…\", \"attempts\": 1, \"paid_at\": \"2026-07-18T18:44:00Z\", \"created_at\": \"2026-07-18T18:34:00Z\" } ] }",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [List Payouts → 200 OK](https://frag.cash/docs/api#list-payouts-200-ok)\n\n---\n📖 Docs: [List Payouts → 200 OK](https://frag.cash/docs/api#list-payouts-200-ok)"
            }
          ]
        },
        {
          "name": "Retrieve Payout",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/public/v1/payouts/{{payoutId}}",
              "host": ["{{baseUrl}}"],
              "path": ["api", "public", "v1", "payouts", "{{payoutId}}"]
            },
            "description": "---\n📖 Docs: [Payouts · Retrieve Payout](https://frag.cash/docs/api#retrieve-payout) — `GET /api/public/v1/payouts/{{payoutId}}`"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', () => pm.response.to.have.status(200));",
                  "const body = pm.response.json();",
                  "pm.test('id matches', () => pm.expect(body.id).to.eql(pm.collectionVariables.get('payoutId')));"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "GET",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/payouts/{{payoutId}}"
                }
              },
              "status": "OK",
              "code": 200,
              "body": "{ \"id\": \"po_33333333-3333-3333-3333-333333333333\", \"status\": \"paid\", \"tx_hash\": \"5s4…\", \"attempts\": 1, \"failure_reason\": null }",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Retrieve Payout → 200 OK](https://frag.cash/docs/api#retrieve-payout-200-ok)\n\n---\n📖 Docs: [Retrieve Payout → 200 OK](https://frag.cash/docs/api#retrieve-payout-200-ok)"
            }
          ]
        },
        {
          "name": "Replay Payout dispatch",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{baseUrl}}/api/public/v1/payouts/{{payoutId}}/replay",
              "host": ["{{baseUrl}}"],
              "path": ["api", "public", "v1", "payouts", "{{payoutId}}", "replay"]
            },
            "description": "Manually re-run the payout dispatcher. Only useful for `failed` or stuck `pending` payouts — the engine already retries with exponential backoff.\n\n---\n📖 Docs: [Payouts · Replay Payout dispatch](https://frag.cash/docs/api#replay-payout-dispatch) — `POST /api/public/v1/payouts/{{payoutId}}/replay`"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', () => pm.response.to.have.status(200));",
                  "const body = pm.response.json();",
                  "pm.test('replayed flag', () => pm.expect(body.replayed).to.eql(true));"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "200 replayed",
              "originalRequest": {
                "method": "POST",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/payouts/{{payoutId}}/replay"
                }
              },
              "status": "OK",
              "code": 200,
              "body": "{ \"replayed\": true, \"result\": { \"status\": \"paid\", \"tx_hash\": \"5s4…\" } }",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Replay Payout dispatch → 200 replayed](https://frag.cash/docs/api#replay-payout-dispatch-200-replayed)\n\n---\n📖 Docs: [Replay Payout dispatch → 200 replayed](https://frag.cash/docs/api#replay-payout-dispatch-200-replayed)"
            }
          ]
        }
      ]
    },
    {
      "name": "Webhook Endpoints",
      "description": "Configure the URLs Frag POSTs signed events to. The `signing_secret` returned on Create / Rotate is shown exactly once — store it immediately.",
      "item": [
        {
          "name": "Create Webhook Endpoint",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/public/v1/webhook-endpoints",
              "host": ["{{baseUrl}}"],
              "path": ["api", "public", "v1", "webhook-endpoints"]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"url\": \"https://your.app/api/frag/webhook\",\n  \"events\": [\n    \"payment_intent.settled\",\n    \"payment_intent.failed\",\n    \"payment_intent.refunded\",\n    \"payout.paid\",\n    \"payout.failed\"\n  ],\n  \"enabled\": true\n}"
            },
            "description": "---\n📖 Docs: [Webhook Endpoints · Create Webhook Endpoint](https://frag.cash/docs/api#create-webhook-endpoint) — `POST /api/public/v1/webhook-endpoints`"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 201', () => pm.response.to.have.status(201));",
                  "const body = pm.response.json();",
                  "pm.test('has id + secret', () => {",
                  "  pm.expect(body.id).to.be.a('string');",
                  "  pm.expect(body.signing_secret).to.match(/^whsec_/);",
                  "});",
                  "if (body.id) pm.collectionVariables.set('webhookEndpointId', body.id);",
                  "if (body.signing_secret) pm.collectionVariables.set('webhookSigningSecret', body.signing_secret);"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "201 Created",
              "originalRequest": {
                "method": "POST",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/webhook-endpoints"
                }
              },
              "status": "Created",
              "code": 201,
              "body": "{ \"id\": \"we_44444444-4444-4444-4444-444444444444\", \"url\": \"https://your.app/api/frag/webhook\", \"events\": [\"payment_intent.settled\"], \"enabled\": true, \"signing_secret\": \"whsec_0123456789abcdef0123456789abcdef0123456789abcdef\", \"created_at\": \"2026-07-18T18:22:00Z\" }",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Create Webhook Endpoint → 201 Created](https://frag.cash/docs/api#create-webhook-endpoint-201-created)\n\n---\n📖 Docs: [Create Webhook Endpoint → 201 Created](https://frag.cash/docs/api#create-webhook-endpoint-201-created)"
            }
          ]
        },
        {
          "name": "List Webhook Endpoints",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/public/v1/webhook-endpoints",
              "host": ["{{baseUrl}}"],
              "path": ["api", "public", "v1", "webhook-endpoints"]
            },
            "description": "---\n📖 Docs: [Webhook Endpoints · List Webhook Endpoints](https://frag.cash/docs/api#list-webhook-endpoints) — `GET /api/public/v1/webhook-endpoints`"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', () => pm.response.to.have.status(200));",
                  "pm.test('data is array', () => pm.expect(pm.response.json().data).to.be.an('array'));"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "GET",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/webhook-endpoints"
                }
              },
              "status": "OK",
              "code": 200,
              "body": "{ \"data\": [ { \"id\": \"we_44444444-4444-4444-4444-444444444444\", \"url\": \"https://your.app/api/frag/webhook\", \"events\": [\"payment_intent.settled\"], \"enabled\": true, \"created_at\": \"2026-07-18T18:22:00Z\" } ] }",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [List Webhook Endpoints → 200 OK](https://frag.cash/docs/api#list-webhook-endpoints-200-ok)\n\n---\n📖 Docs: [List Webhook Endpoints → 200 OK](https://frag.cash/docs/api#list-webhook-endpoints-200-ok)"
            }
          ]
        },
        {
          "name": "Retrieve Webhook Endpoint",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/public/v1/webhook-endpoints/{{webhookEndpointId}}",
              "host": ["{{baseUrl}}"],
              "path": ["api", "public", "v1", "webhook-endpoints", "{{webhookEndpointId}}"]
            },
            "description": "---\n📖 Docs: [Webhook Endpoints · Retrieve Webhook Endpoint](https://frag.cash/docs/api#retrieve-webhook-endpoint) — `GET /api/public/v1/webhook-endpoints/{{webhookEndpointId}}`"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', () => pm.response.to.have.status(200));",
                  "pm.test('id matches', () => pm.expect(pm.response.json().id).to.eql(pm.collectionVariables.get('webhookEndpointId')));"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "GET",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/webhook-endpoints/{{webhookEndpointId}}"
                }
              },
              "status": "OK",
              "code": 200,
              "body": "{ \"id\": \"we_44444444-4444-4444-4444-444444444444\", \"url\": \"https://your.app/api/frag/webhook\", \"events\": [\"payment_intent.settled\"], \"enabled\": true, \"created_at\": \"2026-07-18T18:22:00Z\" }",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Retrieve Webhook Endpoint → 200 OK](https://frag.cash/docs/api#retrieve-webhook-endpoint-200-ok)\n\n---\n📖 Docs: [Retrieve Webhook Endpoint → 200 OK](https://frag.cash/docs/api#retrieve-webhook-endpoint-200-ok)"
            }
          ]
        },
        {
          "name": "Update Webhook Endpoint",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/public/v1/webhook-endpoints/{{webhookEndpointId}}",
              "host": ["{{baseUrl}}"],
              "path": ["api", "public", "v1", "webhook-endpoints", "{{webhookEndpointId}}"]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"events\": [\"payment_intent.settled\", \"payment_intent.failed\", \"payout.paid\"],\n  \"enabled\": true\n}"
            },
            "description": "---\n📖 Docs: [Webhook Endpoints · Update Webhook Endpoint](https://frag.cash/docs/api#update-webhook-endpoint) — `PATCH /api/public/v1/webhook-endpoints/{{webhookEndpointId}}`"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', () => pm.response.to.have.status(200));",
                  "const body = pm.response.json();",
                  "pm.test('events updated', () => pm.expect(body.events).to.be.an('array'));"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "PATCH",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/webhook-endpoints/{{webhookEndpointId}}"
                }
              },
              "status": "OK",
              "code": 200,
              "body": "{ \"id\": \"we_44444444-4444-4444-4444-444444444444\", \"url\": \"https://your.app/api/frag/webhook\", \"events\": [\"payment_intent.settled\", \"payment_intent.failed\", \"payout.paid\"], \"enabled\": true, \"created_at\": \"2026-07-18T18:22:00Z\" }",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Update Webhook Endpoint → 200 OK](https://frag.cash/docs/api#update-webhook-endpoint-200-ok)\n\n---\n📖 Docs: [Update Webhook Endpoint → 200 OK](https://frag.cash/docs/api#update-webhook-endpoint-200-ok)"
            }
          ]
        },
        {
          "name": "Rotate Signing Secret",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{baseUrl}}/api/public/v1/webhook-endpoints/{{webhookEndpointId}}/rotate-secret",
              "host": ["{{baseUrl}}"],
              "path": [
                "api",
                "public",
                "v1",
                "webhook-endpoints",
                "{{webhookEndpointId}}",
                "rotate-secret"
              ]
            },
            "description": "Rotates the endpoint's signing secret. The new plaintext secret is returned exactly once — store it, then update your verifier.\n\n---\n📖 Docs: [Webhook Endpoints · Rotate Signing Secret](https://frag.cash/docs/api#rotate-signing-secret) — `POST /api/public/v1/webhook-endpoints/{{webhookEndpointId}}/rotate-secret`"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', () => pm.response.to.have.status(200));",
                  "const body = pm.response.json();",
                  "pm.test('rotated secret returned', () => pm.expect(body.signing_secret).to.match(/^whsec_/));",
                  "if (body.signing_secret) pm.collectionVariables.set('webhookSigningSecret', body.signing_secret);"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "POST",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/webhook-endpoints/{{webhookEndpointId}}/rotate-secret"
                }
              },
              "status": "OK",
              "code": 200,
              "body": "{ \"id\": \"we_44444444-4444-4444-4444-444444444444\", \"url\": \"https://your.app/api/frag/webhook\", \"events\": [\"payment_intent.settled\"], \"enabled\": true, \"signing_secret\": \"whsec_new0secretHexvalue0here0000000000000000000000000000\", \"created_at\": \"2026-07-18T18:22:00Z\" }",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Rotate Signing Secret → 200 OK](https://frag.cash/docs/api#rotate-signing-secret-200-ok)\n\n---\n📖 Docs: [Rotate Signing Secret → 200 OK](https://frag.cash/docs/api#rotate-signing-secret-200-ok)"
            }
          ]
        },
        {
          "name": "Delete Webhook Endpoint",
          "request": {
            "method": "DELETE",
            "url": {
              "raw": "{{baseUrl}}/api/public/v1/webhook-endpoints/{{webhookEndpointId}}",
              "host": ["{{baseUrl}}"],
              "path": ["api", "public", "v1", "webhook-endpoints", "{{webhookEndpointId}}"]
            },
            "description": "---\n📖 Docs: [Webhook Endpoints · Delete Webhook Endpoint](https://frag.cash/docs/api#delete-webhook-endpoint) — `DELETE /api/public/v1/webhook-endpoints/{{webhookEndpointId}}`"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', () => pm.response.to.have.status(200));",
                  "pm.test('deleted flag', () => pm.expect(pm.response.json().deleted).to.eql(true));"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "DELETE",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/webhook-endpoints/{{webhookEndpointId}}"
                }
              },
              "status": "OK",
              "code": 200,
              "body": "{ \"deleted\": true }",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Delete Webhook Endpoint → 200 OK](https://frag.cash/docs/api#delete-webhook-endpoint-200-ok)\n\n---\n📖 Docs: [Delete Webhook Endpoint → 200 OK](https://frag.cash/docs/api#delete-webhook-endpoint-200-ok)"
            }
          ]
        }
      ]
    },
    {
      "name": "Public / Unauthenticated",
      "description": "Endpoints that don't require a secret key. Safe to call from browsers.",
      "item": [
        {
          "name": "Public Checkout state (poll)",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/public/v1/checkout/{{intentId}}",
              "host": ["{{baseUrl}}"],
              "path": ["api", "public", "v1", "checkout", "{{intentId}}"]
            },
            "description": "Used by the browser SDK to poll intent status. Returns only safe fields — no merchant PII, no keys.\n\n---\n📖 Docs: [Public / Unauthenticated · Public Checkout state (poll)](https://frag.cash/docs/api#public-checkout-state-poll) — `GET /api/public/v1/checkout/{{intentId}}`"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', () => pm.response.to.have.status(200));",
                  "const body = pm.response.json();",
                  "pm.test('has status field', () => pm.expect(body.status).to.be.a('string'));",
                  "pm.test('no sensitive fields', () => {",
                  "  pm.expect(body).to.not.have.property('merchant_id');",
                  "  pm.expect(body).to.not.have.property('secret_hash');",
                  "});"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "GET",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/checkout/{{intentId}}"
                }
              },
              "status": "OK",
              "code": 200,
              "body": "{ \"id\": \"pi_11111111-1111-1111-1111-111111111111\", \"amount\": \"99.00\", \"currency\": \"USD\", \"status\": \"executing\", \"settlement_chain\": \"solana\", \"settlement_token\": \"USDC\", \"expires_at\": \"2026-07-18T18:52:00Z\", \"metadata\": { \"orderId\": \"order_8841\" } }",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Public Checkout state (poll) → 200 OK](https://frag.cash/docs/api#public-checkout-state-poll-200-ok)\n\n---\n📖 Docs: [Public Checkout state (poll) → 200 OK](https://frag.cash/docs/api#public-checkout-state-poll-200-ok)"
            }
          ]
        },
        {
          "name": "Supported Tokens",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/public/v1/tokens?chain=solana",
              "host": ["{{baseUrl}}"],
              "path": ["api", "public", "v1", "tokens"],
              "query": [
                {
                  "key": "chain",
                  "value": "solana",
                  "description": "Optional — filter to a single chain"
                }
              ]
            },
            "description": "---\n📖 Docs: [Public / Unauthenticated · Supported Tokens](https://frag.cash/docs/api#supported-tokens) — `GET /api/public/v1/tokens?chain=solana`"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', () => pm.response.to.have.status(200));",
                  "const body = pm.response.json();",
                  "pm.test('data is array', () => pm.expect(body.data).to.be.an('array'));",
                  "if (body.data.length) {",
                  "  pm.test('tokens are unblocked', () => pm.expect(body.data.every(t => t.blocked === false)).to.eql(true));",
                  "}"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "GET",
                "url": {
                  "raw": "{{baseUrl}}/api/public/v1/tokens?chain=solana"
                }
              },
              "status": "OK",
              "code": 200,
              "body": "{ \"data\": [ { \"chain\": \"solana\", \"address\": \"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\", \"symbol\": \"USDC\", \"name\": \"USD Coin\", \"decimals\": 6, \"verified\": true, \"min_liquidity_usd\": 1000000, \"blocked\": false } ] }",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Supported Tokens → 200 OK](https://frag.cash/docs/api#supported-tokens-200-ok)\n\n---\n📖 Docs: [Supported Tokens → 200 OK](https://frag.cash/docs/api#supported-tokens-200-ok)"
            }
          ]
        },
        {
          "name": "Health Check",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/public/health",
              "host": ["{{baseUrl}}"],
              "path": ["api", "public", "health"]
            },
            "description": "---\n📖 Docs: [Public / Unauthenticated · Health Check](https://frag.cash/docs/api#health-check) — `GET /api/public/health`"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200 or 503', () => pm.expect([200, 503]).to.include(pm.response.code));",
                  "const body = pm.response.json();",
                  "pm.test('service is frag', () => pm.expect(body.service).to.eql('frag'));",
                  "pm.test('reports checks', () => pm.expect(body.checks).to.be.an('object'));"
                ]
              }
            }
          ],
          "response": [
            {
              "name": "200 OK",
              "originalRequest": {
                "method": "GET",
                "url": {
                  "raw": "{{baseUrl}}/api/public/health"
                }
              },
              "status": "OK",
              "code": 200,
              "body": "{\n  \"status\": \"ok\",\n  \"service\": \"frag\",\n  \"version\": \"2026.07.18\",\n  \"time\": \"2026-07-18T18:22:00Z\",\n  \"latency_ms\": 12,\n  \"checks\": {\n    \"env\": { \"supabase_url\": true, \"supabase_publishable\": true, \"cron_secret\": true },\n    \"database\": \"ok\"\n  }\n}",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Health Check → 200 OK](https://frag.cash/docs/api#health-check-200-ok)\n\n---\n📖 Docs: [Health Check → 200 OK](https://frag.cash/docs/api#health-check-200-ok)"
            },
            {
              "name": "503 database down",
              "originalRequest": {
                "method": "GET",
                "url": {
                  "raw": "{{baseUrl}}/api/public/health"
                }
              },
              "status": "Service Unavailable",
              "code": 503,
              "body": "{ \"status\": \"down\", \"service\": \"frag\", \"checks\": { \"database\": \"down\" } }",
              "_postman_previewlanguage": "json",
              "description": "\n\n---\n📖 Docs: [Health Check → 503 database down](https://frag.cash/docs/api#health-check-503-database-down)\n\n---\n📖 Docs: [Health Check → 503 database down](https://frag.cash/docs/api#health-check-503-database-down)"
            }
          ]
        }
      ]
    }
  ]
}
