{
  "info": {
    "_postman_id": "c3e64ff5-9ba4-4a67-a211-3f879a9ac27c",
    "name": "MEMEH RTPO Fintech and Payment Facilitator API",
    "description": "Executable MEMEH RTPO Request-to-Pay integration journey for approved fintech and payment facilitator backends. Run the requests in order. Flow 1 resolves payer and payee aliases through CAS V2 and stores selectable opaque financial-address IDs. Flow 2 submits those selections. The remaining requests read current status and immutable lifecycle events. Full financial addresses are never exposed to this client collection.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{memeh_api_key}}",
        "type": "string"
      }
    ]
  },
  "item": [
    {
      "name": "00 - Connectivity",
      "description": "Confirm that the configured MEMEH RTPO endpoint is reachable before running the protected flow.",
      "item": [
        {
          "name": "Health Check",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "GET",
            "header": [],
            "url": "{{memeh_base_url}}/health",
            "description": "Public liveness endpoint. A successful response confirms HTTP connectivity only; it does not prove CAS, routing, or participant-adapter readiness."
          },
          "response": [],
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"Health endpoint returns HTTP 200\", function () {",
                  "  pm.response.to.have.status(200);",
                  "});",
                  "",
                  "pm.test(\"Health response is JSON\", function () {",
                  "  pm.expect(pm.response.headers.get(\"Content-Type\") || \"\").to.include(\"application/json\");",
                  "});"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "01 - Required Two-Flow Request-to-Pay",
      "description": "Run in order. Resolve both parties first, choose active address options, then create the Request-to-Pay with the captured opaque IDs.",
      "item": [
        {
          "name": "Flow 1 - Resolve Payer and Payee",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              },
              {
                "key": "Accept",
                "value": "application/json",
                "type": "text"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"payer_alias\": \"{{payer_alias}}\",\n  \"payee_alias\": \"{{payee_alias}}\",\n  \"amount\": \"{{amount}}\",\n  \"currency\": \"{{currency}}\",\n  \"reference\": \"{{reference}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": "{{memeh_base_url}}/api/v1/aliases/resolve",
            "description": "Required Flow 1. MEMEH RTPO resolves both aliases through CAS V2 and returns separate payer/payee participant and masked financial-address options. The collection stores the default active option, or the first active option when no default is marked."
          },
          "response": [],
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const runId = Date.now().toString();",
                  "pm.collectionVariables.set(\"reference\", `POSTMAN-${runId}`);",
                  "pm.collectionVariables.set(\"idempotency_key\", `postman-${runId}-attempt-1`);",
                  "[\"resolution_id\", \"payer_finaddress_id\", \"payee_finaddress_id\", \"request_id\"].forEach(function (name) {",
                  "  pm.collectionVariables.unset(name);",
                  "});"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"Flow 1 returns HTTP 200\", function () {",
                  "  pm.response.to.have.status(200);",
                  "});",
                  "",
                  "const body = pm.response.json();",
                  "const payerOptions = body.payer && Array.isArray(body.payer.finaddresses) ? body.payer.finaddresses : [];",
                  "const payeeOptions = body.payee && Array.isArray(body.payee.finaddresses) ? body.payee.finaddresses : [];",
                  "const activePayerOptions = payerOptions.filter(function (option) { return option.status === \"ACTIVE\"; });",
                  "const activePayeeOptions = payeeOptions.filter(function (option) { return option.status === \"ACTIVE\"; });",
                  "",
                  "pm.test(\"CAS resolution is verified and identified\", function () {",
                  "  pm.expect(body.verified).to.eql(true);",
                  "  pm.expect(body.resolution_id).to.be.a(\"string\").and.not.empty;",
                  "  pm.expect(body.source).to.be.a(\"string\").and.not.empty;",
                  "});",
                  "",
                  "pm.test(\"Payer has at least one active participant/address option\", function () {",
                  "  pm.expect(activePayerOptions.length).to.be.greaterThan(0);",
                  "});",
                  "",
                  "pm.test(\"Payee has at least one active participant/address option\", function () {",
                  "  pm.expect(activePayeeOptions.length).to.be.greaterThan(0);",
                  "});",
                  "",
                  "pm.test(\"Public options contain opaque IDs and masked values\", function () {",
                  "  activePayerOptions.concat(activePayeeOptions).forEach(function (option) {",
                  "    pm.expect(option.id).to.match(/^fa_/);",
                  "    pm.expect(option.masked).to.be.a(\"string\").and.not.empty;",
                  "    pm.expect(option.servicer_id).to.be.a(\"string\").and.not.empty;",
                  "    pm.expect(option).not.to.have.property(\"fin_address\");",
                  "  });",
                  "});",
                  "",
                  "if (body.verified && body.resolution_id && activePayerOptions.length && activePayeeOptions.length) {",
                  "  const payerChoice = activePayerOptions.find(function (option) { return option.default; }) || activePayerOptions[0];",
                  "  const payeeChoice = activePayeeOptions.find(function (option) { return option.default; }) || activePayeeOptions[0];",
                  "  pm.collectionVariables.set(\"resolution_id\", body.resolution_id);",
                  "  pm.collectionVariables.set(\"payer_finaddress_id\", payerChoice.id);",
                  "  pm.collectionVariables.set(\"payee_finaddress_id\", payeeChoice.id);",
                  "  pm.collectionVariables.set(\"payer_choice_label\", payerChoice.label || payerChoice.servicer_id);",
                  "  pm.collectionVariables.set(\"payee_choice_label\", payeeChoice.label || payeeChoice.servicer_id);",
                  "  console.log(\"Selected payer option\", payerChoice.label, payerChoice.masked, payerChoice.servicer_id);",
                  "  console.log(\"Selected payee option\", payeeChoice.label, payeeChoice.masked, payeeChoice.servicer_id);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Flow 2 - Create Request-to-Pay",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              },
              {
                "key": "Accept",
                "value": "application/json",
                "type": "text"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"idempotency_key\": \"{{idempotency_key}}\",\n  \"resolution_id\": \"{{resolution_id}}\",\n  \"payer_finaddress_id\": \"{{payer_finaddress_id}}\",\n  \"payee_finaddress_id\": \"{{payee_finaddress_id}}\",\n  \"payer_alias\": \"{{payer_alias}}\",\n  \"payee_alias\": \"{{payee_alias}}\",\n  \"merchant_id\": \"{{merchant_id}}\",\n  \"amount\": \"{{amount}}\",\n  \"currency\": \"{{currency}}\",\n  \"reference\": \"{{reference}}\",\n  \"description\": \"{{description}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": "{{memeh_base_url}}/api/v1/payment-requests",
            "description": "Required Flow 2. Core re-resolves CAS V2, verifies that resolution_id and both opaque selection IDs are still valid, then routes using the selected payee servicer and dispatches the canonical instruction."
          },
          "response": [],
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "[\"resolution_id\", \"payer_finaddress_id\", \"payee_finaddress_id\"].forEach(function (name) {",
                  "  if (!pm.collectionVariables.get(name)) {",
                  "    throw new Error(`${name} is missing. Run Flow 1 - Resolve Payer and Payee first.`);",
                  "  }",
                  "});"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"Flow 2 returns HTTP 202\", function () {",
                  "  pm.response.to.have.status(202);",
                  "});",
                  "",
                  "const body = pm.response.json();",
                  "pm.test(\"Accepted response contains request correlation\", function () {",
                  "  pm.expect(body.request_id).to.be.a(\"string\").and.not.empty;",
                  "  pm.expect(body.status).to.be.a(\"string\").and.not.empty;",
                  "  pm.expect(body.dispatch).to.be.an(\"object\");",
                  "});",
                  "",
                  "pm.test(\"Dispatch acceptance is not misreported as payment completion\", function () {",
                  "  pm.expect(body.status).not.to.eql(\"ACSC\");",
                  "});",
                  "",
                  "if (body.request_id) {",
                  "  pm.collectionVariables.set(\"request_id\", body.request_id);",
                  "}"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "02 - Status and Lifecycle",
      "description": "Read the current state and immutable event history using the request_id captured from Flow 2.",
      "item": [
        {
          "name": "Read Current Request Status",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": "{{memeh_base_url}}/api/v1/payment-requests/{{request_id}}",
            "description": "Returns the latest known request state. DISPATCHED, RCVD, PDNG, and ACSP remain non-final. ACSC is successful completion; RETURNED, RJCT, CANC, and FAILED are terminal outcomes."
          },
          "response": [],
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if (!pm.collectionVariables.get(\"request_id\")) {",
                  "  throw new Error(\"request_id is missing. Run Flow 2 - Create Request-to-Pay first.\");",
                  "}"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"Status endpoint returns HTTP 200\", function () {",
                  "  pm.response.to.have.status(200);",
                  "});",
                  "",
                  "const body = pm.response.json();",
                  "const knownStatuses = [\"RECEIVED\", \"ROUTABLE\", \"DISPATCHED\", \"RCVD\", \"PDNG\", \"ACSP\", \"ACSC\", \"RETURNED\", \"RJCT\", \"CANC\", \"FAILED\"];",
                  "pm.test(\"Status response matches the captured request\", function () {",
                  "  pm.expect(body.request_id).to.eql(pm.collectionVariables.get(\"request_id\"));",
                  "  pm.expect(knownStatuses).to.include(body.status);",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "Read Immutable Lifecycle Events",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": "{{memeh_base_url}}/api/v1/payment-requests/{{request_id}}/events",
            "description": "Returns the append-only event history used for support, audit, lifecycle reconstruction, and reconciliation. Fintechs read this endpoint; participating-provider adapters write lifecycle updates to a separate protected Core endpoint."
          },
          "response": [],
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if (!pm.collectionVariables.get(\"request_id\")) {",
                  "  throw new Error(\"request_id is missing. Run Flow 2 - Create Request-to-Pay first.\");",
                  "}"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"Lifecycle endpoint returns HTTP 200\", function () {",
                  "  pm.response.to.have.status(200);",
                  "});",
                  "",
                  "const body = pm.response.json();",
                  "pm.test(\"Lifecycle response contains an event array\", function () {",
                  "  pm.expect(body.events).to.be.an(\"array\");",
                  "});"
                ]
              }
            }
          ]
        }
      ]
    }
  ],
  "variable": [
    {
      "key": "memeh_base_url",
      "value": "http://127.0.0.1:4000",
      "type": "string"
    },
    {
      "key": "memeh_api_key",
      "value": "replace-with-issued-fintech-api-key",
      "type": "string"
    },
    {
      "key": "merchant_id",
      "value": "GOVPAY-SL",
      "type": "string"
    },
    {
      "key": "payer_alias",
      "value": "078657484",
      "type": "string"
    },
    {
      "key": "payee_alias",
      "value": "076000001",
      "type": "string"
    },
    {
      "key": "amount",
      "value": "100.00",
      "type": "string"
    },
    {
      "key": "currency",
      "value": "SLE",
      "type": "string"
    },
    {
      "key": "description",
      "value": "GovPay service fee",
      "type": "string"
    },
    {
      "key": "reference",
      "value": "",
      "type": "string"
    },
    {
      "key": "idempotency_key",
      "value": "",
      "type": "string"
    },
    {
      "key": "resolution_id",
      "value": "",
      "type": "string"
    },
    {
      "key": "payer_finaddress_id",
      "value": "",
      "type": "string"
    },
    {
      "key": "payee_finaddress_id",
      "value": "",
      "type": "string"
    },
    {
      "key": "payer_choice_label",
      "value": "",
      "type": "string"
    },
    {
      "key": "payee_choice_label",
      "value": "",
      "type": "string"
    },
    {
      "key": "request_id",
      "value": "",
      "type": "string"
    }
  ]
}
