{
  "info": {
    "name": "TulaDB eval",
    "description": "TulaDB quick evaluation: the SDK REST API (port 8080) and the dashboard API (port 3000) of the eval stack (./eval.sh up). Select an environment with gatewayApiKey and dashboardApiKey (./eval.sh postman writes one for your stack), then run the folders in order. Re-runs are safe: runId makes every txn_id new, and setup accepts what already exists.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "type": "text/javascript",
        "exec": [
          "// A fresh runId per collection run keeps every txn_id unique.",
          "if (!pm.collectionVariables.get('runId')) { pm.collectionVariables.set('runId', String(Date.now())); }"
        ]
      }
    }
  ],
  "variable": [
    {
      "key": "ledgerId",
      "value": "1"
    },
    {
      "key": "currency",
      "value": "USD"
    },
    {
      "key": "currencyNumeric",
      "value": "840"
    },
    {
      "key": "sourceAlpha",
      "value": "EVAL"
    },
    {
      "key": "sourceId",
      "value": "7"
    },
    {
      "key": "controlAccountId",
      "value": "1000"
    },
    {
      "key": "accountA",
      "value": "1001"
    },
    {
      "key": "accountB",
      "value": "1002"
    },
    {
      "key": "accountCapped",
      "value": "1003"
    },
    {
      "key": "runId",
      "value": ""
    }
  ],
  "item": [
    {
      "name": "1. Health",
      "item": [
        {
          "name": "SDK server health",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200', () => pm.expect(pm.response.code).to.be.oneOf([200]));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{gatewayUrl}}/v1/healthz",
              "host": [
                "{{gatewayUrl}}"
              ],
              "path": [
                "v1",
                "healthz"
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{gatewayApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            },
            "description": "Public: no API key needed. ok:true once the server can reach an engine."
          }
        },
        {
          "name": "SDK server and engine versions",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200', () => pm.expect(pm.response.code).to.be.oneOf([200]));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{gatewayUrl}}/v1/version",
              "host": [
                "{{gatewayUrl}}"
              ],
              "path": [
                "v1",
                "version"
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{gatewayApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "SDK server routes",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200', () => pm.expect(pm.response.code).to.be.oneOf([200]));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{gatewayUrl}}/v1/routes",
              "host": [
                "{{gatewayUrl}}"
              ],
              "path": [
                "v1",
                "routes"
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{gatewayApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            },
            "description": "The engine route per (currency, ledger): here every write goes to the 3-node cluster."
          }
        },
        {
          "name": "Cluster status (dashboard)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200', () => pm.expect(pm.response.code).to.be.oneOf([200]));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{dashboardUrl}}/api/cluster",
              "host": [
                "{{dashboardUrl}}"
              ],
              "path": [
                "api",
                "cluster"
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{dashboardApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            },
            "description": "Leader, roles and indexes of the three nodes."
          }
        }
      ]
    },
    {
      "name": "2. Setup",
      "item": [
        {
          "name": "Create ledger 1 (USD)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200,409",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200 or 409', () => pm.expect(pm.response.code).to.be.oneOf([200, 409]));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{dashboardUrl}}/api/ledger-instances",
              "host": [
                "{{dashboardUrl}}"
              ],
              "path": [
                "api",
                "ledger-instances"
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{dashboardApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"ledger_id\": {{ledgerId}},\n  \"name\": \"eval\",\n  \"currency\": \"{{currencyNumeric}}\",\n  \"mode\": \"default\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Registers ledger 1 in the engine's ledger registry. 409: it already exists (re-run)."
          }
        },
        {
          "name": "Register source EVAL",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200,409,422",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200 or 409 or 422', () => pm.expect(pm.response.code).to.be.oneOf([200, 409, 422]));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{gatewayUrl}}/v1/sources",
              "host": [
                "{{gatewayUrl}}"
              ],
              "path": [
                "v1",
                "sources"
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{gatewayApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"currency\": \"{{currency}}\",\n  \"alpha\": \"{{sourceAlpha}}\",\n  \"numeric\": {{sourceId}}\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Every write names its source system (source_id); txn_id is unique per source. 409/422: already registered."
          }
        },
        {
          "name": "Create control account 1000",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200,409",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200 or 409', () => pm.expect(pm.response.code).to.be.oneOf([200, 409]));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{dashboardUrl}}/api/control-accounts",
              "host": [
                "{{dashboardUrl}}"
              ],
              "path": [
                "api",
                "control-accounts"
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{dashboardApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"ledger_id\": {{ledgerId}},\n  \"id\": {{controlAccountId}}\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "The ledger's control (funding) account. 409: it already exists."
          }
        },
        {
          "name": "Create account 1001",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200,409",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200 or 409', () => pm.expect(pm.response.code).to.be.oneOf([200, 409]));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{dashboardUrl}}/api/accounts",
              "host": [
                "{{dashboardUrl}}"
              ],
              "path": [
                "api",
                "accounts"
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{dashboardApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"ledger_id\": {{ledgerId}},\n  \"id\": {{accountA}}\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "No limits: the balance may go negative."
          }
        },
        {
          "name": "Create account 1002",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200,409",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200 or 409', () => pm.expect(pm.response.code).to.be.oneOf([200, 409]));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{dashboardUrl}}/api/accounts",
              "host": [
                "{{dashboardUrl}}"
              ],
              "path": [
                "api",
                "accounts"
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{dashboardApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"ledger_id\": {{ledgerId}},\n  \"id\": {{accountB}}\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Create account 1003 (limit_low 0)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200,409",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200 or 409', () => pm.expect(pm.response.code).to.be.oneOf([200, 409]));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{dashboardUrl}}/api/accounts",
              "host": [
                "{{dashboardUrl}}"
              ],
              "path": [
                "api",
                "accounts"
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{dashboardApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"ledger_id\": {{ledgerId}},\n  \"id\": {{accountCapped}},\n  \"limit_low\": 0\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Its balance may not go below 0: the decline example below spends from it."
          }
        },
        {
          "name": "Fund account 1001 with 1,000.00",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200', () => pm.expect(pm.response.code).to.be.oneOf([200]));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{dashboardUrl}}/api/accounts/{{accountA}}/fund",
              "host": [
                "{{dashboardUrl}}"
              ],
              "path": [
                "api",
                "accounts",
                "{{accountA}}",
                "fund"
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{dashboardApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"ledger_id\": {{ledgerId}},\n  \"control_account_id\": {{controlAccountId}},\n  \"amount\": \"1000.00\",\n  \"txn_id\": \"fund-a-{{runId}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "A funding transfer from the control account."
          }
        }
      ]
    },
    {
      "name": "3. Transfers",
      "item": [
        {
          "name": "Transfer 25.00 from 1001 to 1002",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200",
                  "// capture: transferId = ledgerd_response.transfer_id",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200', () => pm.expect(pm.response.code).to.be.oneOf([200]));",
                  "if (pm.response.code === 200) {",
                  "  pm.collectionVariables.set(\"transferId\", pm.response.json()[\"ledgerd_response\"][\"transfer_id\"]);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{gatewayUrl}}/v1/transfer",
              "host": [
                "{{gatewayUrl}}"
              ],
              "path": [
                "v1",
                "transfer"
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{gatewayApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"currency\": \"{{currency}}\",\n  \"ledger_id\": {{ledgerId}},\n  \"source_id\": {{sourceId}},\n  \"debit_account_id\": \"{{accountA}}\",\n  \"credit_account_id\": \"{{accountB}}\",\n  \"amount\": 2500,\n  \"txn_id\": \"t1-{{runId}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "amount is in minor units (USD has scale 2: 2500 = 25.00); amount_decimal takes \"25.00\" instead."
          }
        },
        {
          "name": "Retry the same transfer (idempotent)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 409",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 409', () => pm.expect(pm.response.code).to.be.oneOf([409]));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{gatewayUrl}}/v1/transfer",
              "host": [
                "{{gatewayUrl}}"
              ],
              "path": [
                "v1",
                "transfer"
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{gatewayApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"currency\": \"{{currency}}\",\n  \"ledger_id\": {{ledgerId}},\n  \"source_id\": {{sourceId}},\n  \"debit_account_id\": \"{{accountA}}\",\n  \"credit_account_id\": \"{{accountB}}\",\n  \"amount\": 2500,\n  \"txn_id\": \"t1-{{runId}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Same source_id + txn_id: 409 duplicate_txn. The original write succeeded and is not applied twice."
          }
        },
        {
          "name": "Transfer with amount_decimal",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200', () => pm.expect(pm.response.code).to.be.oneOf([200]));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{gatewayUrl}}/v1/transfer",
              "host": [
                "{{gatewayUrl}}"
              ],
              "path": [
                "v1",
                "transfer"
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{gatewayApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"currency\": \"{{currency}}\",\n  \"ledger_id\": {{ledgerId}},\n  \"source_id\": {{sourceId}},\n  \"debit_account_id\": \"{{accountA}}\",\n  \"credit_account_id\": \"{{accountB}}\",\n  \"amount_decimal\": \"1.50\",\n  \"txn_id\": \"t2-{{runId}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Declined: 1003 has no funds",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200', () => pm.expect(pm.response.code).to.be.oneOf([200]));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{gatewayUrl}}/v1/transfer",
              "host": [
                "{{gatewayUrl}}"
              ],
              "path": [
                "v1",
                "transfer"
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{gatewayApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"currency\": \"{{currency}}\",\n  \"ledger_id\": {{ledgerId}},\n  \"source_id\": {{sourceId}},\n  \"debit_account_id\": \"{{accountCapped}}\",\n  \"credit_account_id\": \"{{accountA}}\",\n  \"amount\": 500,\n  \"txn_id\": \"t3-{{runId}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "HTTP 200 with ok:false: the ledger's verdict (limit_low 0), recorded durably; a retry returns the same decline."
          }
        },
        {
          "name": "Batch of 3 transfers",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200', () => pm.expect(pm.response.code).to.be.oneOf([200]));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{gatewayUrl}}/v1/batch/transfers",
              "host": [
                "{{gatewayUrl}}"
              ],
              "path": [
                "v1",
                "batch",
                "transfers"
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{gatewayApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"transfers\": [\n    {\n      \"currency\": \"{{currency}}\",\n      \"ledger_id\": {{ledgerId}},\n      \"source_id\": {{sourceId}},\n      \"debit_account_id\": \"{{accountA}}\",\n      \"credit_account_id\": \"{{accountB}}\",\n      \"amount\": 100,\n      \"txn_id\": \"b1-{{runId}}\"\n    },\n    {\n      \"currency\": \"{{currency}}\",\n      \"ledger_id\": {{ledgerId}},\n      \"source_id\": {{sourceId}},\n      \"debit_account_id\": \"{{accountA}}\",\n      \"credit_account_id\": \"{{accountB}}\",\n      \"amount\": 200,\n      \"txn_id\": \"b2-{{runId}}\"\n    },\n    {\n      \"currency\": \"{{currency}}\",\n      \"ledger_id\": {{ledgerId}},\n      \"source_id\": {{sourceId}},\n      \"debit_account_id\": \"{{accountB}}\",\n      \"credit_account_id\": \"{{accountA}}\",\n      \"amount\": 50,\n      \"txn_id\": \"b3-{{runId}}\"\n    }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Each item has its own outcome in results[], in request order."
          }
        }
      ]
    },
    {
      "name": "4. Two-phase (reserve / commit)",
      "item": [
        {
          "name": "Reserve 7.00 from 1001",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200",
                  "// capture: reservationId = ledgerd_response.transfer_id",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200', () => pm.expect(pm.response.code).to.be.oneOf([200]));",
                  "if (pm.response.code === 200) {",
                  "  pm.collectionVariables.set(\"reservationId\", pm.response.json()[\"ledgerd_response\"][\"transfer_id\"]);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{gatewayUrl}}/v1/reserve",
              "host": [
                "{{gatewayUrl}}"
              ],
              "path": [
                "v1",
                "reserve"
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{gatewayApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"currency\": \"{{currency}}\",\n  \"ledger_id\": {{ledgerId}},\n  \"source_id\": {{sourceId}},\n  \"debit_account_id\": \"{{accountA}}\",\n  \"credit_account_id\": \"{{accountB}}\",\n  \"amount\": 700,\n  \"txn_id\": \"r1-{{runId}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Holds the amount on the debit side (debits_pending)."
          }
        },
        {
          "name": "Pending reservations",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200', () => pm.expect(pm.response.code).to.be.oneOf([200]));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{gatewayUrl}}/v1/pending-reservations?ledger_id={{ledgerId}}&currency={{currency}}",
              "host": [
                "{{gatewayUrl}}"
              ],
              "path": [
                "v1",
                "pending-reservations"
              ],
              "query": [
                {
                  "key": "ledger_id",
                  "value": "{{ledgerId}}"
                },
                {
                  "key": "currency",
                  "value": "{{currency}}"
                }
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{gatewayApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "Commit the reservation",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200', () => pm.expect(pm.response.code).to.be.oneOf([200]));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{gatewayUrl}}/v1/commit",
              "host": [
                "{{gatewayUrl}}"
              ],
              "path": [
                "v1",
                "commit"
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{gatewayApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"currency\": \"{{currency}}\",\n  \"ledger_id\": {{ledgerId}},\n  \"transfer_id\": \"{{reservationId}}\",\n  \"txn_id\": \"r1c-{{runId}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Posts the held amount; /v1/rollback releases it instead."
          }
        }
      ]
    },
    {
      "name": "5. Rejects",
      "item": [
        {
          "name": "Record an explicit reject",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200', () => pm.expect(pm.response.code).to.be.oneOf([200]));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{gatewayUrl}}/v1/reject",
              "host": [
                "{{gatewayUrl}}"
              ],
              "path": [
                "v1",
                "reject"
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{gatewayApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"currency\": \"{{currency}}\",\n  \"ledger_id\": {{ledgerId}},\n  \"source_id\": {{sourceId}},\n  \"debit_account_id\": \"{{accountA}}\",\n  \"credit_account_id\": \"{{accountB}}\",\n  \"amount\": 900,\n  \"txn_id\": \"x1-{{runId}}\",\n  \"reason_code\": 1001\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "An upstream decision recorded in the ledger (status 41); it moves no value. reason_code is yours."
          }
        },
        {
          "name": "Rejected transfers",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200', () => pm.expect(pm.response.code).to.be.oneOf([200]));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{gatewayUrl}}/v1/rejected-transfers?ledger_id={{ledgerId}}&currency={{currency}}&limit=10",
              "host": [
                "{{gatewayUrl}}"
              ],
              "path": [
                "v1",
                "rejected-transfers"
              ],
              "query": [
                {
                  "key": "ledger_id",
                  "value": "{{ledgerId}}"
                },
                {
                  "key": "currency",
                  "value": "{{currency}}"
                },
                {
                  "key": "limit",
                  "value": "10"
                }
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{gatewayApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            },
            "description": "Explicit rejects and ledger declines."
          }
        }
      ]
    },
    {
      "name": "6. Queries",
      "item": [
        {
          "name": "Balance of 1001",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200', () => pm.expect(pm.response.code).to.be.oneOf([200]));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{gatewayUrl}}/v1/ledgers/{{ledgerId}}/currencies/{{currency}}/accounts/{{accountA}}/balance",
              "host": [
                "{{gatewayUrl}}"
              ],
              "path": [
                "v1",
                "ledgers",
                "{{ledgerId}}",
                "currencies",
                "{{currency}}",
                "accounts",
                "{{accountA}}",
                "balance"
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{gatewayApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "Account 1002",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200', () => pm.expect(pm.response.code).to.be.oneOf([200]));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{gatewayUrl}}/v1/ledgers/{{ledgerId}}/currencies/{{currency}}/accounts/{{accountB}}",
              "host": [
                "{{gatewayUrl}}"
              ],
              "path": [
                "v1",
                "ledgers",
                "{{ledgerId}}",
                "currencies",
                "{{currency}}",
                "accounts",
                "{{accountB}}"
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{gatewayApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "History of 1001",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200', () => pm.expect(pm.response.code).to.be.oneOf([200]));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{gatewayUrl}}/v1/ledgers/{{ledgerId}}/currencies/{{currency}}/accounts/{{accountA}}/history?limit=20",
              "host": [
                "{{gatewayUrl}}"
              ],
              "path": [
                "v1",
                "ledgers",
                "{{ledgerId}}",
                "currencies",
                "{{currency}}",
                "accounts",
                "{{accountA}}",
                "history"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "20"
                }
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{gatewayApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "Transaction by id",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200', () => pm.expect(pm.response.code).to.be.oneOf([200]));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{gatewayUrl}}/v1/transactions/{{transferId}}?ledger_id={{ledgerId}}&currency={{currency}}",
              "host": [
                "{{gatewayUrl}}"
              ],
              "path": [
                "v1",
                "transactions",
                "{{transferId}}"
              ],
              "query": [
                {
                  "key": "ledger_id",
                  "value": "{{ledgerId}}"
                },
                {
                  "key": "currency",
                  "value": "{{currency}}"
                }
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{gatewayApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "Transaction by reference (source + txn_id)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200', () => pm.expect(pm.response.code).to.be.oneOf([200]));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{gatewayUrl}}/v1/transactions/by-ref?source_id={{sourceId}}&txn_id=t1-{{runId}}&ledger_id={{ledgerId}}&currency={{currency}}",
              "host": [
                "{{gatewayUrl}}"
              ],
              "path": [
                "v1",
                "transactions",
                "by-ref"
              ],
              "query": [
                {
                  "key": "source_id",
                  "value": "{{sourceId}}"
                },
                {
                  "key": "txn_id",
                  "value": "t1-{{runId}}"
                },
                {
                  "key": "ledger_id",
                  "value": "{{ledgerId}}"
                },
                {
                  "key": "currency",
                  "value": "{{currency}}"
                }
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{gatewayApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "Accounts in ledger 1",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200', () => pm.expect(pm.response.code).to.be.oneOf([200]));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{gatewayUrl}}/v1/accounts?ledger_id={{ledgerId}}&currency={{currency}}&limit=50",
              "host": [
                "{{gatewayUrl}}"
              ],
              "path": [
                "v1",
                "accounts"
              ],
              "query": [
                {
                  "key": "ledger_id",
                  "value": "{{ledgerId}}"
                },
                {
                  "key": "currency",
                  "value": "{{currency}}"
                },
                {
                  "key": "limit",
                  "value": "50"
                }
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{gatewayApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            }
          }
        },
        {
          "name": "Every currency balance of 1001",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200', () => pm.expect(pm.response.code).to.be.oneOf([200]));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{gatewayUrl}}/v1/ledgers/{{ledgerId}}/accounts/{{accountA}}/balances",
              "host": [
                "{{gatewayUrl}}"
              ],
              "path": [
                "v1",
                "ledgers",
                "{{ledgerId}}",
                "accounts",
                "{{accountA}}",
                "balances"
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{gatewayApiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            }
          }
        }
      ]
    },
    {
      "name": "7. Metrics",
      "item": [
        {
          "name": "Scrape targets up",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200', () => pm.expect(pm.response.code).to.be.oneOf([200]));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{prometheusUrl}}/api/v1/query?query=up%7Bjob%3D%22tuladb%22%7D",
              "host": [
                "{{prometheusUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "query"
              ],
              "query": [
                {
                  "key": "query",
                  "value": "up%7Bjob%3D%22tuladb%22%7D"
                }
              ]
            },
            "auth": {
              "type": "noauth"
            },
            "description": "One series per node exporter; value 1 = scraped."
          }
        },
        {
          "name": "Accepted transfers per node",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200', () => pm.expect(pm.response.code).to.be.oneOf([200]));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{prometheusUrl}}/api/v1/query?query=tuladb_transfers_accepted_total",
              "host": [
                "{{prometheusUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "query"
              ],
              "query": [
                {
                  "key": "query",
                  "value": "tuladb_transfers_accepted_total"
                }
              ]
            },
            "auth": {
              "type": "noauth"
            }
          }
        },
        {
          "name": "Node roles",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// expect: 200",
                  "// A 503 is retryable (the server could not reach an engine): try again, at most 5 times.",
                  "const tries = Number(pm.collectionVariables.get('_retries') || 0);",
                  "if (pm.response.code === 503 && tries < 5) {",
                  "  pm.collectionVariables.set('_retries', tries + 1);",
                  "  setTimeout(() => {}, 1000);",
                  "  pm.execution.setNextRequest(pm.info.requestName);",
                  "  return;",
                  "}",
                  "pm.collectionVariables.set('_retries', 0);",
                  "pm.test('HTTP 200', () => pm.expect(pm.response.code).to.be.oneOf([200]));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{prometheusUrl}}/api/v1/query?query=tuladb_node_role",
              "host": [
                "{{prometheusUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "query"
              ],
              "query": [
                {
                  "key": "query",
                  "value": "tuladb_node_role"
                }
              ]
            },
            "auth": {
              "type": "noauth"
            }
          }
        }
      ]
    }
  ]
}
