{
  "info": {
    "_postman_id": "8248bd48-91bf-4af4-a9e2-56052ae57231",
    "name": "Paynet Open Finance Hub - Build 09",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
    "_exporter_id": "38055270"
  },
  "item": [
    {
      "name": "Authorization Server Flows",
      "item": [
        {
          "name": "Authorization Flow - DP specified in consent",
          "item": [
            {
              "name": "10 - DC -> OFP: GET /.well-known/openid-configuration",
              "event": [
                {
                  "listen": "test",
                  "script": {
                    "exec": [
                      "const utilsSrc = pm.globals.get(\"utils\");",
                      "const utils = eval(utilsSrc); // returns the object from the IIFE",
                      "",
                      "if (pm.response.code !== 200) {",
                      "    utils.visualiseJson( \"Error\", pm.response.text());",
                      "    return;",
                      "} else {",
                      "    let jsonData = pm.response.json();",
                      "    pm.environment.set(\"auth-endpoint\", jsonData.authorization_endpoint);",
                      "    pm.environment.set(\"token-endpoint\", jsonData.token_endpoint);",
                      "    pm.environment.set(\"par-endpoint\", jsonData.pushed_authorization_request_endpoint);",
                      "    pm.environment.set(\"revocation_endpoint\", jsonData.revocation_endpoint);",
                      "    pm.environment.set(\"userinfo_endpoint\", jsonData.userinfo_endpoint);",
                      "    utils.visualiseJson( \".well-known\", jsonData);",
                      "}"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                },
                {
                  "listen": "prerequest",
                  "script": {
                    "exec": [
                      ""
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                }
              ],
              "protocolProfileBehavior": {
                "disableBodyPruning": true
              },
              "request": {
                "method": "GET",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/x-www-form-urlencoded"
                  }
                ],
                "body": {
                  "mode": "urlencoded",
                  "urlencoded": []
                },
                "url": {
                  "raw": "{{issuer}}/.well-known/openid-configuration",
                  "host": [
                    "{{issuer}}"
                  ],
                  "path": [
                    ".well-known",
                    "openid-configuration"
                  ]
                },
                "description": "Queries the .well-known OIDC endpoint.\n\nThis step identifies the various OIDC endpoints that should be used for subsequent steps."
              },
              "response": []
            },
            {
              "name": "20 - Set Context [Postman only]",
              "event": [
                {
                  "listen": "test",
                  "script": {
                    "exec": [
                      "const utilsSrc = pm.globals.get(\"utils\");",
                      "const utils = eval(utilsSrc); // returns the object from the IIFE",
                      "",
                      "if (pm.response.code !== 200) {",
                      "    utils.visualiseJson( \"Error\", pm.response.text());",
                      "    return;",
                      "} else {",
                      "    const jsonData = pm.response.json();",
                      "    pm.environment.set(\"dp_id\", jsonData.args.dp_id);",
                      "    utils.visualiseJson(\"Response\", jsonData);",
                      "}"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                }
              ],
              "protocolProfileBehavior": {
                "disableBodyPruning": true
              },
              "request": {
                "method": "GET",
                "header": [],
                "body": {
                  "mode": "urlencoded",
                  "urlencoded": []
                },
                "url": {
                  "raw": "https://postman-echo.com/get?dp_id=DP9876543210",
                  "protocol": "https",
                  "host": [
                    "postman-echo",
                    "com"
                  ],
                  "path": [
                    "get"
                  ],
                  "query": [
                    {
                      "key": "dp_id",
                      "value": "DP9876543210"
                    }
                  ]
                },
                "description": "Use this step to set parameters for the rest of this flow.\n\nIn the **Params** tab, enter one of the valid dp_ids:\n\n- DP9876543210\n    \n- DP9876543211\n    \n- DP9876543213\n    \n\nTo select a DP at the point of consent authorization, leave the field blank\n\nAlternatively, to test negative flows, you can enter any other value."
              },
              "response": []
            },
            {
              "name": "30 - Sign private_key_jwt [Utility]",
              "event": [
                {
                  "listen": "prerequest",
                  "script": {
                    "exec": [
                      "const uuid = require('uuid');",
                      "",
                      "pm.environment.set(\"exp\", (Date.now() / 1000) + 300);",
                      "pm.environment.set(\"nbf\", (Date.now() / 1000) - 10);",
                      "pm.environment.set(\"uuid\", uuid.v4());",
                      ""
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                },
                {
                  "listen": "test",
                  "script": {
                    "exec": [
                      "const utilsSrc = pm.globals.get(\"utils\");",
                      "const utils = eval(utilsSrc); // returns the object from the IIFE",
                      "",
                      "if (pm.response.code !== 200) {",
                      "    utils.visualiseJson( \"Error\", pm.response.text());",
                      "    return;",
                      "} else {",
                      "    pm.environment.set(\"private_key_jwt\", pm.response.text());",
                      "    utils.visualiseJws( \"private_key_jwt\", pm.response.text());",
                      "}"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                }
              ],
              "protocolProfileBehavior": {
                "disableBodyPruning": true
              },
              "request": {
                "method": "GET",
                "header": [
                  {
                    "key": "content-type",
                    "value": "application/json"
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n    \"header\": {\n        \"alg\": \"PS256\",\n        \"kid\": \"{{kid-local}}\"\n    },\n    \"body\": {\n        \"aud\": \"{{issuer}}\",\n        \"exp\": {{exp}},\n        \"iss\": \"{{_clientId}}\",\n        \"sub\": \"{{_clientId}}\",\n        \"jti\": \"{{uuid}}\",\n        \"iat\": {{nbf}}\n    },\n    \"signingKeyPEM\": \"{{pem-local}}\"\n}"
                },
                "url": {
                  "raw": "{{rs}}/o3/v1.0/message-signature",
                  "host": [
                    "{{rs}}"
                  ],
                  "path": [
                    "o3",
                    "v1.0",
                    "message-signature"
                  ]
                },
                "description": "This is a utility API call to create a private_key_jwt.\n\nThis private_key_jwt will be used in a subsequent step for OIDC client authentication to the PAR and token endpoints.\n\nIn a production implementation, the DC must sign the private key jwt using their private key."
              },
              "response": []
            },
            {
              "name": "40 - Sign PAR request [Utility]",
              "event": [
                {
                  "listen": "prerequest",
                  "script": {
                    "exec": [
                      "const uuid = require('uuid');",
                      "",
                      "pm.environment.set(\"exp\", Date.now() / 1000 + 300);",
                      "pm.environment.set(\"nbf\", (Date.now() / 1000) - 10);",
                      "",
                      "const codeVerifier = uuid.v4() + uuid.v4();",
                      "const hashedCodeVerifier = CryptoJS.SHA256(codeVerifier);",
                      "let codeChallenge = CryptoJS.enc.Base64.stringify(hashedCodeVerifier);",
                      "",
                      "codeChallenge = codeChallenge.replaceAll('+', '-');",
                      "codeChallenge = codeChallenge.replaceAll('/', '_');",
                      "if (codeChallenge.endsWith('=')) { codeChallenge = codeChallenge.substring(0, codeChallenge.length - 1)}",
                      "",
                      "pm.environment.set(\"code-challenge\", codeChallenge );",
                      "pm.environment.set(\"code-verifier\", codeVerifier );",
                      ""
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                },
                {
                  "listen": "test",
                  "script": {
                    "exec": [
                      "const utilsSrc = pm.globals.get(\"utils\");",
                      "const utils = eval(utilsSrc); // returns the object from the IIFE",
                      "",
                      "if (pm.response.code !== 200) {",
                      "    utils.visualiseJson( \"Error\", pm.response.text());",
                      "    return;",
                      "} else {",
                      "    pm.environment.set(\"requestObject\", pm.response.text());",
                      "    utils.visualiseJws( \"Request Object\", pm.response.text());",
                      "}"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                }
              ],
              "protocolProfileBehavior": {
                "disableBodyPruning": true
              },
              "request": {
                "method": "GET",
                "header": [
                  {
                    "key": "content-type",
                    "value": "application/json"
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n    \"header\": {\n        \"alg\": \"PS256\",\n        \"kid\": \"{{kid-local}}\"\n    },\n    \"body\": {\n        \"aud\": \"{{issuer}}\",\n        \"exp\": {{exp}},\n        \"iss\": \"{{_clientId}}\",\n        \"scope\": \"accounts profile\",\n        \"redirect_uri\": \"{{redirectUrl}}\",\n        \"client_id\": \"{{_clientId}}\",\n        \"nonce\": \"{{$guid}}\",\n        \"state\": \"{{$guid}}\",\n        \"nbf\": {{nbf}},\n        \"response_type\": \"code\",\n        \"code_challenge_method\": \"S256\",\n        \"code_challenge\": \"{{code-challenge}}\",\n        \"max_age\": 3600,\n        \"claims\": {\n            \"userinfo\": {\n                \"name\": null,\n                \"email\": null,\n                \"email_verified\": null,\n                \"id_type\": null,\n                \"hashed_id_number\": null\n            }\n        },\n        \"authorization_details\": [\n            {\n                \"type\": \"urn:openfinance-ml:account-access-consent:v1.2\",\n                \"consent\": {\n                    \"dc_id\": \"{{dc_id}}\",\n                    \"dp_id\": \"{{dp_id}}\",\n                    \"consent_type\": \"urn:openfinance-ml:account-access-consent:v1.2\",\n                    \"consent_purpose\": \"pfm\",\n                    \"permissions\": [\n                        \"read_accounts\", \n                        \"read_transactions\", \n                        \"read_balances\"\n                    ],\n                    \"expiration_datetime\": \"2026-05-31T21:06:00+08:00\"\n                }\n            }\n        ]\n    },\n    \"signingKeyPEM\": \"{{pem-local}}\"\n}"
                },
                "url": {
                  "raw": "{{rs}}/o3/v1.0/message-signature",
                  "host": [
                    "{{rs}}"
                  ],
                  "path": [
                    "o3",
                    "v1.0",
                    "message-signature"
                  ]
                },
                "description": "This is a utility API call to create a account access PAR request.\n\nThis JWT will be used in the subsequent step to call the PAR endpoint.\n\nIn a production implementation, the DC must sign the private key jwt using their private key.\n\nYou can modify the permissions and expiration_datetime in the body"
              },
              "response": []
            },
            {
              "name": "50 - DC -> OFP: POST /par",
              "event": [
                {
                  "listen": "test",
                  "script": {
                    "exec": [
                      "// Visualization for Auth Code URL",
                      "var template = `",
                      "<style>",
                      "    .container {",
                      "        font-family: Arial, sans-serif;",
                      "        padding: 20px;",
                      "    }",
                      "    .label {",
                      "        font-size: 14px;",
                      "        color: #666;",
                      "        margin-bottom: 10px;",
                      "    }",
                      "    .url-value {",
                      "        font-size: 14px;",
                      "        color: #333;",
                      "        word-break: break-all;",
                      "        font-family: monospace;",
                      "        background: #f5f5f5;",
                      "        padding: 15px;",
                      "        border-radius: 8px;",
                      "        margin-bottom: 15px;",
                      "    }",
                      "    .url-link {",
                      "        display: inline-block;",
                      "        background: #FF6C37;",
                      "        color: white;",
                      "        padding: 10px 20px;",
                      "        border-radius: 5px;",
                      "        text-decoration: none;",
                      "        font-size: 14px;",
                      "    }",
                      "    .url-link:hover {",
                      "        background: #e55a2b;",
                      "    }",
                      "</style>",
                      "<div class=\"container\">",
                      "  <div class=\"label\">Auth Code URL:</div>",
                      "  <div class=\"url-value\" id=\"authUrlText\">{{authCodeUrl}}</div>",
                      "",
                      "  <button type=\"button\" id=\"copyAuthUrl\">Copy to clipboard</button>",
                      "",
                      "  <!-- fallback -->",
                      "  <textarea id=\"authUrlTA\" style=\"position:absolute; left:-9999px; top:-9999px;\"></textarea>",
                      "",
                      "  <div id=\"copyStatus\" style=\"margin-top:8px;\"></div>",
                      "</div>",
                      "",
                      "<script>",
                      "  (function () {",
                      "    const url = \"{{{authCodeUrl}}}\";",
                      "    const btn = document.getElementById(\"copyAuthUrl\");",
                      "    const status = document.getElementById(\"copyStatus\");",
                      "    const ta = document.getElementById(\"authUrlTA\");",
                      "",
                      "    function setStatus(msg) {",
                      "      if (status) status.textContent = msg;",
                      "    }",
                      "",
                      "    async function copyModern() {",
                      "      await navigator.clipboard.writeText(url);",
                      "    }",
                      "",
                      "    function copyFallback() {",
                      "      ta.value = url;",
                      "      ta.focus();",
                      "      ta.select();",
                      "      const ok = document.execCommand(\"copy\");",
                      "      if (!ok) throw new Error(\"execCommand failed\");",
                      "    }",
                      "",
                      "    btn.addEventListener(\"click\", async function () {",
                      "      try {",
                      "        if (navigator.clipboard && window.isSecureContext) {",
                      "          await copyModern();",
                      "        } else {",
                      "          copyFallback();",
                      "        }",
                      "        setStatus(\"Copied.\");",
                      "      } catch (e) {",
                      "        setStatus(\"Copy failed. Select and copy manually.\");",
                      "      }",
                      "    });",
                      "  })();",
                      "</script>",
                      "`;",
                      "",
                      "const utilsSrc = pm.globals.get(\"utils\");",
                      "const utils = eval(utilsSrc); // returns the object from the IIFE",
                      "",
                      "if (pm.response.code !== 201) {",
                      "    utils.visualiseJson( \"Error\", pm.response.json());",
                      "    return;",
                      "} else {",
                      "   let jsonData = pm.response.json();",
                      "",
                      "    const clientId = pm.environment.get(\"_clientId\");",
                      "    const authEndpoint = pm.environment.get('auth-endpoint');",
                      "    console.log(authEndpoint);",
                      "",
                      "    const authCodeUrl = `${authEndpoint}?client_id=${clientId}&scope=openid&request_uri=${jsonData.request_uri}`;",
                      "    pm.environment.set(\"authCodeUrl\", authCodeUrl);",
                      "",
                      "    pm.visualizer.set(template, { authCodeUrl });",
                      "}"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                },
                {
                  "listen": "prerequest",
                  "script": {
                    "exec": [
                      "// set uuid and time",
                      "pm.environment.set(\"now\", (new Date()).toUTCString());",
                      "const uuid = require('uuid');",
                      "pm.environment.set(\"x-fapi-interaction-id\", uuid.v4());"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                }
              ],
              "request": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/x-www-form-urlencoded"
                  },
                  {
                    "key": "x-cert-dn",
                    "value": "",
                    "type": "text",
                    "disabled": true
                  },
                  {
                    "key": "x-fapi-interaction-id",
                    "value": "{{x-fapi-interaction-id}}",
                    "type": "text"
                  }
                ],
                "body": {
                  "mode": "urlencoded",
                  "urlencoded": [
                    {
                      "key": "client_id",
                      "value": "{{_clientId}}",
                      "type": "text"
                    },
                    {
                      "key": "request",
                      "value": "{{requestObject}}",
                      "type": "default"
                    },
                    {
                      "key": "client_assertion_type",
                      "value": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
                      "type": "text"
                    },
                    {
                      "key": "client_assertion",
                      "value": "{{private_key_jwt}}",
                      "type": "text"
                    }
                  ]
                },
                "url": {
                  "raw": "{{par-endpoint}}",
                  "host": [
                    "{{par-endpoint}}"
                  ]
                }
              },
              "response": []
            },
            {
              "name": "60 - DC -> OFP: POST /token [Auth-code Grant]",
              "event": [
                {
                  "listen": "test",
                  "script": {
                    "exec": [
                      "const utilsSrc = pm.globals.get(\"utils\");",
                      "const utils = eval(utilsSrc); // returns the object from the IIFE",
                      "",
                      "if (pm.response.code !== 200) {",
                      "    utils.visualiseJson( \"Error\", pm.response.text());",
                      "    return;",
                      "} else {",
                      "    let jsonData = pm.response.json();",
                      "",
                      "    pm.environment.set(\"token-from-auth-code-grant-accounts\", jsonData.access_token);",
                      "    pm.environment.set(\"refresh_token\", jsonData.refresh_token);",
                      "    pm.environment.set(\"consent\", jsonData.authorization_details[0].consent.consent_id);",
                      "    pm.environment.set(\"dc_id\", jsonData.authorization_details[0].consent.dc_id);",
                      "    pm.environment.set(\"account_id\", jsonData.authorization_details[0].consent.accounts[0].account_id);",
                      "",
                      "    utils.visualiseJws('id_token', jsonData.id_token);",
                      "}"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                },
                {
                  "listen": "prerequest",
                  "script": {
                    "exec": [
                      "// set uuid and time",
                      "pm.environment.set(\"now\", (new Date()).toUTCString());",
                      "const uuid = require('uuid');",
                      "pm.environment.set(\"x-fapi-interaction-id\", uuid.v4());"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                }
              ],
              "request": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/x-www-form-urlencoded"
                  },
                  {
                    "key": "x-cert-dn",
                    "value": "",
                    "type": "text",
                    "disabled": true
                  },
                  {
                    "key": "x-cert-fingerprint",
                    "value": "xxx",
                    "type": "text"
                  },
                  {
                    "key": "x-fapi-interaction-id",
                    "value": "{{x-fapi-interaction-id}}",
                    "type": "text"
                  }
                ],
                "body": {
                  "mode": "urlencoded",
                  "urlencoded": [
                    {
                      "key": "grant_type",
                      "value": "authorization_code",
                      "type": "text"
                    },
                    {
                      "key": "scope",
                      "value": "accounts",
                      "type": "text"
                    },
                    {
                      "key": "code",
                      "value": "{{authorizationCode}}",
                      "type": "text"
                    },
                    {
                      "key": "redirect_uri",
                      "value": "{{redirectUrl}}",
                      "type": "text"
                    },
                    {
                      "key": "code_verifier",
                      "value": "{{code-verifier}}",
                      "type": "default"
                    },
                    {
                      "key": "client_assertion_type",
                      "value": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
                      "type": "text"
                    },
                    {
                      "key": "client_assertion",
                      "value": "{{private_key_jwt}}",
                      "type": "text"
                    }
                  ]
                },
                "url": {
                  "raw": "{{token-endpoint}}",
                  "host": [
                    "{{token-endpoint}}"
                  ]
                },
                "description": "Copy the authorization code generated into the browser into the **Body** tab in the `code` parameter"
              },
              "response": []
            }
          ],
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  ""
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  ""
                ]
              }
            }
          ]
        },
        {
          "name": "Authorization Flow - DP not specified in consent",
          "item": [
            {
              "name": "10 - DC -> OFP: GET /.well-known/openid-configuration",
              "event": [
                {
                  "listen": "test",
                  "script": {
                    "exec": [
                      "const utilsSrc = pm.globals.get(\"utils\");",
                      "const utils = eval(utilsSrc); // returns the object from the IIFE",
                      "",
                      "if (pm.response.code !== 200) {",
                      "    utils.visualiseJson( \"Error\", pm.response.text());",
                      "    return;",
                      "} else {",
                      "    let jsonData = pm.response.json();",
                      "    pm.environment.set(\"auth-endpoint\", jsonData.authorization_endpoint);",
                      "    pm.environment.set(\"token-endpoint\", jsonData.token_endpoint);",
                      "    pm.environment.set(\"par-endpoint\", jsonData.pushed_authorization_request_endpoint);",
                      "    pm.environment.set(\"revocation_endpoint\", jsonData.revocation_endpoint);",
                      "    pm.environment.set(\"userinfo_endpoint\", jsonData.userinfo_endpoint);",
                      "    utils.visualiseJson( \".well-known\", jsonData);",
                      "}"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                },
                {
                  "listen": "prerequest",
                  "script": {
                    "exec": [
                      ""
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                }
              ],
              "protocolProfileBehavior": {
                "disableBodyPruning": true
              },
              "request": {
                "method": "GET",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/x-www-form-urlencoded"
                  }
                ],
                "body": {
                  "mode": "urlencoded",
                  "urlencoded": []
                },
                "url": {
                  "raw": "{{issuer}}/.well-known/openid-configuration",
                  "host": [
                    "{{issuer}}"
                  ],
                  "path": [
                    ".well-known",
                    "openid-configuration"
                  ]
                },
                "description": "Queries the .well-known OIDC endpoint.\n\nThis step identifies the various OIDC endpoints that should be used for subsequent steps."
              },
              "response": []
            },
            {
              "name": "30 - Sign private_key_jwt [Utility]",
              "event": [
                {
                  "listen": "prerequest",
                  "script": {
                    "exec": [
                      "const uuid = require('uuid');",
                      "",
                      "pm.environment.set(\"exp\", (Date.now() / 1000) + 300);",
                      "pm.environment.set(\"nbf\", (Date.now() / 1000) - 10);",
                      "pm.environment.set(\"uuid\", uuid.v4());",
                      ""
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                },
                {
                  "listen": "test",
                  "script": {
                    "exec": [
                      "const utilsSrc = pm.globals.get(\"utils\");",
                      "const utils = eval(utilsSrc); // returns the object from the IIFE",
                      "",
                      "if (pm.response.code !== 200) {",
                      "    utils.visualiseJson( \"Error\", pm.response.text());",
                      "    return;",
                      "} else {",
                      "    pm.environment.set(\"private_key_jwt\", pm.response.text());",
                      "    utils.visualiseJws( \"private_key_jwt\", pm.response.text());",
                      "}"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                }
              ],
              "protocolProfileBehavior": {
                "disableBodyPruning": true
              },
              "request": {
                "method": "GET",
                "header": [
                  {
                    "key": "content-type",
                    "value": "application/json"
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n    \"header\": {\n        \"alg\": \"PS256\",\n        \"kid\": \"{{kid-local}}\"\n    },\n    \"body\": {\n        \"aud\": \"{{issuer}}\",\n        \"exp\": {{exp}},\n        \"iss\": \"{{_clientId}}\",\n        \"sub\": \"{{_clientId}}\",\n        \"jti\": \"{{uuid}}\",\n        \"iat\": {{nbf}}\n    },\n    \"signingKeyPEM\": \"{{pem-local}}\"\n}"
                },
                "url": {
                  "raw": "{{rs}}/o3/v1.0/message-signature",
                  "host": [
                    "{{rs}}"
                  ],
                  "path": [
                    "o3",
                    "v1.0",
                    "message-signature"
                  ]
                },
                "description": "This is a utility API call to create a private_key_jwt.\n\nThis private_key_jwt will be used in a subsequent step for OIDC client authentication to the PAR and token endpoints.\n\nIn a production implementation, the DC must sign the private key jwt using their private key."
              },
              "response": []
            },
            {
              "name": "40 - Sign PAR request [Utility]",
              "event": [
                {
                  "listen": "prerequest",
                  "script": {
                    "exec": [
                      "const uuid = require('uuid');",
                      "",
                      "pm.environment.set(\"exp\", Date.now() / 1000 + 300);",
                      "pm.environment.set(\"nbf\", (Date.now() / 1000) - 10);",
                      "",
                      "const codeVerifier = uuid.v4() + uuid.v4();",
                      "const hashedCodeVerifier = CryptoJS.SHA256(codeVerifier);",
                      "let codeChallenge = CryptoJS.enc.Base64.stringify(hashedCodeVerifier);",
                      "",
                      "codeChallenge = codeChallenge.replaceAll('+', '-');",
                      "codeChallenge = codeChallenge.replaceAll('/', '_');",
                      "if (codeChallenge.endsWith('=')) { codeChallenge = codeChallenge.substring(0, codeChallenge.length - 1)}",
                      "",
                      "pm.environment.set(\"code-challenge\", codeChallenge );",
                      "pm.environment.set(\"code-verifier\", codeVerifier );",
                      ""
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                },
                {
                  "listen": "test",
                  "script": {
                    "exec": [
                      "const utilsSrc = pm.globals.get(\"utils\");",
                      "const utils = eval(utilsSrc); // returns the object from the IIFE",
                      "",
                      "if (pm.response.code !== 200) {",
                      "    utils.visualiseJson( \"Error\", pm.response.text());",
                      "    return;",
                      "} else {",
                      "    pm.environment.set(\"requestObject\", pm.response.text());",
                      "    utils.visualiseJws( \"Request Object\", pm.response.text());",
                      "}"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                }
              ],
              "protocolProfileBehavior": {
                "disableBodyPruning": true
              },
              "request": {
                "method": "GET",
                "header": [
                  {
                    "key": "content-type",
                    "value": "application/json"
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n    \"header\": {\n        \"alg\": \"PS256\",\n        \"kid\": \"{{kid-local}}\"\n    },\n    \"body\": {\n        \"aud\": \"{{issuer}}\",\n        \"exp\": {{exp}},\n        \"iss\": \"{{_clientId}}\",\n        \"scope\": \"accounts profile\",\n        \"redirect_uri\": \"{{redirectUrl}}\",\n        \"client_id\": \"{{_clientId}}\",\n        \"nonce\": \"{{$guid}}\",\n        \"state\": \"{{$guid}}\",\n        \"nbf\": {{nbf}},\n        \"response_type\": \"code\",\n        \"code_challenge_method\": \"S256\",\n        \"code_challenge\": \"{{code-challenge}}\",\n        \"max_age\": 3600,\n        \"claims\": {\n            \"userinfo\": {\n                \"name\": null,\n                \"email\": null,\n                \"email_verified\": null,\n                \"id_type\": null,\n                \"hashed_id_number\": null\n            }\n        },\n        \"authorization_details\": [\n            {\n                \"type\": \"urn:openfinance-ml:account-access-consent:v1.2\",\n                \"consent\": {\n                    \"dc_id\": \"{{dc_id}}\",\n                    // \"dp_id\": \"{{dp_id}}\",\n                    \"consent_type\": \"urn:openfinance-ml:account-access-consent:v1.2\",\n                    \"consent_purpose\": \"pfm\",\n                    \"permissions\": [\n                        \"read_accounts\", \n                        \"read_transactions\", \n                        \"read_balances\"\n                    ],\n                    \"expiration_datetime\": \"2026-12-31T23:59:00+08:00\"\n                }\n            }\n        ]\n    },\n    \"signingKeyPEM\": \"{{pem-local}}\"\n}"
                },
                "url": {
                  "raw": "{{rs}}/o3/v1.0/message-signature",
                  "host": [
                    "{{rs}}"
                  ],
                  "path": [
                    "o3",
                    "v1.0",
                    "message-signature"
                  ]
                },
                "description": "This is a utility API call to create a account access PAR request.\n\nThis JWT will be used in the subsequent step to call the PAR endpoint.\n\nIn a production implementation, the DC must sign the private key jwt using their private key.\n\nYou can modify the permissions and expiration_datetime in the body"
              },
              "response": []
            },
            {
              "name": "50 - DC -> OFP: POST /par",
              "event": [
                {
                  "listen": "test",
                  "script": {
                    "exec": [
                      "// Visualization for Auth Code URL",
                      "var template = `",
                      "<style>",
                      "    .container {",
                      "        font-family: Arial, sans-serif;",
                      "        padding: 20px;",
                      "    }",
                      "    .label {",
                      "        font-size: 14px;",
                      "        color: #666;",
                      "        margin-bottom: 10px;",
                      "    }",
                      "    .url-value {",
                      "        font-size: 14px;",
                      "        color: #333;",
                      "        word-break: break-all;",
                      "        font-family: monospace;",
                      "        background: #f5f5f5;",
                      "        padding: 15px;",
                      "        border-radius: 8px;",
                      "        margin-bottom: 15px;",
                      "    }",
                      "    .url-link {",
                      "        display: inline-block;",
                      "        background: #FF6C37;",
                      "        color: white;",
                      "        padding: 10px 20px;",
                      "        border-radius: 5px;",
                      "        text-decoration: none;",
                      "        font-size: 14px;",
                      "    }",
                      "    .url-link:hover {",
                      "        background: #e55a2b;",
                      "    }",
                      "</style>",
                      "<div class=\"container\">",
                      "  <div class=\"label\">Auth Code URL:</div>",
                      "  <div class=\"url-value\" id=\"authUrlText\">{{authCodeUrl}}</div>",
                      "",
                      "  <button type=\"button\" id=\"copyAuthUrl\">Copy to clipboard</button>",
                      "",
                      "  <!-- fallback -->",
                      "  <textarea id=\"authUrlTA\" style=\"position:absolute; left:-9999px; top:-9999px;\"></textarea>",
                      "",
                      "  <div id=\"copyStatus\" style=\"margin-top:8px;\"></div>",
                      "</div>",
                      "",
                      "<script>",
                      "  (function () {",
                      "    const url = \"{{{authCodeUrl}}}\";",
                      "    const btn = document.getElementById(\"copyAuthUrl\");",
                      "    const status = document.getElementById(\"copyStatus\");",
                      "    const ta = document.getElementById(\"authUrlTA\");",
                      "",
                      "    function setStatus(msg) {",
                      "      if (status) status.textContent = msg;",
                      "    }",
                      "",
                      "    async function copyModern() {",
                      "      await navigator.clipboard.writeText(url);",
                      "    }",
                      "",
                      "    function copyFallback() {",
                      "      ta.value = url;",
                      "      ta.focus();",
                      "      ta.select();",
                      "      const ok = document.execCommand(\"copy\");",
                      "      if (!ok) throw new Error(\"execCommand failed\");",
                      "    }",
                      "",
                      "    btn.addEventListener(\"click\", async function () {",
                      "      try {",
                      "        if (navigator.clipboard && window.isSecureContext) {",
                      "          await copyModern();",
                      "        } else {",
                      "          copyFallback();",
                      "        }",
                      "        setStatus(\"Copied.\");",
                      "      } catch (e) {",
                      "        setStatus(\"Copy failed. Select and copy manually.\");",
                      "      }",
                      "    });",
                      "  })();",
                      "</script>",
                      "`;",
                      "",
                      "const utilsSrc = pm.globals.get(\"utils\");",
                      "const utils = eval(utilsSrc); // returns the object from the IIFE",
                      "",
                      "if (pm.response.code !== 201) {",
                      "    utils.visualiseJson( \"Error\", pm.response.json());",
                      "    return;",
                      "} else {",
                      "   let jsonData = pm.response.json();",
                      "",
                      "    const clientId = pm.environment.get(\"_clientId\");",
                      "    const authEndpoint = pm.environment.get('auth-endpoint');",
                      "    console.log(authEndpoint);",
                      "",
                      "    const authCodeUrl = `${authEndpoint}?client_id=${clientId}&scope=openid&request_uri=${jsonData.request_uri}`;",
                      "    pm.environment.set(\"authCodeUrl\", authCodeUrl);",
                      "",
                      "    pm.visualizer.set(template, { authCodeUrl });",
                      "}"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                },
                {
                  "listen": "prerequest",
                  "script": {
                    "exec": [
                      "// set uuid and time",
                      "pm.environment.set(\"now\", (new Date()).toUTCString());",
                      "const uuid = require('uuid');",
                      "pm.environment.set(\"x-fapi-interaction-id\", uuid.v4());"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                }
              ],
              "request": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/x-www-form-urlencoded",
                    "type": "text"
                  },
                  {
                    "key": "x-cert-dn",
                    "value": "",
                    "type": "text",
                    "disabled": true
                  },
                  {
                    "key": "x-fapi-interaction-id",
                    "value": "{{x-fapi-interaction-id}}",
                    "type": "text"
                  }
                ],
                "body": {
                  "mode": "urlencoded",
                  "urlencoded": [
                    {
                      "key": "client_id",
                      "value": "{{_clientId}}",
                      "type": "text"
                    },
                    {
                      "key": "request",
                      "value": "{{requestObject}}",
                      "type": "default"
                    },
                    {
                      "key": "client_assertion_type",
                      "value": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
                      "type": "text"
                    },
                    {
                      "key": "client_assertion",
                      "value": "{{private_key_jwt}}",
                      "type": "text"
                    }
                  ]
                },
                "url": {
                  "raw": "{{par-endpoint}}",
                  "host": [
                    "{{par-endpoint}}"
                  ]
                }
              },
              "response": []
            },
            {
              "name": "60 - DC -> OFP: POST /token [Auth-code Grant]",
              "event": [
                {
                  "listen": "test",
                  "script": {
                    "exec": [
                      "const utilsSrc = pm.globals.get(\"utils\");",
                      "const utils = eval(utilsSrc); // returns the object from the IIFE",
                      "",
                      "if (pm.response.code !== 200) {",
                      "    utils.visualiseJson( \"Error\", pm.response.text());",
                      "    return;",
                      "} else {",
                      "    let jsonData = pm.response.json();",
                      "",
                      "    pm.environment.set(\"token-from-auth-code-grant-accounts\", jsonData.access_token);",
                      "    pm.environment.set(\"refresh_token\", jsonData.refresh_token);",
                      "    pm.environment.set(\"consent\", jsonData.authorization_details[0].consent.consent_id);",
                      "    pm.environment.set(\"dc_id\", jsonData.authorization_details[0].consent.dc_id);",
                      "    pm.environment.set(\"account_id\", jsonData.authorization_details[0].consent.accounts[0].account_id);",
                      "    pm.environment.set(\"dp_id\", jsonData.authorization_details[0].consent.dp_id);",
                      "",
                      "    utils.visualiseJws('id_token', jsonData.id_token);",
                      "}"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                },
                {
                  "listen": "prerequest",
                  "script": {
                    "exec": [
                      "// set uuid and time",
                      "pm.environment.set(\"now\", (new Date()).toUTCString());",
                      "const uuid = require('uuid');",
                      "pm.environment.set(\"x-fapi-interaction-id\", uuid.v4());"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                }
              ],
              "request": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/x-www-form-urlencoded"
                  },
                  {
                    "key": "x-cert-dn",
                    "value": "",
                    "type": "text",
                    "disabled": true
                  },
                  {
                    "key": "x-cert-fingerprint",
                    "value": "xxx",
                    "type": "text",
                    "disabled": true
                  },
                  {
                    "key": "x-fapi-interaction-id",
                    "value": "{{x-fapi-interaction-id}}",
                    "type": "text"
                  }
                ],
                "body": {
                  "mode": "urlencoded",
                  "urlencoded": [
                    {
                      "key": "grant_type",
                      "value": "authorization_code",
                      "type": "text"
                    },
                    {
                      "key": "scope",
                      "value": "accounts",
                      "type": "text"
                    },
                    {
                      "key": "code",
                      "value": "{{authorizationCode}}",
                      "type": "text"
                    },
                    {
                      "key": "redirect_uri",
                      "value": "{{redirectUrl}}",
                      "type": "text"
                    },
                    {
                      "key": "code_verifier",
                      "value": "{{code-verifier}}",
                      "type": "default"
                    },
                    {
                      "key": "client_assertion_type",
                      "value": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
                      "type": "text"
                    },
                    {
                      "key": "client_assertion",
                      "value": "{{private_key_jwt}}",
                      "type": "text"
                    }
                  ]
                },
                "url": {
                  "raw": "{{tokenEndpoint}}",
                  "host": [
                    "{{tokenEndpoint}}"
                  ]
                },
                "description": "Copy the authorization code generated into the browser into the **Body** tab in the `code` parameter"
              },
              "response": []
            }
          ],
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  ""
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  ""
                ]
              }
            }
          ]
        },
        {
          "name": "Refresh Token",
          "item": [
            {
              "name": "10 - Sign private_key_jwt [Utility]",
              "event": [
                {
                  "listen": "prerequest",
                  "script": {
                    "exec": [
                      "const uuid = require('uuid');",
                      "",
                      "pm.environment.set(\"exp\", Date.now() / 1000 + 300);",
                      "pm.environment.set(\"nbf\", (Date.now() / 1000) - 10);",
                      "pm.environment.set(\"uuid\", uuid.v4());",
                      ""
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                },
                {
                  "listen": "test",
                  "script": {
                    "exec": [
                      "const utilsSrc = pm.globals.get(\"utils\");",
                      "const utils = eval(utilsSrc); // returns the object from the IIFE",
                      "",
                      "if (pm.response.code !== 200) {",
                      "    utils.visualiseJson( \"Error\", pm.response.text());",
                      "    return;",
                      "} else {",
                      "    pm.environment.set(\"private_key_jwt\", pm.response.text());",
                      "    utils.visualiseJws( \"private_key_jwt\", pm.response.text());",
                      "}"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                }
              ],
              "protocolProfileBehavior": {
                "disableBodyPruning": true
              },
              "request": {
                "method": "GET",
                "header": [
                  {
                    "key": "content-type",
                    "value": "application/json"
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n    \"header\": {\n        \"alg\": \"PS256\",\n        \"kid\": \"{{kid-local}}\"\n    },\n    \"body\": {\n        \"aud\": \"{{issuer}}\",\n        \"exp\": {{exp}},\n        \"iss\": \"{{_clientId}}\",\n        \"sub\": \"{{_clientId}}\",\n        \"jti\": \"{{uuid}}\",\n        \"iat\": {{nbf}}\n    },\n    \"signingKeyPEM\": \"{{pem-local}}\"\n}"
                },
                "url": {
                  "raw": "{{rs}}/o3/v1.0/message-signature",
                  "host": [
                    "{{rs}}"
                  ],
                  "path": [
                    "o3",
                    "v1.0",
                    "message-signature"
                  ]
                },
                "description": "This is a utility API call to create a private_key_jwt.\n\nThis private_key_jwt will be used in a subsequent step for OIDC client authentication to the PAR and token endpoints.\n\nIn a production implementation, the DC must sign the private key jwt using their private key."
              },
              "response": []
            },
            {
              "name": "20 - POST /token [Refresh Token Grant]",
              "event": [
                {
                  "listen": "test",
                  "script": {
                    "exec": [
                      "const utilsSrc = pm.globals.get(\"utils\");",
                      "const utils = eval(utilsSrc); // returns the object from the IIFE",
                      "",
                      "if (pm.response.code !== 200) {",
                      "    utils.visualiseJson( \"Error\", pm.response.json());",
                      "    return;",
                      "} else {",
                      "    let jsonData = pm.response.json()",
                      "    pm.environment.set(\"token-from-auth-code-grant-accounts\", jsonData.access_token);",
                      "",
                      "    utils.visualiseJws( \"id_token\", jsonData.id_token);",
                      "}"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                },
                {
                  "listen": "prerequest",
                  "script": {
                    "exec": [
                      "// set uuid and time",
                      "pm.environment.set(\"now\", (new Date()).toUTCString());",
                      "const uuid = require('uuid');",
                      "pm.environment.set(\"x-fapi-interaction-id\", uuid.v4());"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                }
              ],
              "request": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/x-www-form-urlencoded",
                    "type": "text"
                  },
                  {
                    "key": "x-cert-dn",
                    "value": "",
                    "type": "text",
                    "disabled": true
                  },
                  {
                    "key": "x-cert-fingerprint",
                    "value": "xxx",
                    "type": "text"
                  },
                  {
                    "key": "x-fapi-interaction-id",
                    "value": "{{x-fapi-interaction-id}}",
                    "type": "text"
                  }
                ],
                "body": {
                  "mode": "urlencoded",
                  "urlencoded": [
                    {
                      "key": "grant_type",
                      "value": "refresh_token",
                      "type": "text"
                    },
                    {
                      "key": "scope",
                      "value": "accounts",
                      "type": "text"
                    },
                    {
                      "key": "client_assertion_type",
                      "value": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
                      "type": "text"
                    },
                    {
                      "key": "client_assertion",
                      "value": "{{private_key_jwt}}",
                      "type": "text"
                    },
                    {
                      "key": "refresh_token",
                      "value": "{{refresh_token}}",
                      "type": "text"
                    }
                  ]
                },
                "url": {
                  "raw": "{{token-endpoint}}",
                  "host": [
                    "{{token-endpoint}}"
                  ]
                },
                "description": "Copy the authorization code generated into the browser into the **Body** tab in the `code` parameter"
              },
              "response": []
            }
          ]
        },
        {
          "name": "Other OIDC Requests",
          "item": [
            {
              "name": "Userinfo",
              "item": [
                {
                  "name": "20 - GET /userinfo",
                  "event": [
                    {
                      "listen": "test",
                      "script": {
                        "exec": [
                          "const utilsSrc = pm.globals.get(\"utils\");",
                          "const utils = eval(utilsSrc); // returns the object from the IIFE",
                          "",
                          "if (pm.response.code !== 200) {",
                          "    utils.visualiseJson( \"Error\", pm.response.json());",
                          "    return;",
                          "} else {",
                          "    utils.visualiseJws( \"User Info\", pm.response.text());",
                          "}"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    },
                    {
                      "listen": "prerequest",
                      "script": {
                        "exec": [
                          "// set uuid and time",
                          "pm.environment.set(\"now\", (new Date()).toUTCString());",
                          "const uuid = require('uuid');",
                          "pm.environment.set(\"x-fapi-interaction-id\", uuid.v4());"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    }
                  ],
                  "protocolProfileBehavior": {
                    "disableBodyPruning": true
                  },
                  "request": {
                    "method": "GET",
                    "header": [
                      {
                        "key": "Content-Type",
                        "value": "application/x-www-form-urlencoded",
                        "type": "text"
                      },
                      {
                        "key": "Authorization",
                        "value": "Bearer {{token-from-auth-code-grant-accounts}}",
                        "type": "text"
                      },
                      {
                        "key": "x-cert-dn",
                        "value": "",
                        "type": "text",
                        "disabled": true
                      },
                      {
                        "key": "x-cert-fingerprint",
                        "value": "",
                        "type": "text",
                        "disabled": true
                      },
                      {
                        "key": "x-fapi-interaction-id",
                        "value": "{{x-fapi-interaction-id}}",
                        "type": "text"
                      }
                    ],
                    "body": {
                      "mode": "urlencoded",
                      "urlencoded": []
                    },
                    "url": {
                      "raw": "{{userinfo_endpoint}}",
                      "host": [
                        "{{userinfo_endpoint}}"
                      ]
                    },
                    "description": "Copy the authorization code generated into the browser into the **Body** tab in the `code` parameter"
                  },
                  "response": []
                }
              ]
            },
            {
              "name": "Introspection",
              "item": [
                {
                  "name": "10 - Sign private_key_jwt [Utility]",
                  "event": [
                    {
                      "listen": "prerequest",
                      "script": {
                        "exec": [
                          "const uuid = require('uuid');",
                          "",
                          "pm.environment.set(\"exp\", Date.now() / 1000 + 300);",
                          "pm.environment.set(\"nbf\", (Date.now() / 1000) - 10);",
                          "pm.environment.set(\"uuid\", uuid.v4());",
                          ""
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    },
                    {
                      "listen": "test",
                      "script": {
                        "exec": [
                          "const utilsSrc = pm.globals.get(\"utils\");",
                          "const utils = eval(utilsSrc); // returns the object from the IIFE",
                          "",
                          "if (pm.response.code !== 200) {",
                          "    utils.visualiseJson( \"Error\", pm.response.text());",
                          "    return;",
                          "} else {",
                          "    pm.environment.set(\"private_key_jwt\", pm.response.text());",
                          "    utils.visualiseJws( \"private_key_jwt\", pm.response.text());",
                          "}"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    }
                  ],
                  "protocolProfileBehavior": {
                    "disableBodyPruning": true
                  },
                  "request": {
                    "method": "GET",
                    "header": [
                      {
                        "key": "content-type",
                        "value": "application/json"
                      }
                    ],
                    "body": {
                      "mode": "raw",
                      "raw": "{\n    \"header\": {\n        \"alg\": \"PS256\",\n        \"kid\": \"{{kid-local}}\"\n    },\n    \"body\": {\n        \"aud\": \"{{issuer}}\",\n        \"exp\": {{exp}},\n        \"iss\": \"{{_clientId}}\",\n        \"sub\": \"{{_clientId}}\",\n        \"jti\": \"{{uuid}}\",\n        \"iat\": {{nbf}}\n    },\n    \"signingKeyPEM\": \"{{pem-local}}\"\n}"
                    },
                    "url": {
                      "raw": "{{rs}}/o3/v1.0/message-signature",
                      "host": [
                        "{{rs}}"
                      ],
                      "path": [
                        "o3",
                        "v1.0",
                        "message-signature"
                      ]
                    },
                    "description": "This is a utility API call to create a private_key_jwt.\n\nThis private_key_jwt will be used in a subsequent step for OIDC client authentication to the PAR and token endpoints.\n\nIn a production implementation, the DC must sign the private key jwt using their private key."
                  },
                  "response": []
                },
                {
                  "name": "Introspection - ACG Access Token",
                  "event": [
                    {
                      "listen": "prerequest",
                      "script": {
                        "exec": [
                          "// set uuid and time",
                          "pm.environment.set(\"now\", (new Date()).toUTCString());",
                          "const uuid = require('uuid');",
                          "pm.environment.set(\"x-fapi-interaction-id\", uuid.v4());"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    },
                    {
                      "listen": "test",
                      "script": {
                        "exec": [
                          "const utilsSrc = pm.globals.get(\"utils\");",
                          "const utils = eval(utilsSrc); // returns the object from the IIFE",
                          "",
                          "if (pm.response.code !== 200) {",
                          "    utils.visualiseJson( \"Error\", pm.response.text());",
                          "    return;",
                          "} else {",
                          "    utils.visualiseJws( \"Token Introspection Response\", pm.response.text());",
                          "}"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    }
                  ],
                  "request": {
                    "method": "POST",
                    "header": [
                      {
                        "key": "Content-Type",
                        "value": "application/x-www-form-urlencoded"
                      },
                      {
                        "key": "x-fapi-interaction-id",
                        "value": "{{x-fapi-interaction-id}}",
                        "type": "text"
                      }
                    ],
                    "body": {
                      "mode": "urlencoded",
                      "urlencoded": [
                        {
                          "key": "token",
                          "value": "{{token-from-auth-code-grant-accounts}}",
                          "type": "text"
                        },
                        {
                          "key": "client_assertion_type",
                          "value": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
                          "type": "text"
                        },
                        {
                          "key": "client_assertion",
                          "value": "{{private_key_jwt}}",
                          "type": "text"
                        }
                      ]
                    },
                    "url": {
                      "raw": "{{introspectionEndpoint}}",
                      "host": [
                        "{{introspectionEndpoint}}"
                      ]
                    },
                    "description": "Copy the authorization code generated into the browser into the **Body** tab in the `code` parameter"
                  },
                  "response": []
                },
                {
                  "name": "Introspection - refresh token",
                  "event": [
                    {
                      "listen": "test",
                      "script": {
                        "exec": [
                          "const utilsSrc = pm.globals.get(\"utils\");",
                          "const utils = eval(utilsSrc); // returns the object from the IIFE",
                          "",
                          "if (pm.response.code !== 200) {",
                          "    utils.visualiseJson( \"Error\", pm.response.text());",
                          "    return;",
                          "} else {",
                          "    utils.visualiseJws( \"Token Introspection Response\", pm.response.text());",
                          "}"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    },
                    {
                      "listen": "prerequest",
                      "script": {
                        "exec": [
                          "// set uuid and time",
                          "pm.environment.set(\"now\", (new Date()).toUTCString());",
                          "const uuid = require('uuid');",
                          "pm.environment.set(\"x-fapi-interaction-id\", uuid.v4());"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    }
                  ],
                  "request": {
                    "method": "POST",
                    "header": [
                      {
                        "key": "Content-Type",
                        "value": "application/x-www-form-urlencoded"
                      },
                      {
                        "key": "x-cert-dn",
                        "value": "",
                        "type": "text",
                        "disabled": true
                      },
                      {
                        "key": "x-cert-fingerprint",
                        "value": "",
                        "type": "text",
                        "disabled": true
                      },
                      {
                        "key": "x-fapi-interaction-id",
                        "value": "{{x-fapi-interaction-id}}",
                        "type": "text"
                      }
                    ],
                    "body": {
                      "mode": "urlencoded",
                      "urlencoded": [
                        {
                          "key": "token",
                          "value": "{{refresh_token}}",
                          "type": "text"
                        },
                        {
                          "key": "client_assertion_type",
                          "value": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
                          "type": "text"
                        },
                        {
                          "key": "client_assertion",
                          "value": "{{private_key_jwt}}",
                          "type": "text"
                        }
                      ]
                    },
                    "url": {
                      "raw": "{{introspectionEndpoint}}",
                      "host": [
                        "{{introspectionEndpoint}}"
                      ]
                    },
                    "description": "Copy the authorization code generated into the browser into the **Body** tab in the `code` parameter"
                  },
                  "response": []
                },
                {
                  "name": "Introspection - CCG Access Token",
                  "event": [
                    {
                      "listen": "test",
                      "script": {
                        "exec": [
                          "const utilsSrc = pm.globals.get(\"utils\");",
                          "const utils = eval(utilsSrc); // returns the object from the IIFE",
                          "",
                          "if (pm.response.code !== 200) {",
                          "    utils.visualiseJson( \"Error\", pm.response.text());",
                          "    return;",
                          "} else {",
                          "    utils.visualiseJws( \"Token Introspection Response\", pm.response.text());",
                          "}"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    },
                    {
                      "listen": "prerequest",
                      "script": {
                        "exec": [
                          "// set uuid and time",
                          "pm.environment.set(\"now\", (new Date()).toUTCString());",
                          "const uuid = require('uuid');",
                          "pm.environment.set(\"x-fapi-interaction-id\", uuid.v4());"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    }
                  ],
                  "request": {
                    "method": "POST",
                    "header": [
                      {
                        "key": "Content-Type",
                        "value": "application/x-www-form-urlencoded"
                      },
                      {
                        "key": "x-cert-dn",
                        "value": "",
                        "type": "text",
                        "disabled": true
                      },
                      {
                        "key": "x-cert-fingerprint",
                        "value": "",
                        "type": "text",
                        "disabled": true
                      },
                      {
                        "key": "x-fapi-interaction-id",
                        "value": "{{x-fapi-interaction-id}}",
                        "type": "text"
                      }
                    ],
                    "body": {
                      "mode": "urlencoded",
                      "urlencoded": [
                        {
                          "key": "token",
                          "value": "{{token-from-client-credentials-grant-accounts}}",
                          "type": "text"
                        },
                        {
                          "key": "client_assertion_type",
                          "value": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
                          "type": "text"
                        },
                        {
                          "key": "client_assertion",
                          "value": "{{private_key_jwt}}",
                          "type": "text"
                        }
                      ]
                    },
                    "url": {
                      "raw": "{{introspectionEndpoint}}",
                      "host": [
                        "{{introspectionEndpoint}}"
                      ]
                    },
                    "description": "Copy the authorization code generated into the browser into the **Body** tab in the `code` parameter"
                  },
                  "response": []
                }
              ]
            },
            {
              "name": "revocation",
              "item": [
                {
                  "name": "10 - Sign private_key_jwt [Utility]",
                  "event": [
                    {
                      "listen": "prerequest",
                      "script": {
                        "exec": [
                          "const uuid = require('uuid');",
                          "",
                          "pm.environment.set(\"exp\", Date.now() / 1000 + 300);",
                          "pm.environment.set(\"nbf\", (Date.now() / 1000) - 10);",
                          "pm.environment.set(\"uuid\", uuid.v4());",
                          ""
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    },
                    {
                      "listen": "test",
                      "script": {
                        "exec": [
                          "const utilsSrc = pm.globals.get(\"utils\");",
                          "const utils = eval(utilsSrc); // returns the object from the IIFE",
                          "",
                          "if (pm.response.code !== 200) {",
                          "    utils.visualiseJson( \"Error\", pm.response.text());",
                          "    return;",
                          "} else {",
                          "    pm.environment.set(\"private_key_jwt\", pm.response.text());",
                          "    utils.visualiseJws( \"private_key_jwt\", pm.response.text());",
                          "}"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    }
                  ],
                  "protocolProfileBehavior": {
                    "disableBodyPruning": true
                  },
                  "request": {
                    "method": "GET",
                    "header": [
                      {
                        "key": "content-type",
                        "value": "application/json"
                      }
                    ],
                    "body": {
                      "mode": "raw",
                      "raw": "{\n    \"header\": {\n        \"alg\": \"PS256\",\n        \"kid\": \"{{kid-local}}\"\n    },\n    \"body\": {\n        \"aud\": \"{{issuer}}\",\n        \"exp\": {{exp}},\n        \"iss\": \"{{_clientId}}\",\n        \"sub\": \"{{_clientId}}\",\n        \"jti\": \"{{uuid}}\",\n        \"iat\": {{nbf}}\n    },\n    \"signingKeyPEM\": \"{{pem-local}}\"\n}"
                    },
                    "url": {
                      "raw": "{{rs}}/o3/v1.0/message-signature",
                      "host": [
                        "{{rs}}"
                      ],
                      "path": [
                        "o3",
                        "v1.0",
                        "message-signature"
                      ]
                    },
                    "description": "This is a utility API call to create a private_key_jwt.\n\nThis private_key_jwt will be used in a subsequent step for OIDC client authentication to the PAR and token endpoints.\n\nIn a production implementation, the DC must sign the private key jwt using their private key."
                  },
                  "response": []
                },
                {
                  "name": "POST /revocation",
                  "event": [
                    {
                      "listen": "test",
                      "script": {
                        "exec": [
                          "// let jsonData = JSON.parse(responseBody);",
                          "// pm.environment.set(\"token-from-auth-code-grant-accounts\", jsonData.access_token);",
                          "",
                          "// // JWT Visualization",
                          "// const utilsSrc = pm.globals.get(\"utils\");",
                          "// const utils = eval(utilsSrc); // returns the object from the IIFE",
                          "",
                          "// const template = pm.collectionVariables.get(\"collJwtTemplate\");",
                          "// pm.visualizer.set(template, utils.visualiseJws('id_token', jsonData.id_token));"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    },
                    {
                      "listen": "prerequest",
                      "script": {
                        "exec": [
                          "// set uuid and time",
                          "pm.environment.set(\"now\", (new Date()).toUTCString());",
                          "const uuid = require('uuid');",
                          "pm.environment.set(\"x-fapi-interaction-id\", uuid.v4());"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    }
                  ],
                  "request": {
                    "method": "POST",
                    "header": [
                      {
                        "key": "Content-Type",
                        "value": "application/x-www-form-urlencoded",
                        "type": "text"
                      },
                      {
                        "key": "x-cert-dn",
                        "value": "",
                        "type": "text",
                        "disabled": true
                      },
                      {
                        "key": "x-cert-fingerprint",
                        "value": "",
                        "type": "text",
                        "disabled": true
                      },
                      {
                        "key": "x-fapi-interaction-id",
                        "value": "{{x-fapi-interaction-id}}",
                        "type": "text"
                      }
                    ],
                    "body": {
                      "mode": "urlencoded",
                      "urlencoded": [
                        {
                          "key": "token",
                          "value": "{{token-from-auth-code-grant-accounts}}",
                          "type": "text"
                        },
                        {
                          "key": "client_assertion",
                          "value": "{{private_key_jwt}}",
                          "type": "text"
                        },
                        {
                          "key": "client_assertion_type",
                          "value": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
                          "type": "text"
                        }
                      ]
                    },
                    "url": {
                      "raw": "{{revocation_endpoint}}",
                      "host": [
                        "{{revocation_endpoint}}"
                      ]
                    },
                    "description": "Copy the authorization code generated into the browser into the **Body** tab in the `code` parameter"
                  },
                  "response": []
                }
              ]
            },
            {
              "name": "JWKS",
              "item": [
                {
                  "name": "JWKS for Hub",
                  "event": [
                    {
                      "listen": "test",
                      "script": {
                        "exec": [
                          ""
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    },
                    {
                      "listen": "prerequest",
                      "script": {
                        "exec": [
                          ""
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    }
                  ],
                  "protocolProfileBehavior": {
                    "disableBodyPruning": true
                  },
                  "request": {
                    "method": "GET",
                    "header": [
                      {
                        "key": "Content-Type",
                        "value": "application/x-www-form-urlencoded"
                      }
                    ],
                    "body": {
                      "mode": "urlencoded",
                      "urlencoded": []
                    },
                    "url": {
                      "raw": "{{issuer}}/v1/oauth/jwks/paynet",
                      "host": [
                        "{{issuer}}"
                      ],
                      "path": [
                        "v1",
                        "oauth",
                        "jwks",
                        "paynet"
                      ]
                    },
                    "description": "Queries the .well-known OIDC endpoint.\n\nThis step identifies the various OIDC endpoints that should be used for subsequent steps."
                  },
                  "response": []
                },
                {
                  "name": "JWKS for DP",
                  "event": [
                    {
                      "listen": "test",
                      "script": {
                        "exec": [
                          ""
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    },
                    {
                      "listen": "prerequest",
                      "script": {
                        "exec": [
                          ""
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    }
                  ],
                  "protocolProfileBehavior": {
                    "disableBodyPruning": true
                  },
                  "request": {
                    "method": "GET",
                    "header": [
                      {
                        "key": "Content-Type",
                        "value": "application/x-www-form-urlencoded"
                      }
                    ],
                    "body": {
                      "mode": "urlencoded",
                      "urlencoded": []
                    },
                    "url": {
                      "raw": "{{issuer}}/v1/oauth/jwks/{{dp_id}}",
                      "host": [
                        "{{issuer}}"
                      ],
                      "path": [
                        "v1",
                        "oauth",
                        "jwks",
                        "{{dp_id}}"
                      ]
                    },
                    "description": "Queries the .well-known OIDC endpoint.\n\nThis step identifies the various OIDC endpoints that should be used for subsequent steps."
                  },
                  "response": []
                }
              ]
            }
          ]
        }
      ]
    },
    {
      "name": "Resource Server Flows",
      "item": [
        {
          "name": "Consents",
          "item": [
            {
              "name": "10 - Sign private_key_jwt [Utility]",
              "event": [
                {
                  "listen": "prerequest",
                  "script": {
                    "exec": [
                      "const uuid = require('uuid');",
                      "",
                      "pm.environment.set(\"exp\", Date.now() / 1000 + 300);",
                      "pm.environment.set(\"nbf\", (Date.now() / 1000) - 10);",
                      "pm.environment.set(\"uuid\", uuid.v4());",
                      ""
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                },
                {
                  "listen": "test",
                  "script": {
                    "exec": [
                      "const utilsSrc = pm.globals.get(\"utils\");",
                      "const utils = eval(utilsSrc); // returns the object from the IIFE",
                      "",
                      "if (pm.response.code !== 200) {",
                      "    utils.visualiseJson( \"Error\", pm.response.text());",
                      "    return;",
                      "} else {",
                      "    pm.environment.set(\"private_key_jwt\", pm.response.text());",
                      "    utils.visualiseJws( \"private_key_jwt\", pm.response.text());",
                      "}"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                }
              ],
              "protocolProfileBehavior": {
                "disableBodyPruning": true
              },
              "request": {
                "method": "GET",
                "header": [
                  {
                    "key": "content-type",
                    "value": "application/json"
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n    \"header\": {\n        \"alg\": \"PS256\",\n        \"kid\": \"{{kid-local}}\"\n    },\n    \"body\": {\n        \"aud\": \"{{issuer}}\",\n        \"exp\": {{exp}},\n        \"iss\": \"{{_clientId}}\",\n        \"sub\": \"{{_clientId}}\",\n        \"jti\": \"{{uuid}}\",\n        \"iat\": {{nbf}}\n    },\n    \"signingKeyPEM\": \"{{pem-local}}\"\n}"
                },
                "url": {
                  "raw": "{{rs}}/o3/v1.0/message-signature",
                  "host": [
                    "{{rs}}"
                  ],
                  "path": [
                    "o3",
                    "v1.0",
                    "message-signature"
                  ]
                },
                "description": "This is a utility API call to create a private_key_jwt.\n\nThis private_key_jwt will be used in a subsequent step for OIDC client authentication to the PAR and token endpoints.\n\nIn a production implementation, the DC must sign the private key jwt using their private key."
              },
              "response": []
            },
            {
              "name": "20 - POST /token [Client Credentials Grant]",
              "event": [
                {
                  "listen": "test",
                  "script": {
                    "exec": [
                      "const utilsSrc = pm.globals.get(\"utils\");",
                      "const utils = eval(utilsSrc); // returns the object from the IIFE",
                      "",
                      "if (pm.response.code !== 200) {",
                      "    utils.visualiseJson( \"Error\", pm.response.json());",
                      "    return;",
                      "} else {",
                      "    let jsonData = pm.response.json()",
                      "    pm.environment.set(\"token-from-client-credentials-grant-accounts\", jsonData.access_token);",
                      "",
                      "    utils.visualiseJson( \"Access Token\", jsonData);",
                      "}"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                },
                {
                  "listen": "prerequest",
                  "script": {
                    "exec": [
                      "// set uuid and time",
                      "pm.environment.set(\"now\", (new Date()).toUTCString());",
                      "const uuid = require('uuid');",
                      "pm.environment.set(\"x-fapi-interaction-id\", uuid.v4());"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                }
              ],
              "request": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/x-www-form-urlencoded",
                    "type": "text"
                  },
                  {
                    "key": "x-cert-dn",
                    "value": "",
                    "type": "text",
                    "disabled": true
                  },
                  {
                    "key": "x-cert-fingerprint",
                    "value": "xxx",
                    "type": "text"
                  },
                  {
                    "key": "x-fapi-interaction-id",
                    "value": "{{x-fapi-interaction-id}}",
                    "type": "text"
                  }
                ],
                "body": {
                  "mode": "urlencoded",
                  "urlencoded": [
                    {
                      "key": "grant_type",
                      "value": "client_credentials",
                      "type": "text"
                    },
                    {
                      "key": "scope",
                      "value": "accounts",
                      "type": "text"
                    },
                    {
                      "key": "client_assertion_type",
                      "value": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
                      "type": "text"
                    },
                    {
                      "key": "client_assertion",
                      "value": "{{private_key_jwt}}",
                      "type": "text"
                    }
                  ]
                },
                "url": {
                  "raw": "{{token-endpoint}}",
                  "host": [
                    "{{token-endpoint}}"
                  ]
                },
                "description": "Copy the authorization code generated into the browser into the **Body** tab in the `code` parameter"
              },
              "response": []
            },
            {
              "name": "40 - GET /consents/:consent_id",
              "event": [
                {
                  "listen": "test",
                  "script": {
                    "exec": [
                      ""
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                },
                {
                  "listen": "prerequest",
                  "script": {
                    "exec": [
                      "// set uuid and time",
                      "pm.environment.set(\"now\", (new Date()).toUTCString());",
                      "const uuid = require('uuid');",
                      "pm.environment.set(\"x-fapi-interaction-id\", uuid.v4());"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                }
              ],
              "request": {
                "method": "GET",
                "header": [
                  {
                    "key": "authorization",
                    "value": "Bearer {{token-from-client-credentials-grant-accounts}}",
                    "type": "text"
                  },
                  {
                    "key": "x-cert-dn",
                    "value": "CN=HQuZPIt3ipkh33Uxytox1E,OU=0015800001041RHAAY,O=OpenBanking,C=GB",
                    "type": "text",
                    "disabled": true
                  },
                  {
                    "key": "x-cert-fingerprint",
                    "value": "xxx",
                    "type": "text",
                    "disabled": true
                  },
                  {
                    "key": "x-fapi-interaction-id",
                    "value": "{{x-fapi-interaction-id}}",
                    "type": "text"
                  }
                ],
                "url": {
                  "raw": "{{rs}}/v1/consents/{{consent}}",
                  "host": [
                    "{{rs}}"
                  ],
                  "path": [
                    "v1",
                    "consents",
                    "{{consent}}"
                  ]
                }
              },
              "response": []
            },
            {
              "name": "50 - POST /consents/:consent_id/suspend",
              "event": [
                {
                  "listen": "prerequest",
                  "script": {
                    "exec": [
                      "// set uuid and time",
                      "pm.environment.set(\"now\", (new Date()).toUTCString());",
                      "const uuid = require('uuid');",
                      "pm.environment.set(\"x-fapi-interaction-id\", uuid.v4());"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                }
              ],
              "request": {
                "method": "POST",
                "header": [
                  {
                    "key": "authorization",
                    "value": "Bearer {{token-from-client-credentials-grant-accounts}}",
                    "type": "text"
                  },
                  {
                    "key": "x-cert-dn",
                    "value": "CN=HQuZPIt3ipkh33Uxytox1E,OU=0015800001041RHAAY,O=OpenBanking,C=GB",
                    "type": "text"
                  },
                  {
                    "key": "x-cert-fingerprint",
                    "value": "xxx",
                    "type": "text"
                  },
                  {
                    "key": "content-type",
                    "value": "application/json",
                    "type": "text"
                  },
                  {
                    "key": "x-fapi-interaction-id",
                    "value": "{{x-fapi-interaction-id}}",
                    "type": "text"
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n    \"updated_by\": \"data_consumer\",\n    \"status_reason\": {\n        \"reason_code\": \"inactive_account\",\n        \"reason_description\": \"string\"\n    }\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "url": {
                  "raw": "{{rs}}/v1/consents/{{consent}}/suspend",
                  "host": [
                    "{{rs}}"
                  ],
                  "path": [
                    "v1",
                    "consents",
                    "{{consent}}",
                    "suspend"
                  ]
                }
              },
              "response": []
            },
            {
              "name": "60 - POST /consents/:consent_id/reactivate",
              "event": [
                {
                  "listen": "prerequest",
                  "script": {
                    "exec": [
                      "// set uuid and time",
                      "pm.environment.set(\"now\", (new Date()).toUTCString());",
                      "const uuid = require('uuid');",
                      "pm.environment.set(\"x-fapi-interaction-id\", uuid.v4());"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                }
              ],
              "request": {
                "method": "POST",
                "header": [
                  {
                    "key": "authorization",
                    "value": "Bearer {{token-from-client-credentials-grant-accounts}}",
                    "type": "text"
                  },
                  {
                    "key": "x-cert-dn",
                    "value": "CN=HQuZPIt3ipkh33Uxytox1E,OU=0015800001041RHAAY,O=OpenBanking,C=GB",
                    "type": "text"
                  },
                  {
                    "key": "x-cert-fingerprint",
                    "value": "xxx",
                    "type": "text"
                  },
                  {
                    "key": "content-type",
                    "value": "application/json",
                    "type": "text"
                  },
                  {
                    "key": "x-fapi-interaction-id",
                    "value": "{{x-fapi-interaction-id}}",
                    "type": "text"
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{ \"updated_by\": \"data_consumer\" }",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "url": {
                  "raw": "{{rs}}/v1/consents/{{consent}}/reactivate",
                  "host": [
                    "{{rs}}"
                  ],
                  "path": [
                    "v1",
                    "consents",
                    "{{consent}}",
                    "reactivate"
                  ]
                }
              },
              "response": []
            },
            {
              "name": "70 - POST /consents/:consent_id/revoke",
              "event": [
                {
                  "listen": "prerequest",
                  "script": {
                    "exec": [
                      "// set uuid and time",
                      "pm.environment.set(\"now\", (new Date()).toUTCString());",
                      "const uuid = require('uuid');",
                      "pm.environment.set(\"x-fapi-interaction-id\", uuid.v4());"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                }
              ],
              "request": {
                "method": "POST",
                "header": [
                  {
                    "key": "authorization",
                    "value": "Bearer {{token-from-client-credentials-grant-accounts}}",
                    "type": "text"
                  },
                  {
                    "key": "x-cert-dn",
                    "value": "CN=HQuZPIt3ipkh33Uxytox1E,OU=0015800001041RHAAY,O=OpenBanking,C=GB",
                    "type": "text"
                  },
                  {
                    "key": "x-cert-fingerprint",
                    "value": "xxx",
                    "type": "text"
                  },
                  {
                    "key": "content-type",
                    "value": "application/json",
                    "type": "text"
                  },
                  {
                    "key": "x-fapi-interaction-id",
                    "value": "{{x-fapi-interaction-id}}",
                    "type": "text"
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n    \"updated_by\": \"data_consumer\",\n    \"status_reason\": {\n        \"reason_code\": \"inactive_account\",\n        \"reason_description\": \"string\"\n    }\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "url": {
                  "raw": "{{rs}}/v1/consents/{{consent}}/revoke",
                  "host": [
                    "{{rs}}"
                  ],
                  "path": [
                    "v1",
                    "consents",
                    "{{consent}}",
                    "revoke"
                  ]
                }
              },
              "response": []
            }
          ]
        },
        {
          "name": "Providers",
          "item": [
            {
              "name": "10 - Sign private_key_jwt [Utility]",
              "event": [
                {
                  "listen": "prerequest",
                  "script": {
                    "exec": [
                      "const uuid = require('uuid');",
                      "",
                      "pm.environment.set(\"exp\", Date.now() / 1000 + 300);",
                      "pm.environment.set(\"nbf\", (Date.now() / 1000) - 10);",
                      "pm.environment.set(\"uuid\", uuid.v4());",
                      ""
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                },
                {
                  "listen": "test",
                  "script": {
                    "exec": [
                      "const utilsSrc = pm.globals.get(\"utils\");",
                      "const utils = eval(utilsSrc); // returns the object from the IIFE",
                      "",
                      "if (pm.response.code !== 200) {",
                      "    utils.visualiseJson( \"Error\", pm.response.text());",
                      "    return;",
                      "} else {",
                      "    pm.environment.set(\"private_key_jwt\", pm.response.text());",
                      "    utils.visualiseJws( \"private_key_jwt\", pm.response.text());",
                      "}"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                }
              ],
              "protocolProfileBehavior": {
                "disableBodyPruning": true
              },
              "request": {
                "method": "GET",
                "header": [
                  {
                    "key": "content-type",
                    "value": "application/json"
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n    \"header\": {\n        \"alg\": \"PS256\",\n        \"kid\": \"{{kid-local}}\"\n    },\n    \"body\": {\n        \"aud\": \"{{issuer}}\",\n        \"exp\": {{exp}},\n        \"iss\": \"{{_clientId}}\",\n        \"sub\": \"{{_clientId}}\",\n        \"jti\": \"{{uuid}}\",\n        \"iat\": {{nbf}}\n    },\n    \"signingKeyPEM\": \"{{pem-local}}\"\n}"
                },
                "url": {
                  "raw": "{{rs}}/o3/v1.0/message-signature",
                  "host": [
                    "{{rs}}"
                  ],
                  "path": [
                    "o3",
                    "v1.0",
                    "message-signature"
                  ]
                },
                "description": "This is a utility API call to create a private_key_jwt.\n\nThis private_key_jwt will be used in a subsequent step for OIDC client authentication to the PAR and token endpoints.\n\nIn a production implementation, the DC must sign the private key jwt using their private key."
              },
              "response": []
            },
            {
              "name": "20 - POST /token [Client Credentials Grant]",
              "event": [
                {
                  "listen": "test",
                  "script": {
                    "exec": [
                      "const utilsSrc = pm.globals.get(\"utils\");",
                      "const utils = eval(utilsSrc); // returns the object from the IIFE",
                      "",
                      "if (pm.response.code !== 200) {",
                      "    utils.visualiseJson( \"Error\", pm.response.json());",
                      "    return;",
                      "} else {",
                      "    let jsonData = pm.response.json()",
                      "    pm.environment.set(\"token-from-client-credentials-grant-accounts\", jsonData.access_token);",
                      "",
                      "    utils.visualiseJson( \"Access Token\", jsonData);",
                      "}"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                },
                {
                  "listen": "prerequest",
                  "script": {
                    "exec": [
                      "// set uuid and time",
                      "pm.environment.set(\"now\", (new Date()).toUTCString());",
                      "const uuid = require('uuid');",
                      "pm.environment.set(\"x-fapi-interaction-id\", uuid.v4());"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                }
              ],
              "request": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/x-www-form-urlencoded"
                  },
                  {
                    "key": "x-cert-dn",
                    "value": "",
                    "type": "text"
                  },
                  {
                    "key": "x-cert-fingerprint",
                    "value": "xxx",
                    "type": "text"
                  },
                  {
                    "key": "x-fapi-interaction-id",
                    "value": "{{x-fapi-interaction-id}}",
                    "type": "text"
                  }
                ],
                "body": {
                  "mode": "urlencoded",
                  "urlencoded": [
                    {
                      "key": "grant_type",
                      "value": "client_credentials",
                      "type": "text"
                    },
                    {
                      "key": "scope",
                      "value": "accounts",
                      "type": "text"
                    },
                    {
                      "key": "client_assertion_type",
                      "value": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
                      "type": "text"
                    },
                    {
                      "key": "client_assertion",
                      "value": "{{private_key_jwt}}",
                      "type": "text"
                    }
                  ]
                },
                "url": {
                  "raw": "{{token-endpoint}}",
                  "host": [
                    "{{token-endpoint}}"
                  ]
                },
                "description": "Copy the authorization code generated into the browser into the **Body** tab in the `code` parameter"
              },
              "response": []
            },
            {
              "name": "30 - GET /providers",
              "event": [
                {
                  "listen": "prerequest",
                  "script": {
                    "exec": [
                      "// set uuid and time",
                      "pm.environment.set(\"now\", (new Date()).toUTCString());",
                      "const uuid = require('uuid');",
                      "pm.environment.set(\"x-fapi-interaction-id\", uuid.v4());"
                    ],
                    "type": "text/javascript",
                    "packages": {},
                    "requests": {}
                  }
                }
              ],
              "request": {
                "method": "GET",
                "header": [
                  {
                    "key": "authorization",
                    "value": "Bearer {{token-from-client-credentials-grant-accounts}}",
                    "type": "text"
                  },
                  {
                    "key": "x-cert-dn",
                    "value": "CN=HQuZPIt3ipkh33Uxytox1E,OU=0015800001041RHAAY,O=OpenBanking,C=GB",
                    "type": "text"
                  },
                  {
                    "key": "x-cert-fingerprint",
                    "value": "xxx",
                    "type": "text"
                  },
                  {
                    "key": "x-fapi-interaction-id",
                    "value": "{{x-fapi-interaction-id}}",
                    "type": "text"
                  }
                ],
                "url": {
                  "raw": "{{rs}}/v1/providers",
                  "host": [
                    "{{rs}}"
                  ],
                  "path": [
                    "v1",
                    "providers"
                  ]
                }
              },
              "response": []
            }
          ]
        },
        {
          "name": "Balances, Accounts, Transactions",
          "item": [
            {
              "name": "Account",
              "item": [
                {
                  "name": "10 - Sign x-signature header [Utility]",
                  "event": [
                    {
                      "listen": "prerequest",
                      "script": {
                        "exec": [
                          "pm.environment.set(\"exp\", Date.now() / 1000 + 290);",
                          "pm.environment.set(\"nbf\", (Date.now() / 1000) - 10);",
                          "const uuid = require('uuid');",
                          "pm.environment.set(\"uuidv4\", uuid.v4());",
                          ""
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    },
                    {
                      "listen": "test",
                      "script": {
                        "exec": [
                          "const utilsSrc = pm.globals.get(\"utils\");",
                          "const utils = eval(utilsSrc); // returns the object from the IIFE",
                          "",
                          "if (pm.response.code !== 200) {",
                          "    utils.visualiseJson( \"Error\", pm.response.json());",
                          "    return;",
                          "} else {",
                          "    pm.environment.set(\"x-signature\", pm.response.text());",
                          "    utils.visualiseJws( \"x-signature header\", pm.response.text());",
                          "}"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    }
                  ],
                  "protocolProfileBehavior": {
                    "disableBodyPruning": true
                  },
                  "request": {
                    "method": "GET",
                    "header": [
                      {
                        "key": "content-type",
                        "value": "application/json"
                      }
                    ],
                    "body": {
                      "mode": "raw",
                      "raw": "{\n    \"header\": {\n        \"alg\": \"PS256\",\n        \"kid\": \"{{kid-local}}\"\n    },\n    \"body\": {\n        \"iss\": \"{{dc_id}}\",\n        \"exp\": {{exp}},\n        \"iat\": {{nbf}},\n        \"nbf\": {{nbf}},\n        \"aud\": [\n            \"PayNet OFP\",\n            \"{{dp_id}}\"\n        ],\n        \"jti\": \"{{uuidv4}}\",\n        \"qpm\": { },\n        \"url\": \"{{rs}}/v1/accounts/{{account_id}}\",\n        \"sub\": \"{{consent}}\"\n    },\n    \"signingKeyPEM\": \"{{pem-local}}\"\n}"
                    },
                    "url": {
                      "raw": "{{rs}}/o3/v1.0/message-signature",
                      "host": [
                        "{{rs}}"
                      ],
                      "path": [
                        "o3",
                        "v1.0",
                        "message-signature"
                      ]
                    }
                  },
                  "response": []
                },
                {
                  "name": "20 - GET Accounts",
                  "event": [
                    {
                      "listen": "test",
                      "script": {
                        "exec": [
                          "const utilsSrc = pm.globals.get(\"utils\");",
                          "const utils = eval(utilsSrc); // returns the object from the IIFE",
                          "",
                          "if (pm.response.code !== 200) {",
                          "    utils.visualiseJson( \"Error\", pm.response.json());",
                          "    return;",
                          "} else {",
                          "    const jws = utils.parseJwt(pm.response.text());",
                          "    pm.environment.set(\"jwe\", jws.payload.data);",
                          "    utils.visualiseJws('Response', pm.response.text());",
                          "}"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    },
                    {
                      "listen": "prerequest",
                      "script": {
                        "exec": [
                          ""
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    }
                  ],
                  "request": {
                    "method": "GET",
                    "header": [
                      {
                        "key": "authorization",
                        "value": "Bearer {{token-from-auth-code-grant-accounts}}",
                        "type": "text"
                      },
                      {
                        "key": "x-cert-dn",
                        "value": "CN=HQuZPIt3ipkh33Uxytox1E,OU=0015800001041RHAAY,O=OpenBanking,C=GB",
                        "type": "text"
                      },
                      {
                        "key": "x-cert-fingerprint",
                        "value": "xxx",
                        "type": "text"
                      },
                      {
                        "key": "x-signature",
                        "value": "{{x-signature}}",
                        "type": "text"
                      },
                      {
                        "key": "x-fapi-interaction-id",
                        "value": "{{uuidv4}}",
                        "type": "text"
                      },
                      {
                        "key": "x-enc-kid",
                        "value": "{{x-enc-kid}}",
                        "type": "text"
                      }
                    ],
                    "url": {
                      "raw": "{{rs}}/v1/accounts/{{account_id}}",
                      "host": [
                        "{{rs}}"
                      ],
                      "path": [
                        "v1",
                        "accounts",
                        "{{account_id}}"
                      ]
                    }
                  },
                  "response": []
                },
                {
                  "name": "30 - Decrypt [Utility]",
                  "event": [
                    {
                      "listen": "prerequest",
                      "script": {
                        "exec": [
                          ""
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    },
                    {
                      "listen": "test",
                      "script": {
                        "exec": [
                          "const utilsSrc = pm.globals.get(\"utils\");",
                          "const utils = eval(utilsSrc); // returns the object from the IIFE",
                          "",
                          "if (pm.response.code !== 200) {",
                          "    utils.visualiseJson( \"Error\", pm.response.json());",
                          "    return;",
                          "} else {",
                          "    utils.visualiseJson('Decrypted Payload', JSON.parse(pm.response.json().plainText));",
                          "}"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    }
                  ],
                  "protocolProfileBehavior": {
                    "disableBodyPruning": true
                  },
                  "request": {
                    "method": "GET",
                    "header": [
                      {
                        "key": "content-type",
                        "value": "application/json"
                      }
                    ],
                    "body": {
                      "mode": "raw",
                      "raw": "{\n    \"keyManagementAlgorithms\": [ \"RSA-OAEP-256\"],\n    \"contentEncryptionAlgorithms\": [\"A256GCM\"],\n    \"cipherText\": \"{{jwe}}\",\n    \"pem\": \"{{enc-local}}\"\n}"
                    },
                    "url": {
                      "raw": "{{rs}}/o3/v1.0/message-decryption",
                      "host": [
                        "{{rs}}"
                      ],
                      "path": [
                        "o3",
                        "v1.0",
                        "message-decryption"
                      ]
                    }
                  },
                  "response": []
                }
              ]
            },
            {
              "name": "Balance",
              "item": [
                {
                  "name": "10 - Sign x-signature header [Utility]",
                  "event": [
                    {
                      "listen": "prerequest",
                      "script": {
                        "exec": [
                          "pm.environment.set(\"exp\", Date.now() / 1000 + 290);",
                          "pm.environment.set(\"nbf\", (Date.now() / 1000) - 10);",
                          "const uuid = require('uuid');",
                          "pm.environment.set(\"uuidv4\", uuid.v4());",
                          ""
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    },
                    {
                      "listen": "test",
                      "script": {
                        "exec": [
                          "const utilsSrc = pm.globals.get(\"utils\");",
                          "const utils = eval(utilsSrc); // returns the object from the IIFE",
                          "",
                          "if (pm.response.code !== 200) {",
                          "    utils.visualiseJson( \"Error\", pm.response.json());",
                          "    return;",
                          "} else {",
                          "    pm.environment.set(\"x-signature\", pm.response.text());",
                          "    utils.visualiseJws( \"x-signature header\", pm.response.text());",
                          "}"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    }
                  ],
                  "protocolProfileBehavior": {
                    "disableBodyPruning": true
                  },
                  "request": {
                    "method": "GET",
                    "header": [
                      {
                        "key": "content-type",
                        "value": "application/json"
                      }
                    ],
                    "body": {
                      "mode": "raw",
                      "raw": "{\n    \"header\": {\n        \"alg\": \"PS256\",\n        \"kid\": \"{{kid-local}}\"\n    },\n    \"body\": {\n        \"iss\": \"{{dc_id}}\",\n        \"exp\": {{exp}},\n        \"iat\": {{nbf}},\n        \"nbf\": {{nbf}},\n        \"aud\": [\n            \"{{dp_id}}\",\n            \"PayNet OFP\"\n        ],\n        \"jti\": \"{{uuidv4}}\",\n        \"qpm\": { },\n        \"url\": \"{{rs}}/v1/accounts/{{account_id}}/balances\",\n        \"sub\": \"{{consent}}\"\n    },\n    \"signingKeyPEM\": \"{{pem-local}}\"\n}"
                    },
                    "url": {
                      "raw": "{{rs}}/o3/v1.0/message-signature",
                      "host": [
                        "{{rs}}"
                      ],
                      "path": [
                        "o3",
                        "v1.0",
                        "message-signature"
                      ]
                    }
                  },
                  "response": []
                },
                {
                  "name": "20 - GET Balances",
                  "event": [
                    {
                      "listen": "test",
                      "script": {
                        "exec": [
                          "const utilsSrc = pm.globals.get(\"utils\");",
                          "const utils = eval(utilsSrc); // returns the object from the IIFE",
                          "",
                          "if (pm.response.code !== 200) {",
                          "    utils.visualiseJson( \"Error\", pm.response.json());",
                          "    return;",
                          "} else {",
                          "    const jws = utils.parseJwt(pm.response.text());",
                          "    pm.environment.set(\"jwe\", jws.payload.data);",
                          "    utils.visualiseJws('Response', pm.response.text());",
                          "}"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    }
                  ],
                  "request": {
                    "method": "GET",
                    "header": [
                      {
                        "key": "authorization",
                        "value": "Bearer {{token-from-auth-code-grant-accounts}}",
                        "type": "text"
                      },
                      {
                        "key": "x-cert-dn",
                        "value": "CN=HQuZPIt3ipkh33Uxytox1E,OU=0015800001041RHAAY,O=OpenBanking,C=GB",
                        "type": "text"
                      },
                      {
                        "key": "x-cert-fingerprint",
                        "value": "xxx",
                        "type": "text"
                      },
                      {
                        "key": "x-signature",
                        "value": "{{x-signature}}",
                        "type": "text"
                      },
                      {
                        "key": "x-fapi-interaction-id",
                        "value": "{{uuidv4}}",
                        "type": "text"
                      },
                      {
                        "key": "x-enc-kid",
                        "value": "{{x-enc-kid}}",
                        "type": "text"
                      }
                    ],
                    "url": {
                      "raw": "{{rs}}/v1/accounts/{{account_id}}/balances",
                      "host": [
                        "{{rs}}"
                      ],
                      "path": [
                        "v1",
                        "accounts",
                        "{{account_id}}",
                        "balances"
                      ]
                    }
                  },
                  "response": []
                },
                {
                  "name": "30 - Decrypt [Utility]",
                  "event": [
                    {
                      "listen": "prerequest",
                      "script": {
                        "exec": [
                          ""
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    },
                    {
                      "listen": "test",
                      "script": {
                        "exec": [
                          "const utilsSrc = pm.globals.get(\"utils\");",
                          "const utils = eval(utilsSrc); // returns the object from the IIFE",
                          "",
                          "if (pm.response.code !== 200) {",
                          "    utils.visualiseJson( \"Error\", pm.response.json());",
                          "    return;",
                          "} else {",
                          "    utils.visualiseJson('Decrypted Payload', JSON.parse(pm.response.json().plainText));",
                          "}"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    }
                  ],
                  "protocolProfileBehavior": {
                    "disableBodyPruning": true
                  },
                  "request": {
                    "method": "GET",
                    "header": [
                      {
                        "key": "content-type",
                        "value": "application/json"
                      }
                    ],
                    "body": {
                      "mode": "raw",
                      "raw": "{\n    \"keyManagementAlgorithms\": [ \"RSA-OAEP-256\"],\n    \"contentEncryptionAlgorithms\": [\"A256GCM\"],\n    \"cipherText\": \"{{jwe}}\",\n    \"pem\": \"{{enc-local}}\"\n}"
                    },
                    "url": {
                      "raw": "{{rs}}/o3/v1.0/message-decryption",
                      "host": [
                        "{{rs}}"
                      ],
                      "path": [
                        "o3",
                        "v1.0",
                        "message-decryption"
                      ]
                    }
                  },
                  "response": []
                }
              ]
            },
            {
              "name": "Transaction",
              "item": [
                {
                  "name": "10 - Sign x-signature header [Utility]",
                  "event": [
                    {
                      "listen": "prerequest",
                      "script": {
                        "exec": [
                          "pm.environment.set(\"exp\", Date.now() / 1000 + 290);",
                          "pm.environment.set(\"nbf\", (Date.now() / 1000) - 10);",
                          "const uuid = require('uuid');",
                          "pm.environment.set(\"uuidv4\", uuid.v4());",
                          "",
                          "// query parameters",
                          "const qpm = { ",
                          "    \"to_date\": \"2025-12-25\", ",
                          "    \"page_size\": \"10\"",
                          "};",
                          "const qpmString = JSON.stringify(qpm);",
                          "pm.environment.set(\"qpm\", qpmString);",
                          ""
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    },
                    {
                      "listen": "test",
                      "script": {
                        "exec": [
                          "const utilsSrc = pm.globals.get(\"utils\");",
                          "const utils = eval(utilsSrc); // returns the object from the IIFE",
                          "",
                          "if (pm.response.code !== 200) {",
                          "    utils.visualiseJson( \"Error\", pm.response.json());",
                          "    return;",
                          "} else {",
                          "    pm.environment.set(\"x-signature\", pm.response.text());",
                          "    utils.visualiseJws( \"x-signature header\", pm.response.text());",
                          "}"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    }
                  ],
                  "protocolProfileBehavior": {
                    "disableBodyPruning": true
                  },
                  "request": {
                    "method": "GET",
                    "header": [
                      {
                        "key": "content-type",
                        "value": "application/json"
                      }
                    ],
                    "body": {
                      "mode": "raw",
                      "raw": "{\n    \"header\": {\n        \"alg\": \"PS256\",\n        \"kid\": \"{{kid-local}}\"\n    },\n    \"body\": {\n        \"iss\": \"{{dc_id}}\",\n        \"exp\": {{exp}},\n        \"iat\": {{nbf}},\n        \"nbf\": {{nbf}},\n        \"aud\": [\n            \"{{dp_id}}\",\n            \"PayNet OFP\"\n        ],\n        \"jti\": \"{{uuidv4}}\",\n        \"qpm\": {{qpm}},\n        \"url\": \"{{rs}}/v1/accounts/{{account_id}}/transactions\",\n        \"sub\": \"{{consent}}\"\n    },\n    \"signingKeyPEM\": \"{{pem-local}}\"\n}"
                    },
                    "url": {
                      "raw": "{{rs}}/o3/v1.0/message-signature?page_size=3",
                      "host": [
                        "{{rs}}"
                      ],
                      "path": [
                        "o3",
                        "v1.0",
                        "message-signature"
                      ],
                      "query": [
                        {
                          "key": "page_size",
                          "value": "3"
                        }
                      ]
                    }
                  },
                  "response": []
                },
                {
                  "name": "20 - GET transactions",
                  "event": [
                    {
                      "listen": "test",
                      "script": {
                        "exec": [
                          "const utilsSrc = pm.globals.get(\"utils\");",
                          "const utils = eval(utilsSrc); // returns the object from the IIFE",
                          "",
                          "if (pm.response.code !== 200) {",
                          "    utils.visualiseJson( \"Error\", pm.response.json());",
                          "    return;",
                          "} else {",
                          "    const jws = utils.parseJwt(pm.response.text());",
                          "    pm.environment.set(\"jwe\", jws.payload.data);",
                          "    utils.visualiseJws('Response', pm.response.text());",
                          "}"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    },
                    {
                      "listen": "prerequest",
                      "script": {
                        "exec": [
                          ""
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    }
                  ],
                  "request": {
                    "method": "GET",
                    "header": [
                      {
                        "key": "authorization",
                        "value": "Bearer {{token-from-auth-code-grant-accounts}}",
                        "type": "text"
                      },
                      {
                        "key": "x-cert-dn",
                        "value": "CN=HQuZPIt3ipkh33Uxytox1E,OU=0015800001041RHAAY,O=OpenBanking,C=GB",
                        "type": "text"
                      },
                      {
                        "key": "x-cert-fingerprint",
                        "value": "xxx",
                        "type": "text"
                      },
                      {
                        "key": "x-signature",
                        "value": "{{x-signature}}",
                        "type": "text"
                      },
                      {
                        "key": "x-fapi-interaction-id",
                        "value": "{{uuidv4}}",
                        "type": "text"
                      },
                      {
                        "key": "x-enc-kid",
                        "value": "{{x-enc-kid}}",
                        "type": "text"
                      }
                    ],
                    "url": {
                      "raw": "{{rs}}/v1/accounts/{{account_id}}/transactions?to_date=2025-12-25&page_size=10",
                      "host": [
                        "{{rs}}"
                      ],
                      "path": [
                        "v1",
                        "accounts",
                        "{{account_id}}",
                        "transactions"
                      ],
                      "query": [
                        {
                          "key": "to_date",
                          "value": "2025-12-25"
                        },
                        {
                          "key": "page_size",
                          "value": "10"
                        },
                        {
                          "key": "next_page_params",
                          "value": "eyJwYWdlU2l6ZSI6MTAsImZpcnN0UmVjb3JkIjoyMCwiYWRkaXRpb25hbFBhcmFtcyI6eyJ0b19kYXRlIjoiMjAyNS0xMi0yNSIsInBhZ2Vfc2l6ZSI6IjEwIn19",
                          "disabled": true
                        },
                        {
                          "key": "",
                          "value": "",
                          "disabled": true
                        }
                      ]
                    }
                  },
                  "response": []
                },
                {
                  "name": "30 - Decrypt [Utility]",
                  "event": [
                    {
                      "listen": "prerequest",
                      "script": {
                        "exec": [
                          ""
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    },
                    {
                      "listen": "test",
                      "script": {
                        "exec": [
                          "const utilsSrc = pm.globals.get(\"utils\");",
                          "const utils = eval(utilsSrc); // returns the object from the IIFE",
                          "",
                          "if (pm.response.code !== 200) {",
                          "    utils.visualiseJson( \"Error\", pm.response.json());",
                          "    return;",
                          "} else {",
                          "    utils.visualiseJson('Decrypted Payload', JSON.parse(pm.response.json().plainText));",
                          "}"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    }
                  ],
                  "protocolProfileBehavior": {
                    "disableBodyPruning": true
                  },
                  "request": {
                    "method": "GET",
                    "header": [
                      {
                        "key": "content-type",
                        "value": "application/json"
                      }
                    ],
                    "body": {
                      "mode": "raw",
                      "raw": "{\n    \"keyManagementAlgorithms\": [ \"RSA-OAEP-256\"],\n    \"contentEncryptionAlgorithms\": [\"A256GCM\"],\n    \"cipherText\": \"{{jwe}}\",\n    \"pem\": \"{{enc-local}}\"\n}"
                    },
                    "url": {
                      "raw": "{{rs}}/o3/v1.0/message-decryption",
                      "host": [
                        "{{rs}}"
                      ],
                      "path": [
                        "o3",
                        "v1.0",
                        "message-decryption"
                      ]
                    }
                  },
                  "response": []
                }
              ]
            },
            {
              "name": "Transactions - pagination",
              "item": [
                {
                  "name": "10 - Sign x-signature header [Utility]",
                  "event": [
                    {
                      "listen": "prerequest",
                      "script": {
                        "exec": [
                          "pm.environment.set(\"exp\", Date.now() / 1000 + 290);",
                          "pm.environment.set(\"nbf\", (Date.now() / 1000) - 10);",
                          "const uuid = require('uuid');",
                          "pm.environment.set(\"uuidv4\", uuid.v4());",
                          "",
                          "// query parameters",
                          "const qpm = { ",
                          "    \"from_date\": \"2025-10-01\", ",
                          "    \"to_date\": \"2025-11-30\", ",
                          "    \"page_size\": \"10\"",
                          "};",
                          "const qpmString = JSON.stringify(qpm);",
                          "pm.environment.set(\"qpm\", qpmString);"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    },
                    {
                      "listen": "test",
                      "script": {
                        "exec": [
                          "const utilsSrc = pm.globals.get(\"utils\");",
                          "const utils = eval(utilsSrc); // returns the object from the IIFE",
                          "",
                          "if (pm.response.code !== 200) {",
                          "    utils.visualiseJson( \"Error\", pm.response.json());",
                          "    return;",
                          "} else {",
                          "    pm.environment.set(\"x-signature\", pm.response.text());",
                          "    utils.visualiseJws( \"x-signature header\", pm.response.text());",
                          "}"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    }
                  ],
                  "protocolProfileBehavior": {
                    "disableBodyPruning": true
                  },
                  "request": {
                    "method": "GET",
                    "header": [
                      {
                        "key": "content-type",
                        "value": "application/json"
                      }
                    ],
                    "body": {
                      "mode": "raw",
                      "raw": "{\n    \"header\": {\n        \"alg\": \"PS256\",\n        \"kid\": \"{{kid-local}}\"\n    },\n    \"body\": {\n        \"iss\": \"{{dc_id}}\",\n        \"exp\": {{exp}},\n        \"iat\": {{nbf}},\n        \"nbf\": {{nbf}},\n        \"aud\": [\n            \"{{dp_id}}\",\n            \"PayNet OFP\"\n        ],\n        \"jti\": \"{{uuidv4}}\",\n        \"qpm\": {{qpm}},\n        \"url\": \"{{rs}}/v1/accounts/{{account_id}}/transactions\",\n        \"sub\": \"{{consent}}\"\n    },\n    \"signingKeyPEM\": \"{{pem-local}}\"\n}"
                    },
                    "url": {
                      "raw": "{{rs}}/o3/v1.0/message-signature",
                      "host": [
                        "{{rs}}"
                      ],
                      "path": [
                        "o3",
                        "v1.0",
                        "message-signature"
                      ]
                    }
                  },
                  "response": []
                },
                {
                  "name": "20 - GET transactions - first page",
                  "event": [
                    {
                      "listen": "test",
                      "script": {
                        "exec": [
                          "const utilsSrc = pm.globals.get(\"utils\");",
                          "const utils = eval(utilsSrc); // returns the object from the IIFE",
                          "",
                          "if (pm.response.code !== 200) {",
                          "    utils.visualiseJson( \"Error\", pm.response.json());",
                          "    return;",
                          "} else {",
                          "    const jws = utils.parseJwt(pm.response.text());",
                          "    pm.environment.set(\"jwe\", jws.payload.data);",
                          "    utils.visualiseJws('Response', pm.response.text());",
                          "}"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    }
                  ],
                  "request": {
                    "method": "GET",
                    "header": [
                      {
                        "key": "authorization",
                        "value": "Bearer {{token-from-auth-code-grant-accounts}}",
                        "type": "text"
                      },
                      {
                        "key": "x-cert-dn",
                        "value": "CN=HQuZPIt3ipkh33Uxytox1E,OU=0015800001041RHAAY,O=OpenBanking,C=GB",
                        "type": "text"
                      },
                      {
                        "key": "x-cert-fingerprint",
                        "value": "xxx",
                        "type": "text"
                      },
                      {
                        "key": "x-signature",
                        "value": "{{x-signature}}",
                        "type": "text"
                      },
                      {
                        "key": "x-fapi-interaction-id",
                        "value": "{{uuidv4}}",
                        "type": "text"
                      },
                      {
                        "key": "x-enc-kid",
                        "value": "{{x-enc-kid}}",
                        "type": "text"
                      }
                    ],
                    "url": {
                      "raw": "{{rs}}/v1/accounts/{{account_id}}/transactions?from_date=2025-10-01&to_date=2025-11-30&page_size=10",
                      "host": [
                        "{{rs}}"
                      ],
                      "path": [
                        "v1",
                        "accounts",
                        "{{account_id}}",
                        "transactions"
                      ],
                      "query": [
                        {
                          "key": "from_date",
                          "value": "2025-10-01"
                        },
                        {
                          "key": "to_date",
                          "value": "2025-11-30"
                        },
                        {
                          "key": "page_size",
                          "value": "10"
                        },
                        {
                          "key": "",
                          "value": "",
                          "disabled": true
                        }
                      ]
                    }
                  },
                  "response": []
                },
                {
                  "name": "30 - Decrypt [Utility] - first page",
                  "event": [
                    {
                      "listen": "prerequest",
                      "script": {
                        "exec": [
                          ""
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    },
                    {
                      "listen": "test",
                      "script": {
                        "exec": [
                          "const utilsSrc = pm.globals.get(\"utils\");",
                          "const utils = eval(utilsSrc); // returns the object from the IIFE",
                          "",
                          "if (pm.response.code !== 200) {",
                          "    utils.visualiseJson( \"Error\", pm.response.json());",
                          "} else {",
                          "    const decryptedResponse = pm.response.json();",
                          "    const payload = JSON.parse(decryptedResponse.plainText);",
                          "    console.log(payload);",
                          "    const next_page_params = payload.meta.next_page_params;",
                          "    console.log(next_page_params);",
                          "    pm.environment.set(\"next_page_params\", next_page_params); // store the next_page_params in the environment variable",
                          "",
                          "    utils.visualiseJson('Decrypted Payload', JSON.parse(pm.response.json().plainText));",
                          "}"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    }
                  ],
                  "protocolProfileBehavior": {
                    "disableBodyPruning": true
                  },
                  "request": {
                    "method": "GET",
                    "header": [
                      {
                        "key": "content-type",
                        "value": "application/json"
                      }
                    ],
                    "body": {
                      "mode": "raw",
                      "raw": "{\n    \"keyManagementAlgorithms\": [ \"RSA-OAEP-256\"],\n    \"contentEncryptionAlgorithms\": [\"A256GCM\"],\n    \"cipherText\": \"{{jwe}}\",\n    \"pem\": \"{{enc-local}}\"\n}"
                    },
                    "url": {
                      "raw": "{{rs}}/o3/v1.0/message-decryption",
                      "host": [
                        "{{rs}}"
                      ],
                      "path": [
                        "o3",
                        "v1.0",
                        "message-decryption"
                      ]
                    }
                  },
                  "response": []
                },
                {
                  "name": "40 - Sign x-signature header for subsequent page [Utility]",
                  "event": [
                    {
                      "listen": "prerequest",
                      "script": {
                        "exec": [
                          "pm.environment.set(\"exp\", Date.now() / 1000 + 290);",
                          "pm.environment.set(\"nbf\", (Date.now() / 1000) - 10);",
                          "const uuid = require('uuid');",
                          "pm.environment.set(\"uuidv4\", uuid.v4());",
                          "",
                          "// query parameters",
                          "const qpm = { ",
                          "    \"page_size\": \"10\",",
                          "    \"from_date\": \"2025-10-01\",",
                          "    \"to_date\": \"2025-11-30\",",
                          "    \"next_page_params\": pm.environment.get(\"next_page_params\")",
                          "};",
                          "const qpmString = JSON.stringify(qpm);",
                          "pm.environment.set(\"qpm\", qpmString);"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    },
                    {
                      "listen": "test",
                      "script": {
                        "exec": [
                          "const utilsSrc = pm.globals.get(\"utils\");",
                          "const utils = eval(utilsSrc); // returns the object from the IIFE",
                          "",
                          "if (pm.response.code !== 200) {",
                          "    utils.visualiseJson( \"Error\", pm.response.json());",
                          "    return;",
                          "} else {",
                          "    pm.environment.set(\"x-signature\", pm.response.text());",
                          "    utils.visualiseJws( \"x-signature header\", pm.response.text());",
                          "}"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    }
                  ],
                  "protocolProfileBehavior": {
                    "disableBodyPruning": true
                  },
                  "request": {
                    "method": "GET",
                    "header": [
                      {
                        "key": "content-type",
                        "value": "application/json"
                      }
                    ],
                    "body": {
                      "mode": "raw",
                      "raw": "{\n    \"header\": {\n        \"alg\": \"PS256\",\n        \"kid\": \"{{kid-local}}\"\n    },\n    \"body\": {\n        \"iss\": \"{{dc_id}}\",\n        \"exp\": {{exp}},\n        \"iat\": {{nbf}},\n        \"nbf\": {{nbf}},\n        \"aud\": [\n            \"{{dp_id}}\",\n            \"PayNet OFP\"\n        ],\n        \"jti\": \"{{uuidv4}}\",\n        \"qpm\": {{qpm}},\n        \"url\": \"{{rs}}/v1/accounts/{{account_id}}/transactions\",\n        \"sub\": \"{{consent}}\"\n    },\n    \"signingKeyPEM\": \"{{pem-local}}\"\n}"
                    },
                    "url": {
                      "raw": "{{rs}}/o3/v1.0/message-signature",
                      "host": [
                        "{{rs}}"
                      ],
                      "path": [
                        "o3",
                        "v1.0",
                        "message-signature"
                      ]
                    }
                  },
                  "response": []
                },
                {
                  "name": "40 - GET transactions - subsequent pages",
                  "event": [
                    {
                      "listen": "test",
                      "script": {
                        "exec": [
                          "const utilsSrc = pm.globals.get(\"utils\");",
                          "const utils = eval(utilsSrc); // returns the object from the IIFE",
                          "",
                          "if (pm.response.code !== 200) {",
                          "    utils.visualiseJson( \"Error\", pm.response.json());",
                          "    return;",
                          "} else {",
                          "    const jws = utils.parseJwt(pm.response.text());",
                          "    pm.environment.set(\"jwe\", jws.payload.data);",
                          "    utils.visualiseJws('Response', pm.response.text());",
                          "}"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    }
                  ],
                  "request": {
                    "method": "GET",
                    "header": [
                      {
                        "key": "authorization",
                        "value": "Bearer {{token-from-auth-code-grant-accounts}}",
                        "type": "text"
                      },
                      {
                        "key": "x-cert-dn",
                        "value": "CN=HQuZPIt3ipkh33Uxytox1E,OU=0015800001041RHAAY,O=OpenBanking,C=GB",
                        "type": "text"
                      },
                      {
                        "key": "x-cert-fingerprint",
                        "value": "xxx",
                        "type": "text"
                      },
                      {
                        "key": "x-signature",
                        "value": "{{x-signature}}",
                        "type": "text"
                      },
                      {
                        "key": "x-fapi-interaction-id",
                        "value": "{{uuidv4}}",
                        "type": "text"
                      },
                      {
                        "key": "x-enc-kid",
                        "value": "{{x-enc-kid}}",
                        "type": "text"
                      }
                    ],
                    "url": {
                      "raw": "{{rs}}/v1/accounts/{{account_id}}/transactions?page_size=10&next_page_params={{next_page_params}}&from_date=2025-10-01&to_date=2025-11-30",
                      "host": [
                        "{{rs}}"
                      ],
                      "path": [
                        "v1",
                        "accounts",
                        "{{account_id}}",
                        "transactions"
                      ],
                      "query": [
                        {
                          "key": "page_size",
                          "value": "10"
                        },
                        {
                          "key": "next_page_params",
                          "value": "{{next_page_params}}"
                        },
                        {
                          "key": "from_date",
                          "value": "2025-10-01"
                        },
                        {
                          "key": "to_date",
                          "value": "2025-11-30"
                        },
                        {
                          "key": "",
                          "value": "",
                          "disabled": true
                        }
                      ]
                    }
                  },
                  "response": []
                },
                {
                  "name": "50 - Decrypt [Utility] - subsequent pages",
                  "event": [
                    {
                      "listen": "prerequest",
                      "script": {
                        "exec": [
                          ""
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    },
                    {
                      "listen": "test",
                      "script": {
                        "exec": [
                          "const utilsSrc = pm.globals.get(\"utils\");",
                          "const utils = eval(utilsSrc); // returns the object from the IIFE",
                          "",
                          "if (pm.response.code !== 200) {",
                          "    utils.visualiseJson( \"Error\", pm.response.json());",
                          "} else {",
                          "    const decryptedResponse = JSON.parse(pm.response.json().plainText);",
                          "    const next_page_params = decryptedResponse.meta.next_page_params;",
                          "    pm.environment.set(\"next_page_params\", next_page_params); // store the next_page_params in the environment variable",
                          "",
                          "    utils.visualiseJson('Decrypted Payload', JSON.parse(pm.response.json().plainText));",
                          "}"
                        ],
                        "type": "text/javascript",
                        "packages": {},
                        "requests": {}
                      }
                    }
                  ],
                  "protocolProfileBehavior": {
                    "disableBodyPruning": true
                  },
                  "request": {
                    "method": "GET",
                    "header": [
                      {
                        "key": "content-type",
                        "value": "application/json"
                      }
                    ],
                    "body": {
                      "mode": "raw",
                      "raw": "{\n    \"keyManagementAlgorithms\": [ \"RSA-OAEP-256\"],\n    \"contentEncryptionAlgorithms\": [\"A256GCM\"],\n    \"cipherText\": \"{{jwe}}\",\n    \"pem\": \"{{enc-local}}\"\n}"
                    },
                    "url": {
                      "raw": "{{rs}}/o3/v1.0/message-decryption",
                      "host": [
                        "{{rs}}"
                      ],
                      "path": [
                        "o3",
                        "v1.0",
                        "message-decryption"
                      ]
                    }
                  },
                  "response": []
                }
              ]
            }
          ],
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Shared JWT Visualization Function",
                  "// This function can be called from any request's post-response script with: visualizeJWT()",
                  "",
                  "function visualizeJWT() {",
                  "    const responseText = pm.response.text();",
                  "",
                  "    // Decode JWT parts (base64url decode)",
                  "    function decodeBase64Url(str) {",
                  "        const base64 = str.replace(/-/g, '+').replace(/_/g, '/');",
                  "        const decoded = atob(base64);",
                  "        return JSON.parse(decoded);",
                  "    }",
                  "",
                  "    function decodeJWTToken(token) {",
                  "        const parts = token.split('.');",
                  "        if (parts.length !== 3) {",
                  "            throw new Error('Invalid JWT format');",
                  "        }",
                  "        return {",
                  "            header: decodeBase64Url(parts[0]),",
                  "            payload: decodeBase64Url(parts[1])",
                  "        };",
                  "    }",
                  "",
                  "    var template = `",
                  "    <link href=\"https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css\" rel=\"stylesheet\" />",
                  "    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js\"></script>",
                  "    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-json.min.js\"></script>",
                  "",
                  "    <style>",
                  "        body {",
                  "            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;",
                  "            background-color: #1e1e1e;",
                  "            color: #d4d4d4;",
                  "            padding: 20px;",
                  "            margin: 0;",
                  "        }",
                  "        .section {",
                  "            margin-bottom: 24px;",
                  "        }",
                  "        .section-title {",
                  "            font-size: 14px;",
                  "            font-weight: 600;",
                  "            color: #569cd6;",
                  "            margin-bottom: 8px;",
                  "            text-transform: uppercase;",
                  "            letter-spacing: 0.5px;",
                  "        }",
                  "        pre[class*=\"language-\"] {",
                  "            margin: 0;",
                  "            border-radius: 6px;",
                  "            font-size: 13px;",
                  "            line-height: 1.5;",
                  "        }",
                  "        code[class*=\"language-\"] {",
                  "            font-family: 'Fira Code', 'Consolas', 'Monaco', monospace;",
                  "        }",
                  "        .error {",
                  "            color: #f48771;",
                  "            background-color: #3a1d1d;",
                  "            padding: 12px;",
                  "            border-radius: 6px;",
                  "            border-left: 3px solid #f48771;",
                  "        }",
                  "    </style>",
                  "",
                  "    <div class=\"section\">",
                  "        <div class=\"section-title\">JWT Header</div>",
                  "        {{#if error}}",
                  "            <div class=\"error\">{{error}}</div>",
                  "        {{else}}",
                  "            <pre class=\"language-json\"><code class=\"language-json\" id=\"header-code\"></code></pre>",
                  "        {{/if}}",
                  "    </div>",
                  "",
                  "    {{#unless error}}",
                  "    <div class=\"section\">",
                  "        <div class=\"section-title\">JWT Payload</div>",
                  "        <pre class=\"language-json\"><code class=\"language-json\" id=\"payload-code\"></code></pre>",
                  "    </div>",
                  "    {{/unless}}",
                  "",
                  "    <script>",
                  "        pm.getData(function (err, value) {",
                  "            if (!value.error) {",
                  "                var headerEl = document.getElementById('header-code');",
                  "                var payloadEl = document.getElementById('payload-code');",
                  "                ",
                  "                headerEl.textContent = value.headerJson;",
                  "                payloadEl.textContent = value.payloadJson;",
                  "                ",
                  "                Prism.highlightElement(headerEl);",
                  "                Prism.highlightElement(payloadEl);",
                  "            }",
                  "        });",
                  "    </script>`;",
                  "",
                  "    function constructVisualizerPayload() {",
                  "        try {",
                  "            const decoded = decodeJWTToken(responseText);",
                  "            return {",
                  "                headerJson: JSON.stringify(decoded.header, null, 2),",
                  "                payloadJson: JSON.stringify(decoded.payload, null, 2),",
                  "                error: null",
                  "            };",
                  "        } catch (e) {",
                  "            return {",
                  "                error: 'Failed to decode JWT: ' + e.message,",
                  "                headerJson: null,",
                  "                payloadJson: null",
                  "            };",
                  "        }",
                  "    }",
                  "",
                  "    pm.visualizer.set(template, constructVisualizerPayload());",
                  "}",
                  "",
                  "// Make the function globally available for child requests",
                  "pm.visualizeJWT = visualizeJWT;"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Events",
      "item": [
        {
          "name": "Review Events [Utility]",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "const utilsSrc = pm.globals.get(\"utils\");",
                  "const utils = eval(utilsSrc); // returns the object from the IIFE",
                  "",
                  "if (pm.response.code !== 200) {",
                  "    utils.visualiseJson( \"Error\", pm.response.text());",
                  "    return;",
                  "} else {",
                  "    const event = pm.response.json()",
                  "    console.log(event);",
                  "    const lastEvent = event.data[event.data.length - 1];",
                  "    utils.visualiseJws( \"private_key_jwt\", lastEvent.requestBody);",
                  "}"
                ],
                "type": "text/javascript",
                "packages": {},
                "requests": {}
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{rs}}/review-emitted-events",
              "host": [
                "{{rs}}"
              ],
              "path": [
                "review-emitted-events"
              ],
              "query": [
                {
                  "key": "minutesInPast",
                  "value": "5",
                  "disabled": true
                }
              ]
            }
          },
          "response": []
        }
      ]
    }
  ],
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "type": "text/javascript",
        "packages": {},
        "requests": {},
        "exec": [
          "function b64urlDecode(input) {",
          "  const pad = '='.repeat((4 - (input.length % 4)) % 4);",
          "  const b64 = (String(input) + pad).replace(/-/g, '+').replace(/_/g, '/');",
          "  return atob(b64);",
          "}",
          "",
          "function parseJwt(jwtText) {",
          "  const jwt = String(jwtText || '');",
          "  const parts = jwt.split('.');",
          "  const signature = parts[2] || '';",
          "",
          "  let header = {};",
          "  let payload = {};",
          "",
          "  try { header = JSON.parse(b64urlDecode(parts[0] || '')); } catch (_) {}",
          "  try { payload = JSON.parse(b64urlDecode(parts[1] || '')); } catch (_) {}",
          "",
          "  return { jwt, header, payload, signature };",
          "}",
          "",
          "function visualiseJws(title, jwtText) {",
          "    console.log('visualising jws ...');",
          "  const { jwt, header, payload, signature } = parseJwt(jwtText ?? pm.response.text());",
          "",
          "  const templateProperties = {",
          "    title,",
          "    headerJson: JSON.stringify(header, null, 2),",
          "    payloadJson: JSON.stringify(payload, null, 2),",
          "    signature,",
          "    rawJwt: jwt",
          "  };",
          "",
          "    const template = pm.collectionVariables.get(\"collJwtTemplate\");",
          "    pm.visualizer.set(template, templateProperties);",
          "}",
          "",
          "function visualiseJson(title, json) {",
          "    const template = pm.collectionVariables.get(\"collJsonTemplate\");",
          "    pm.visualizer.set(template, {title, json: JSON.stringify(json, null, 2)});",
          "}",
          "",
          "",
          "// Make it global",
          "const utilsSrc = `",
          "(function () {",
          "  ${b64urlDecode.toString()}",
          "  ${parseJwt.toString()}",
          "  ${visualiseJws.toString()}",
          "  ${visualiseJson.toString()}",
          "",
          "  return {",
          "    b64urlDecode,",
          "    parseJwt,",
          "    visualiseJws,",
          "    visualiseJson",
          "  };",
          "})()",
          "`;",
          "",
          "pm.globals.set(\"utils\", utilsSrc);"
        ]
      }
    },
    {
      "listen": "test",
      "script": {
        "type": "text/javascript",
        "packages": {},
        "requests": {},
        "exec": [
          ""
        ]
      }
    }
  ],
  "variable": [
    {
      "key": "collJwtTemplate",
      "value": "<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css\" />\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-json.min.js\"></script>\n<style>\n  :root{\n    /* Ozone-like tokens (approximate) */\n    --oz-navy: #0b1f4a;\n    --oz-navy-2: #102a63;\n    --oz-teal: #2bb9c8;\n    --oz-teal-2: #1aa7b7;\n    --oz-accent: #ff6a3d;\n\n    --oz-bg: #f6f8fb;\n    --oz-surface: #ffffff;\n    --oz-surface-2: #f2f5f9;\n\n    --oz-text: #0e1525;\n    --oz-muted: #5b6474;\n    --oz-border: rgba(16, 42, 99, 0.12);\n\n    --oz-radius: 5px;\n    --oz-radius-sm: 5px;\n\n    --oz-shadow: 0 10px 30px rgba(11, 31, 74, 0.10);\n    --oz-shadow-sm: 0 6px 18px rgba(11, 31, 74, 0.08);\n  }\n\n  .jwt-container {\n    font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, \"Apple Color Emoji\",\"Segoe UI Emoji\";\n    max-width: 900px;\n    margin: 0 auto;\n    padding: 28px 18px;\n    color: var(--oz-text);\n    background: transparent;\n  }\n\n  .jwt-title {\n    font-size: 20px;\n    font-weight: 750;\n    letter-spacing: -0.02em;\n    color: var(--oz-navy);\n    margin: 0 0 12px;\n    text-align: left;\n  }\n\n  .jwt-part {\n    margin-top: 24px;\n  }\n\n  .jwt-part-title {\n    font-size: 13px;\n    font-weight: 700;\n    text-transform: uppercase;\n    letter-spacing: 0.08em;\n    margin-bottom: 10px;\n    color: var(--oz-muted);\n  }\n\n  .jwt-part-value {\n    font-family: \"JetBrains Mono\", \"Fira Code\", \"SF Mono\", Consolas, monospace;\n    font-size: 11px;\n    word-break: break-all;\n    background: var(--oz-surface-2);\n    padding: 14px 16px;\n    border-radius: var(--oz-radius-sm);\n    color: var(--oz-text);\n    line-height: 1.7;\n    border: 1px solid var(--oz-border);\n  }\n</style>\n\n<div class=\"jwt-container\">\n  <div class=\"jwt-title\">{{title}}</div>\n\n  <div class=\"jwt-part\">\n    <div class=\"jwt-part-title\">Header</div>\n    <div class=\"jwt-part-value\">\n        <pre class=\" language-json\"><code class=\"language-json\">{{headerJson}}</code></pre>\n    </div>  \n  </div>\n\n  <div class=\"jwt-part\">\n    <div class=\"jwt-part-title\">Body</div>\n    <div class=\"jwt-part-value\">\n        <pre class=\" language-json\"><code class=\"language-json\">{{payloadJson}}</code></pre>\n    </div>  \n  </div>\n\n  <div class=\"jwt-part\">\n    <div class=\"jwt-part-title\">Raw JWT</div>\n    <div class=\"jwt-part-value\">{{rawJwt}}</div>\n  </div>\n</div>\n\n<script>\n  // Initialize Prism.js syntax highlighting after content is loaded\n  setTimeout(function() {\n    if (typeof Prism !== 'undefined') {\n      Prism.highlightAll();\n    }\n  }, 100);\n</script>"
    },
    {
      "key": "collJsonTemplate",
      "value": "<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css\" />\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-json.min.js\"></script>\n<style>\n  :root{\n    /* Ozone-like tokens (approximate) */\n    --oz-navy: #0b1f4a;\n    --oz-navy-2: #102a63;\n    --oz-teal: #2bb9c8;\n    --oz-teal-2: #1aa7b7;\n    --oz-accent: #ff6a3d;\n    --oz-bg: #f6f8fb;\n    --oz-surface: #ffffff;\n    --oz-surface-2: #f2f5f9;\n    --oz-text: #0e1525;\n    --oz-muted: #5b6474;\n    --oz-border: rgba(16, 42, 99, 0.12);\n    --oz-radius: 5px;\n    --oz-radius-sm: 5px;\n    --oz-shadow: 0 10px 30px rgba(11, 31, 74, 0.10);\n    --oz-shadow-sm: 0 6px 18px rgba(11, 31, 74, 0.08);\n  }\n  .json-container {\n    font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, \"Apple Color Emoji\",\"Segoe UI Emoji\";\n    max-width: 900px;\n    margin: 0 auto;\n    padding: 28px 18px;\n    color: var(--oz-text);\n    background: transparent;\n  }\n  .json-title {\n    font-size: 20px;\n    font-weight: 750;\n    letter-spacing: -0.02em;\n    color: var(--oz-navy);\n    margin: 0 0 12px;\n    text-align: left;\n  }\n  .json-part {\n    margin-top: 24px;\n  }\n  .json-part-title {\n    font-size: 13px;\n    font-weight: 700;\n    text-transform: uppercase;\n    letter-spacing: 0.08em;\n    margin-bottom: 10px;\n    color: var(--oz-muted);\n  }\n  .json-part-value {\n    font-family: \"JetBrains Mono\", \"Fira Code\", \"SF Mono\", Consolas, monospace;\n    font-size: 11px;\n    word-break: break-all;\n    background: var(--oz-surface-2);\n    padding: 14px 16px;\n    border-radius: var(--oz-radius-sm);\n    color: var(--oz-text);\n    line-height: 1.7;\n    border: 1px solid var(--oz-border);\n  }\n</style>\n<div class=\"json-container\">\n  <div class=\"json-title\">{{title}}</div>\n  <div class=\"json-part\">\n    <div class=\"json-part-value\">\n        <pre class=\" language-json\"><code class=\"language-json\">{{json}}</code></pre>\n    </div>  \n  </div>\n<script>\n  // Initialize Prism.js syntax highlighting after content is loaded\n  setTimeout(function() {\n    if (typeof Prism !== 'undefined') {\n      Prism.highlightAll();\n    }\n  }, 100);\n</script>"
    }
  ]
}