{
  "item": [
    {
      "id": "f5089425-c4f0-45c9-8cdd-eb472a5c039c",
      "name": "Subscription",
      "description": {
        "content": "The PIN flow: the general case, works on any connection including Wi-Fi.\nRead Anti-fraud before building this.\n",
        "type": "text/plain"
      },
      "item": [
        {
          "id": "cfa0de70-407b-4d41-b756-9ff4d98f288b",
          "name": "Read whether a number is subscribed",
          "request": {
            "name": "Read whether a number is subscribed",
            "description": {
              "content": "Changes nothing, and the ideal first call when setting up: it exercises your\ntoken, your allowlisted address, your grant and your capability at once.\n\n**Every call names its service**, this one included: one credential can cover\nseveral services on the same short code, so `serviceId` is required here as a\nquery parameter. Omitting it does not fall back to a default, it answers\n`SERVICE_NOT_FOUND`.\n\nDo not poll this to learn about changes: renewals, failed charges and endings\nreach you through DataSync as they happen. This answers \"what is true right now?\"\nfor a support question or a reconciliation.\n",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "dcb",
                "subscription",
                "status"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [
                {
                  "disabled": false,
                  "key": "serviceId",
                  "value": "{{serviceId}}",
                  "description": "(Required) The service being asked about."
                },
                {
                  "disabled": false,
                  "key": "msisdn",
                  "value": "{{msisdn}}",
                  "description": "(Required) The subscriber's number."
                }
              ],
              "variable": [
                {
                  "description": "Supplied by the operator team.",
                  "type": "any",
                  "value": "{{apiHost}}",
                  "key": "apiHost"
                }
              ],
              "raw": "{{baseUrl}}/dcb/subscription/status?serviceId={{serviceId}}&msisdn={{msisdn}}"
            },
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET"
          },
          "response": [
            {
              "id": "a528be41-7e03-4cec-a449-365d241e1920",
              "name": "A success envelope whose `data` carries the subscription's current state.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "status"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [
                    {
                      "key": "serviceId",
                      "value": "4821"
                    },
                    {
                      "key": "msisdn",
                      "value": "9647500000000"
                    }
                  ],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "GET",
                "body": {}
              },
              "status": "OK",
              "code": 200,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"string\",\n  \"data\": {\n    \"msisdn\": \"string\",\n    \"subscribed\": false,\n    \"state\": \"unsubscribed\",\n    \"subscribedAt\": \"2001-12-27T18:59:32.574Z\"\n  }\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "6177eb84-31d5-4bd9-8f38-5ec2a7fab70f",
              "name": "`UNAUTHENTICATED`, `CREDENTIAL_REVOKED`.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "status"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [
                    {
                      "key": "serviceId",
                      "value": "4821"
                    },
                    {
                      "key": "msisdn",
                      "value": "9647500000000"
                    }
                  ],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "GET",
                "body": {}
              },
              "status": "Unauthorized",
              "code": 401,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "c977e323-3889-4a9b-8412-9da32a7d4589",
              "name": "`IP_NOT_ALLOWLISTED`, `ABILITY_NOT_GRANTED`, `SUBSCRIBER_BLACKLISTED`,\n`CONTENT_NOT_ALLOWED_TODAY`, `PURCHASE_CHANNEL_NOT_ENABLED`, `FRAUD_BLOCKED`.\n\nOn `IP_NOT_ALLOWLISTED` **the response tells you the address we saw**: compare it\nwith what you registered.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "status"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [
                    {
                      "key": "serviceId",
                      "value": "4821"
                    },
                    {
                      "key": "msisdn",
                      "value": "9647500000000"
                    }
                  ],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "GET",
                "body": {}
              },
              "status": "Forbidden",
              "code": 403,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "de103b17-61e8-4145-839a-0e954afa80a8",
              "name": "`SERVICE_NOT_FOUND`: no such service, or none you have access to.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "status"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [
                    {
                      "key": "serviceId",
                      "value": "4821"
                    },
                    {
                      "key": "msisdn",
                      "value": "9647500000000"
                    }
                  ],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "GET",
                "body": {}
              },
              "status": "Not Found",
              "code": 404,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "32d90e73-13ac-4d94-8d1b-7de342b0aef3",
              "name": "`VALIDATION_FAILED`, `INVALID_MSISDN`, `SERVICE_NOT_ON_SHORT_CODE`,\n`PIN_NOT_REQUESTED`, `PIN_INVALID`, `PIN_EXPIRED`, `PIN_ATTEMPTS_EXCEEDED`,\n`CONTENT_TOO_LONG`, `FRAUD_TRANSACTION_UNKNOWN`.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "status"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [
                    {
                      "key": "serviceId",
                      "value": "4821"
                    },
                    {
                      "key": "msisdn",
                      "value": "9647500000000"
                    }
                  ],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "GET",
                "body": {}
              },
              "status": "Unprocessable Entity (WebDAV) (RFC 4918)",
              "code": 422,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "b1701fad-975d-4f8d-84c4-d561c2ee1c94",
              "name": "`RATE_LIMITED` and `PIN_RATE_LIMITED` (both retryable), plus the limit ceilings\n`CONTENT_LIMIT_EXCEEDED`, `PURCHASE_DAILY_LIMIT_REACHED`,\n`PURCHASE_AMOUNT_LIMIT_REACHED` and `SHORT_CODE_PART_LIMIT_REACHED`, which are\nceilings on the subscriber or the short code rather than on you.\n\nUse the reset header rather than guessing: it is exact.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "status"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [
                    {
                      "key": "serviceId",
                      "value": "4821"
                    },
                    {
                      "key": "msisdn",
                      "value": "9647500000000"
                    }
                  ],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "GET",
                "body": {}
              },
              "status": "Too Many Requests",
              "code": 429,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "227cc57e-e777-408f-90b4-3db3ce60984c",
              "name": "`INTERNAL_ERROR`, retryable. Retry with backoff and quote the `requestId` if it persists.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "status"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [
                    {
                      "key": "serviceId",
                      "value": "4821"
                    },
                    {
                      "key": "msisdn",
                      "value": "9647500000000"
                    }
                  ],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "GET",
                "body": {}
              },
              "status": "Internal Server Error",
              "code": 500,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            }
          ],
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "eea9389e-21fe-4005-a66f-7db5c63b9b1b",
          "name": "Send a PIN by SMS",
          "request": {
            "name": "Send a PIN by SMS",
            "description": {
              "content": "**Nothing is charged and no subscription exists yet.** This step only establishes\nthat the person holds the number.\n\nNote what is absent: no `ti`/`ts` here. The anti-fraud identifiers go on Verify PIN.\n\nSuccess means the PIN was accepted for sending, not that the subscriber has\nreceived it: delivery is a network event and takes a moment.\n\n`PIN_RATE_LIMITED` is a per-number ceiling, not a per-integration one. It usually\nmeans a subscriber is retrying rather than that you are.\n",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "dcb",
                "subscription",
                "pin"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [
                {
                  "description": "Supplied by the operator team.",
                  "type": "any",
                  "value": "{{apiHost}}",
                  "key": "apiHost"
                }
              ],
              "raw": "{{baseUrl}}/dcb/subscription/pin"
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"msisdn\": \"{{msisdn}}\",\n  \"shortCode\": \"{{shortCode}}\",\n  \"serviceId\": \"{{serviceId}}\",\n  \"spTransactionId\": \"{{spTransactionId}}\",\n  \"language\": \"{{language}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "id": "00d9311b-76a1-4b19-9751-97b04f3c111b",
              "name": "The operation succeeded.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "pin"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"language\": \"en\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"OK\",\n  \"data\": {}\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "6bee8ca7-5359-4e48-97f5-21ab51d493fe",
              "name": "`UNAUTHENTICATED`, `CREDENTIAL_REVOKED`.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "pin"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"language\": \"en\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Unauthorized",
              "code": 401,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "aacae0ba-8a57-4d02-98ef-130861428d70",
              "name": "`IP_NOT_ALLOWLISTED`, `ABILITY_NOT_GRANTED`, `SUBSCRIBER_BLACKLISTED`,\n`CONTENT_NOT_ALLOWED_TODAY`, `PURCHASE_CHANNEL_NOT_ENABLED`, `FRAUD_BLOCKED`.\n\nOn `IP_NOT_ALLOWLISTED` **the response tells you the address we saw**: compare it\nwith what you registered.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "pin"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"language\": \"en\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Forbidden",
              "code": 403,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "66fb4302-96f2-4d8b-8491-3c829906b2f9",
              "name": "`SERVICE_NOT_FOUND`: no such service, or none you have access to.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "pin"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"language\": \"en\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Not Found",
              "code": 404,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "234bc381-573f-44bd-867c-d4712d8cc870",
              "name": "`DUPLICATE_TRANSACTION_ID`, `ALREADY_SUBSCRIBED`, `NOT_SUBSCRIBED`,\n`SERVICE_NOT_ACTIVE`, `PARENT_SUBSCRIPTION_REQUIRED`.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "pin"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"language\": \"en\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Conflict",
              "code": 409,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "79f2cfe1-18e5-4357-bc44-97420e7613aa",
              "name": "`VALIDATION_FAILED`, `INVALID_MSISDN`, `SERVICE_NOT_ON_SHORT_CODE`,\n`PIN_NOT_REQUESTED`, `PIN_INVALID`, `PIN_EXPIRED`, `PIN_ATTEMPTS_EXCEEDED`,\n`CONTENT_TOO_LONG`, `FRAUD_TRANSACTION_UNKNOWN`.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "pin"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"language\": \"en\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Unprocessable Entity (WebDAV) (RFC 4918)",
              "code": 422,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "1444fd12-3f8f-4434-acf5-12b3b54e8c95",
              "name": "`RATE_LIMITED` and `PIN_RATE_LIMITED` (both retryable), plus the limit ceilings\n`CONTENT_LIMIT_EXCEEDED`, `PURCHASE_DAILY_LIMIT_REACHED`,\n`PURCHASE_AMOUNT_LIMIT_REACHED` and `SHORT_CODE_PART_LIMIT_REACHED`, which are\nceilings on the subscriber or the short code rather than on you.\n\nUse the reset header rather than guessing: it is exact.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "pin"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"language\": \"en\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Too Many Requests",
              "code": 429,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "2d2970fe-81f5-4b85-aef3-aa67d8dbee44",
              "name": "`INTERNAL_ERROR`, retryable. Retry with backoff and quote the `requestId` if it persists.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "pin"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"language\": \"en\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Internal Server Error",
              "code": 500,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            }
          ],
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "b122ca1d-dbc1-465e-95da-14ddc4e7ea9e",
          "name": "Check the PIN and open the subscription",
          "request": {
            "name": "Check the PIN and open the subscription",
            "description": {
              "content": "**This is the call that commits.** In order: the PIN is checked, the anti-fraud\nverdict is obtained, the subscription is opened. That ordering is deliberate: a\nwrong PIN costs no fraud check, and no charge happens behind an unverified\ninteraction.\n\n**`ti` must be the one the script call registered.** If this `ti` was never used\nto fetch the anti-fraud script, or you generated a fresh one for this call, you\nget `FRAUD_TRANSACTION_UNKNOWN` on every attempt. It is not a decline and\nretrying will not help.\n\n`FRAUD_CHECK_UNAVAILABLE` consumes nothing: retry with the same\n`spTransactionId` and the same PIN, both are still valid.\n",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "dcb",
                "subscription",
                "verify"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [
                {
                  "description": "Supplied by the operator team.",
                  "type": "any",
                  "value": "{{apiHost}}",
                  "key": "apiHost"
                }
              ],
              "raw": "{{baseUrl}}/dcb/subscription/verify"
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"msisdn\": \"{{msisdn}}\",\n  \"shortCode\": \"{{shortCode}}\",\n  \"serviceId\": \"{{serviceId}}\",\n  \"spTransactionId\": \"{{spTransactionId}}\",\n  \"pin\": \"{{pin}}\",\n  \"ti\": \"{{ti}}\",\n  \"ts\": \"{{ts}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "id": "65816761-bb49-4f1f-a5f8-f13b4b34878a",
              "name": "The operation succeeded.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "verify"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"pin\": \"1234\",\n  \"ti\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"ts\": \"1757500000\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"OK\",\n  \"data\": {}\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "ed082b15-5fca-493b-94cc-65846d8ad396",
              "name": "`UNAUTHENTICATED`, `CREDENTIAL_REVOKED`.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "verify"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"pin\": \"1234\",\n  \"ti\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"ts\": \"1757500000\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Unauthorized",
              "code": 401,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "90997011-4828-4df8-95c9-c7f7e6001d02",
              "name": "`IP_NOT_ALLOWLISTED`, `ABILITY_NOT_GRANTED`, `SUBSCRIBER_BLACKLISTED`,\n`CONTENT_NOT_ALLOWED_TODAY`, `PURCHASE_CHANNEL_NOT_ENABLED`, `FRAUD_BLOCKED`.\n\nOn `IP_NOT_ALLOWLISTED` **the response tells you the address we saw**: compare it\nwith what you registered.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "verify"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"pin\": \"1234\",\n  \"ti\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"ts\": \"1757500000\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Forbidden",
              "code": 403,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "acae87ee-6a50-4d58-86ef-90c690871eb8",
              "name": "`SERVICE_NOT_FOUND`: no such service, or none you have access to.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "verify"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"pin\": \"1234\",\n  \"ti\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"ts\": \"1757500000\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Not Found",
              "code": 404,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "5217a514-b840-40d3-a545-c2930d91dc79",
              "name": "`DUPLICATE_TRANSACTION_ID`, `ALREADY_SUBSCRIBED`, `NOT_SUBSCRIBED`,\n`SERVICE_NOT_ACTIVE`, `PARENT_SUBSCRIPTION_REQUIRED`.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "verify"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"pin\": \"1234\",\n  \"ti\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"ts\": \"1757500000\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Conflict",
              "code": 409,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "9e6da3ac-fc01-43c5-9687-5bfc17d2bcee",
              "name": "`VALIDATION_FAILED`, `INVALID_MSISDN`, `SERVICE_NOT_ON_SHORT_CODE`,\n`PIN_NOT_REQUESTED`, `PIN_INVALID`, `PIN_EXPIRED`, `PIN_ATTEMPTS_EXCEEDED`,\n`CONTENT_TOO_LONG`, `FRAUD_TRANSACTION_UNKNOWN`.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "verify"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"pin\": \"1234\",\n  \"ti\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"ts\": \"1757500000\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Unprocessable Entity (WebDAV) (RFC 4918)",
              "code": 422,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "2de94ae8-49a8-44b1-8dd2-f559ec9a5e6f",
              "name": "`RATE_LIMITED` and `PIN_RATE_LIMITED` (both retryable), plus the limit ceilings\n`CONTENT_LIMIT_EXCEEDED`, `PURCHASE_DAILY_LIMIT_REACHED`,\n`PURCHASE_AMOUNT_LIMIT_REACHED` and `SHORT_CODE_PART_LIMIT_REACHED`, which are\nceilings on the subscriber or the short code rather than on you.\n\nUse the reset header rather than guessing: it is exact.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "verify"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"pin\": \"1234\",\n  \"ti\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"ts\": \"1757500000\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Too Many Requests",
              "code": 429,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "a90902f8-0ca2-4735-9d3e-23f51fe6a661",
              "name": "`INTERNAL_ERROR`, retryable. Retry with backoff and quote the `requestId` if it persists.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "verify"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"pin\": \"1234\",\n  \"ti\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"ts\": \"1757500000\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Internal Server Error",
              "code": 500,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "a5416125-b21f-447b-b678-2c3cc0c11bac",
              "name": "`FRAUD_CHECK_UNAVAILABLE` and `ANTIFRAUD_SCRIPT_UNAVAILABLE`, both retryable.\n**`FRAUD_CHECK_UNAVAILABLE` consumes nothing**: retry with the same\n`spTransactionId` and the same PIN.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "verify"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"pin\": \"1234\",\n  \"ti\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"ts\": \"1757500000\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Service Unavailable",
              "code": 503,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            }
          ],
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "58be4ced-162a-45c6-bbb4-8c9d8c9e2653",
          "name": "End a subscription on the subscriber's behalf",
          "request": {
            "name": "End a subscription on the subscriber's behalf",
            "description": {
              "content": "The subscription ends immediately. **The already-paid period is not refunded or\npro-rated:** this is the same ending a subscriber gets by any other route.\n\nA DataSync event follows, **including to you** if you are the registered\nreceiver. That is not an echo to be filtered out: a third party may also be\nregistered, and your own receiver should treat it like any other event.\n\n`NOT_SUBSCRIBED` means there is no live subscription to end. Ending an\nalready-ended subscription is not an error: sending the same `spTransactionId`\nagain replays the original outcome.\n\nThis is not the subscriber's only way out. They can always stop by messaging the\nshort code directly, and that route is not something you control.\n",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "dcb",
                "subscription",
                "unsubscribe"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [
                {
                  "description": "Supplied by the operator team.",
                  "type": "any",
                  "value": "{{apiHost}}",
                  "key": "apiHost"
                }
              ],
              "raw": "{{baseUrl}}/dcb/subscription/unsubscribe"
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"msisdn\": \"{{msisdn}}\",\n  \"shortCode\": \"{{shortCode}}\",\n  \"serviceId\": \"{{serviceId}}\",\n  \"spTransactionId\": \"{{spTransactionId}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "id": "6391dfcc-41e3-445d-b355-6e75758702f1",
              "name": "The operation succeeded.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "unsubscribe"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"OK\",\n  \"data\": {}\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "32f35977-c7d7-4188-9e21-13a7030f05bb",
              "name": "`UNAUTHENTICATED`, `CREDENTIAL_REVOKED`.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "unsubscribe"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Unauthorized",
              "code": 401,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "6e867b5f-9e00-48c6-b4d1-265d0684d706",
              "name": "`IP_NOT_ALLOWLISTED`, `ABILITY_NOT_GRANTED`, `SUBSCRIBER_BLACKLISTED`,\n`CONTENT_NOT_ALLOWED_TODAY`, `PURCHASE_CHANNEL_NOT_ENABLED`, `FRAUD_BLOCKED`.\n\nOn `IP_NOT_ALLOWLISTED` **the response tells you the address we saw**: compare it\nwith what you registered.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "unsubscribe"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Forbidden",
              "code": 403,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "e678f103-56a6-4b07-aa27-abd2eaaece3e",
              "name": "`SERVICE_NOT_FOUND`: no such service, or none you have access to.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "unsubscribe"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Not Found",
              "code": 404,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "67251737-7430-4e7c-8f9e-af2499aeab9d",
              "name": "`DUPLICATE_TRANSACTION_ID`, `ALREADY_SUBSCRIBED`, `NOT_SUBSCRIBED`,\n`SERVICE_NOT_ACTIVE`, `PARENT_SUBSCRIPTION_REQUIRED`.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "unsubscribe"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Conflict",
              "code": 409,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "2c1f4a1b-230b-48c1-a9a0-9c92e202cb59",
              "name": "`VALIDATION_FAILED`, `INVALID_MSISDN`, `SERVICE_NOT_ON_SHORT_CODE`,\n`PIN_NOT_REQUESTED`, `PIN_INVALID`, `PIN_EXPIRED`, `PIN_ATTEMPTS_EXCEEDED`,\n`CONTENT_TOO_LONG`, `FRAUD_TRANSACTION_UNKNOWN`.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "unsubscribe"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Unprocessable Entity (WebDAV) (RFC 4918)",
              "code": 422,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "e42f8eab-dabb-4fa4-adef-21eb34d0c65b",
              "name": "`RATE_LIMITED` and `PIN_RATE_LIMITED` (both retryable), plus the limit ceilings\n`CONTENT_LIMIT_EXCEEDED`, `PURCHASE_DAILY_LIMIT_REACHED`,\n`PURCHASE_AMOUNT_LIMIT_REACHED` and `SHORT_CODE_PART_LIMIT_REACHED`, which are\nceilings on the subscriber or the short code rather than on you.\n\nUse the reset header rather than guessing: it is exact.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "unsubscribe"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Too Many Requests",
              "code": 429,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "8393b234-99d5-40b7-9529-ce4b322efb31",
              "name": "`INTERNAL_ERROR`, retryable. Retry with backoff and quote the `requestId` if it persists.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "subscription",
                    "unsubscribe"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Internal Server Error",
              "code": 500,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            }
          ],
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        }
      ],
      "event": []
    },
    {
      "id": "83670e79-d0d0-48a1-aa4f-a7255304d59d",
      "name": "One-Time Purchase",
      "description": {
        "content": "A single charge rather than a recurring subscription. Creates nothing ongoing.",
        "type": "text/plain"
      },
      "item": [
        {
          "id": "e05082d2-984f-411a-8566-0e93931d6cb9",
          "name": "Send a one-time code for a single purchase",
          "request": {
            "name": "Send a one-time code for a single purchase",
            "description": {
              "content": "**`amount` is prohibited on this call.** Sending it is a validation failure, not a\nsilent override. The price comes from the service's own configuration, so an\nintegration cannot charge an arbitrary sum whatever happens to its own code.\n\n**Eligibility is checked here, before any message is sent.** If the purchase\ncannot complete you find out now, and the subscriber is never sent a code for\nsomething that was always going to fail. So `PARENT_SUBSCRIPTION_REQUIRED`,\n`PURCHASE_DAILY_LIMIT_REACHED`, `PURCHASE_AMOUNT_LIMIT_REACHED` and\n`PURCHASE_CHANNEL_NOT_ENABLED` can all return at this step with no SMS spent.\n\nEligibility is checked **again** at Verify. The two are additive, not\nalternatives, so do not treat passing here as a guarantee.\n",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "dcb",
                "purchase",
                "otp"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [
                {
                  "description": "Supplied by the operator team.",
                  "type": "any",
                  "value": "{{apiHost}}",
                  "key": "apiHost"
                }
              ],
              "raw": "{{baseUrl}}/dcb/purchase/otp"
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"msisdn\": \"{{msisdn}}\",\n  \"shortCode\": \"{{shortCode}}\",\n  \"serviceId\": \"{{serviceId}}\",\n  \"spTransactionId\": \"{{spTransactionId}}\",\n  \"language\": \"{{language}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "id": "c1a40d64-0272-452f-b1bd-8d9773389770",
              "name": "The operation succeeded.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "purchase",
                    "otp"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"language\": \"en\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"OK\",\n  \"data\": {}\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "520e6b9f-45fc-4725-b835-94fe31da0ca6",
              "name": "`UNAUTHENTICATED`, `CREDENTIAL_REVOKED`.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "purchase",
                    "otp"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"language\": \"en\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Unauthorized",
              "code": 401,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "43790624-abf8-4c2e-8d0d-0dc322176a6a",
              "name": "`CHARGE_FAILED`, `INSUFFICIENT_BALANCE`: the operator declined the charge itself.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "purchase",
                    "otp"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"language\": \"en\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Payment Required",
              "code": 402,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "9cebe36a-0eed-4f1a-aadc-2258da852be0",
              "name": "`IP_NOT_ALLOWLISTED`, `ABILITY_NOT_GRANTED`, `SUBSCRIBER_BLACKLISTED`,\n`CONTENT_NOT_ALLOWED_TODAY`, `PURCHASE_CHANNEL_NOT_ENABLED`, `FRAUD_BLOCKED`.\n\nOn `IP_NOT_ALLOWLISTED` **the response tells you the address we saw**: compare it\nwith what you registered.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "purchase",
                    "otp"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"language\": \"en\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Forbidden",
              "code": 403,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "274f458d-2772-4a0b-9276-bbd5c68628f4",
              "name": "`SERVICE_NOT_FOUND`: no such service, or none you have access to.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "purchase",
                    "otp"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"language\": \"en\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Not Found",
              "code": 404,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "d167a9ca-e2a8-48c4-a73b-9fb7a67caa21",
              "name": "`DUPLICATE_TRANSACTION_ID`, `ALREADY_SUBSCRIBED`, `NOT_SUBSCRIBED`,\n`SERVICE_NOT_ACTIVE`, `PARENT_SUBSCRIPTION_REQUIRED`.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "purchase",
                    "otp"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"language\": \"en\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Conflict",
              "code": 409,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "21ec25ea-fc15-48e8-8c57-006dec6e0173",
              "name": "`VALIDATION_FAILED`, `INVALID_MSISDN`, `SERVICE_NOT_ON_SHORT_CODE`,\n`PIN_NOT_REQUESTED`, `PIN_INVALID`, `PIN_EXPIRED`, `PIN_ATTEMPTS_EXCEEDED`,\n`CONTENT_TOO_LONG`, `FRAUD_TRANSACTION_UNKNOWN`.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "purchase",
                    "otp"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"language\": \"en\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Unprocessable Entity (WebDAV) (RFC 4918)",
              "code": 422,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "57b4fc53-ff29-43a5-a72f-24d52d20205c",
              "name": "`RATE_LIMITED` and `PIN_RATE_LIMITED` (both retryable), plus the limit ceilings\n`CONTENT_LIMIT_EXCEEDED`, `PURCHASE_DAILY_LIMIT_REACHED`,\n`PURCHASE_AMOUNT_LIMIT_REACHED` and `SHORT_CODE_PART_LIMIT_REACHED`, which are\nceilings on the subscriber or the short code rather than on you.\n\nUse the reset header rather than guessing: it is exact.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "purchase",
                    "otp"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"language\": \"en\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Too Many Requests",
              "code": 429,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "7437a72a-f2e3-4942-9994-e3203864d5a7",
              "name": "`INTERNAL_ERROR`, retryable. Retry with backoff and quote the `requestId` if it persists.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "purchase",
                    "otp"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"language\": \"en\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Internal Server Error",
              "code": 500,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            }
          ],
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "906a170e-9bc9-4a5f-b809-eaae3aa8e6d9",
          "name": "Check the code and charge once",
          "request": {
            "name": "Check the code and charge once",
            "description": {
              "content": "In order: the code is checked, eligibility is re-checked, the anti-fraud verdict\nis obtained, the charge is made. **Nothing is charged until all three checks\npass**, which is why a refusal at any step leaves the subscriber's balance\nuntouched.\n\n**`amount` is prohibited here too.** The price is the service's, not the request's.\n\nA purchase is a single charge. No subscription is created, nothing renews, and\nthere is nothing to unsubscribe from afterwards.\n\n`INSUFFICIENT_BALANCE` is worth handling distinctly in your UI: it is the one\nrefusal the subscriber can do something about immediately.\n",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "dcb",
                "purchase",
                "verify"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [
                {
                  "description": "Supplied by the operator team.",
                  "type": "any",
                  "value": "{{apiHost}}",
                  "key": "apiHost"
                }
              ],
              "raw": "{{baseUrl}}/dcb/purchase/verify"
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"msisdn\": \"{{msisdn}}\",\n  \"shortCode\": \"{{shortCode}}\",\n  \"serviceId\": \"{{serviceId}}\",\n  \"spTransactionId\": \"{{spTransactionId}}\",\n  \"pin\": \"{{pin}}\",\n  \"ti\": \"{{ti}}\",\n  \"ts\": \"{{ts}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "id": "9e90bc71-5510-4b4b-92ab-7164d7d1d895",
              "name": "The operation succeeded.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "purchase",
                    "verify"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"pin\": \"1234\",\n  \"ti\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"ts\": \"1757500000\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"OK\",\n  \"data\": {}\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "330fad4c-eb75-4a23-9bce-055792ea938b",
              "name": "`UNAUTHENTICATED`, `CREDENTIAL_REVOKED`.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "purchase",
                    "verify"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"pin\": \"1234\",\n  \"ti\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"ts\": \"1757500000\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Unauthorized",
              "code": 401,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "d4b3c4d4-7ce2-43c9-93ba-3d79490ecba8",
              "name": "`CHARGE_FAILED`, `INSUFFICIENT_BALANCE`: the operator declined the charge itself.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "purchase",
                    "verify"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"pin\": \"1234\",\n  \"ti\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"ts\": \"1757500000\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Payment Required",
              "code": 402,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "42ae21d2-6224-4504-b4d7-b5df30301677",
              "name": "`IP_NOT_ALLOWLISTED`, `ABILITY_NOT_GRANTED`, `SUBSCRIBER_BLACKLISTED`,\n`CONTENT_NOT_ALLOWED_TODAY`, `PURCHASE_CHANNEL_NOT_ENABLED`, `FRAUD_BLOCKED`.\n\nOn `IP_NOT_ALLOWLISTED` **the response tells you the address we saw**: compare it\nwith what you registered.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "purchase",
                    "verify"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"pin\": \"1234\",\n  \"ti\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"ts\": \"1757500000\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Forbidden",
              "code": 403,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "3a8e9202-fe21-46dc-a1d1-55f24cd18230",
              "name": "`SERVICE_NOT_FOUND`: no such service, or none you have access to.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "purchase",
                    "verify"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"pin\": \"1234\",\n  \"ti\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"ts\": \"1757500000\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Not Found",
              "code": 404,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "bf6428bb-4ea1-4ea7-97c2-552e5f83fdce",
              "name": "`DUPLICATE_TRANSACTION_ID`, `ALREADY_SUBSCRIBED`, `NOT_SUBSCRIBED`,\n`SERVICE_NOT_ACTIVE`, `PARENT_SUBSCRIPTION_REQUIRED`.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "purchase",
                    "verify"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"pin\": \"1234\",\n  \"ti\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"ts\": \"1757500000\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Conflict",
              "code": 409,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "dde30564-7800-4dde-a713-9ef9f325c535",
              "name": "`VALIDATION_FAILED`, `INVALID_MSISDN`, `SERVICE_NOT_ON_SHORT_CODE`,\n`PIN_NOT_REQUESTED`, `PIN_INVALID`, `PIN_EXPIRED`, `PIN_ATTEMPTS_EXCEEDED`,\n`CONTENT_TOO_LONG`, `FRAUD_TRANSACTION_UNKNOWN`.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "purchase",
                    "verify"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"pin\": \"1234\",\n  \"ti\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"ts\": \"1757500000\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Unprocessable Entity (WebDAV) (RFC 4918)",
              "code": 422,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "6f0edb1b-fb98-4f27-8d98-ea94d4ae4dcd",
              "name": "`RATE_LIMITED` and `PIN_RATE_LIMITED` (both retryable), plus the limit ceilings\n`CONTENT_LIMIT_EXCEEDED`, `PURCHASE_DAILY_LIMIT_REACHED`,\n`PURCHASE_AMOUNT_LIMIT_REACHED` and `SHORT_CODE_PART_LIMIT_REACHED`, which are\nceilings on the subscriber or the short code rather than on you.\n\nUse the reset header rather than guessing: it is exact.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "purchase",
                    "verify"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"pin\": \"1234\",\n  \"ti\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"ts\": \"1757500000\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Too Many Requests",
              "code": 429,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "1b113e01-0896-4911-b292-a85a8101dfe3",
              "name": "`INTERNAL_ERROR`, retryable. Retry with backoff and quote the `requestId` if it persists.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "purchase",
                    "verify"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"pin\": \"1234\",\n  \"ti\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"ts\": \"1757500000\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Internal Server Error",
              "code": 500,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "6c6edb71-1310-4f15-ad7f-e1e5605c0d8f",
              "name": "`FRAUD_CHECK_UNAVAILABLE` and `ANTIFRAUD_SCRIPT_UNAVAILABLE`, both retryable.\n**`FRAUD_CHECK_UNAVAILABLE` consumes nothing**: retry with the same\n`spTransactionId` and the same PIN.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "purchase",
                    "verify"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"shortCode\": \"1234\",\n  \"serviceId\": 4821,\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"pin\": \"1234\",\n  \"ti\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"ts\": \"1757500000\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Service Unavailable",
              "code": 503,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            }
          ],
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        }
      ],
      "event": []
    },
    {
      "id": "d6985bca-1f16-4705-a5f0-9490dadef107",
      "name": "Send SMS",
      "description": {
        "content": "One message to one subscriber of your service.",
        "type": "text/plain"
      },
      "item": [
        {
          "id": "2ed8b6d3-c73e-44aa-8c59-d15a7aa45945",
          "name": "Send one message to one subscriber of your service",
          "request": {
            "name": "Send one message to one subscriber of your service",
            "description": {
              "content": "**`msg` and `alphanumeric` are prohibited**, and refused rather than ignored. On\nthe legacy platform `msg` carried hex-encoded text and `alphanumeric` set a sender\nID. Accepting them silently would mean either double-encoding your message or\nquietly ignoring a sender you asked for. The sender is derived from the service's\nshort code and is not something a request can set, which is also why no\n`shortCode` is sent here.\n\n**Messages are not split.** A message longer than the service permits returns\n`CONTENT_TOO_LONG` rather than arriving in pieces. The limit is a single message\npart: 70 characters for Arabic or Kurdish, 160 for English. Multi-part sending is\nnot implemented yet, and refusing is deliberate: a message split across parts\ncannot currently be tracked or reconciled correctly.\n\nThree separate budgets can refuse a send: the subscriber's daily content\nallowance (`CONTENT_LIMIT_EXCEEDED`), the short code's own budget\n(`SHORT_CODE_PART_LIMIT_REACHED`), and the service's allowed days\n(`CONTENT_NOT_ALLOWED_TODAY`).\n",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "dcb",
                "sms"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [
                {
                  "description": "Supplied by the operator team.",
                  "type": "any",
                  "value": "{{apiHost}}",
                  "key": "apiHost"
                }
              ],
              "raw": "{{baseUrl}}/dcb/sms"
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"msisdn\": \"{{msisdn}}\",\n  \"serviceId\": \"{{serviceId}}\",\n  \"message\": \"{{message}}\",\n  \"spTransactionId\": \"{{spTransactionId}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "id": "a8949510-abbb-4706-b556-d17d0af1920e",
              "name": "The operation succeeded.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "sms"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"serviceId\": 4821,\n  \"message\": \"Your subscription is active. Reply STOP to cancel.\",\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"OK\",\n  \"data\": {}\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "d78fb08c-804f-4522-b123-571a9cab82f8",
              "name": "`UNAUTHENTICATED`, `CREDENTIAL_REVOKED`.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "sms"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"serviceId\": 4821,\n  \"message\": \"Your subscription is active. Reply STOP to cancel.\",\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Unauthorized",
              "code": 401,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "8eb08bcf-29a7-4bac-8302-5ade09b9df2a",
              "name": "`IP_NOT_ALLOWLISTED`, `ABILITY_NOT_GRANTED`, `SUBSCRIBER_BLACKLISTED`,\n`CONTENT_NOT_ALLOWED_TODAY`, `PURCHASE_CHANNEL_NOT_ENABLED`, `FRAUD_BLOCKED`.\n\nOn `IP_NOT_ALLOWLISTED` **the response tells you the address we saw**: compare it\nwith what you registered.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "sms"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"serviceId\": 4821,\n  \"message\": \"Your subscription is active. Reply STOP to cancel.\",\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Forbidden",
              "code": 403,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "5365f098-1ad5-41b9-92b5-dd93149a8639",
              "name": "`SERVICE_NOT_FOUND`: no such service, or none you have access to.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "sms"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"serviceId\": 4821,\n  \"message\": \"Your subscription is active. Reply STOP to cancel.\",\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Not Found",
              "code": 404,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "4e6eb4e6-0780-4442-a6d7-0bf37074dea5",
              "name": "`DUPLICATE_TRANSACTION_ID`, `ALREADY_SUBSCRIBED`, `NOT_SUBSCRIBED`,\n`SERVICE_NOT_ACTIVE`, `PARENT_SUBSCRIPTION_REQUIRED`.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "sms"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"serviceId\": 4821,\n  \"message\": \"Your subscription is active. Reply STOP to cancel.\",\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Conflict",
              "code": 409,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "5cca8598-77d3-4b74-913e-e714dfaacabc",
              "name": "`VALIDATION_FAILED`, `INVALID_MSISDN`, `SERVICE_NOT_ON_SHORT_CODE`,\n`PIN_NOT_REQUESTED`, `PIN_INVALID`, `PIN_EXPIRED`, `PIN_ATTEMPTS_EXCEEDED`,\n`CONTENT_TOO_LONG`, `FRAUD_TRANSACTION_UNKNOWN`.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "sms"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"serviceId\": 4821,\n  \"message\": \"Your subscription is active. Reply STOP to cancel.\",\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Unprocessable Entity (WebDAV) (RFC 4918)",
              "code": 422,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "dc1bf85d-769d-4dab-b45a-4e81ca562aa9",
              "name": "`RATE_LIMITED` and `PIN_RATE_LIMITED` (both retryable), plus the limit ceilings\n`CONTENT_LIMIT_EXCEEDED`, `PURCHASE_DAILY_LIMIT_REACHED`,\n`PURCHASE_AMOUNT_LIMIT_REACHED` and `SHORT_CODE_PART_LIMIT_REACHED`, which are\nceilings on the subscriber or the short code rather than on you.\n\nUse the reset header rather than guessing: it is exact.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "sms"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"serviceId\": 4821,\n  \"message\": \"Your subscription is active. Reply STOP to cancel.\",\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Too Many Requests",
              "code": 429,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "ded7f80a-8f45-45cc-a113-6ff8f35b786b",
              "name": "`INTERNAL_ERROR`, retryable. Retry with backoff and quote the `requestId` if it persists.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "sms"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "POST",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"msisdn\": \"9647500000000\",\n  \"serviceId\": 4821,\n  \"message\": \"Your subscription is active. Reply STOP to cancel.\",\n  \"spTransactionId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Internal Server Error",
              "code": 500,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            }
          ],
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        }
      ],
      "event": []
    },
    {
      "id": "cbdcf693-2a00-4176-9d22-eed5b41e55d4",
      "name": "Anti-fraud",
      "description": {
        "content": "Mandatory, and it starts on your page. Fetch the script from your BACKEND, never\nfrom the browser: this endpoint looks like a front-end concern because its output\nis a script, and calling it from the page publishes your API token to every visitor.\n",
        "type": "text/plain"
      },
      "item": [
        {
          "id": "be61e1c2-260f-47f5-a4bd-307145d3c24c",
          "name": "Fetch the protection script for your page",
          "request": {
            "name": "Fetch the protection script for your page",
            "description": {
              "content": "**Call this from your backend, never from the browser.** If your web page calls\nthis endpoint directly, your API token is published to every visitor. It looks\nlike a front-end concern because its output is a script. It is not.\n\nYour server calls us, we fetch the protection script using the platform's own\nanti-fraud account, and we return it for you to embed. You never hold anti-fraud\ncredentials and never register with the provider.\n\nEmbed it in `<head>`, ahead of anything else, and load it **exactly once per\npage**. Loading it twice does not double the protection: it produces a page whose\nbehaviour cannot be interpreted.\n\nThe `ti` and `ts` you generate here must be the ones you send on verification.\n",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "dcb",
                "antifraud",
                "script"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [
                {
                  "disabled": false,
                  "key": "shortCode",
                  "value": "{{shortCode}}",
                  "description": "(Required) "
                },
                {
                  "disabled": false,
                  "key": "serviceId",
                  "value": "{{serviceId}}",
                  "description": "(Required) "
                },
                {
                  "disabled": false,
                  "key": "ti",
                  "value": "{{ti}}",
                  "description": "(Required) "
                },
                {
                  "disabled": false,
                  "key": "ts",
                  "value": "{{ts}}",
                  "description": "(Required) "
                },
                {
                  "disabled": false,
                  "key": "te",
                  "value": "{{te}}",
                  "description": "(Required) The CSS selector of the element the subscriber actually clicks: your submit\nbutton, or the form containing it.\n\n**The anti-fraud provider's own documentation lists `te` as optional. That is\ntrue only of a different integration style, which this platform does not\nuse.** Here it is mandatory: it is how the interaction is observed at all.\n\nOn a single page updated in place, target the **confirmation** button, the\nsecond click rather than the first. On a two-page flow, put the script on the\n**code** page and target the **form** wrapping the input and its submit button.\n\n**Pass the RAW selector if your HTTP client encodes query parameters for you**, which\nmost do. `te` travels in a query string, so a `#` has to reach us as `%23` - but\nhanding a client the already-encoded `%23confirm-button` sends `%2523`, and we then\nreceive those nine literal characters as the selector. It matches nothing, the call\nstill succeeds, and verification fails several steps later for an unrelated-looking\nreason.\n\nPre-encode only when you assemble the URL as a string yourself, or when your tool\nsubstitutes variables literally rather than encoding them.\n"
                },
                {
                  "disabled": false,
                  "key": "flow",
                  "value": "{{flow}}",
                  "description": "(Required) Which journey is being scored: `lp` for the PIN flow, `he` for header\nenrichment. The two are not interchangeable and the value is passed to the\nprovider, so a wrong one scores the wrong journey.\n"
                }
              ],
              "variable": [
                {
                  "description": "Supplied by the operator team.",
                  "type": "any",
                  "value": "{{apiHost}}",
                  "key": "apiHost"
                }
              ],
              "raw": "{{baseUrl}}/dcb/antifraud/script?shortCode={{shortCode}}&serviceId={{serviceId}}&ti={{ti}}&ts={{ts}}&te={{te}}&flow={{flow}}"
            },
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET"
          },
          "response": [
            {
              "id": "bde9e3f3-becb-4345-884a-1ace571583b0",
              "name": "The standard success envelope, with the script in `data.script`.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "antifraud",
                    "script"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [
                    {
                      "key": "shortCode",
                      "value": "1234"
                    },
                    {
                      "key": "serviceId",
                      "value": "4821"
                    },
                    {
                      "key": "ti",
                      "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                    },
                    {
                      "key": "ts",
                      "value": "1757500000"
                    },
                    {
                      "key": "te",
                      "value": "#confirm-button"
                    },
                    {
                      "key": "flow",
                      "value": "lp"
                    }
                  ],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "GET",
                "body": {}
              },
              "status": "OK",
              "code": 200,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"OK\",\n  \"data\": {\n    \"script\": \"<script>/* provider script body */</script>\"\n  }\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "13539959-d6d1-4948-a6e8-bdd55e42d3f8",
              "name": "`UNAUTHENTICATED`, `CREDENTIAL_REVOKED`.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "antifraud",
                    "script"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [
                    {
                      "key": "shortCode",
                      "value": "1234"
                    },
                    {
                      "key": "serviceId",
                      "value": "4821"
                    },
                    {
                      "key": "ti",
                      "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                    },
                    {
                      "key": "ts",
                      "value": "1757500000"
                    },
                    {
                      "key": "te",
                      "value": "#confirm-button"
                    },
                    {
                      "key": "flow",
                      "value": "lp"
                    }
                  ],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "GET",
                "body": {}
              },
              "status": "Unauthorized",
              "code": 401,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "9706be03-3033-4207-b6ae-0d49f2e35a46",
              "name": "`IP_NOT_ALLOWLISTED`, `ABILITY_NOT_GRANTED`, `SUBSCRIBER_BLACKLISTED`,\n`CONTENT_NOT_ALLOWED_TODAY`, `PURCHASE_CHANNEL_NOT_ENABLED`, `FRAUD_BLOCKED`.\n\nOn `IP_NOT_ALLOWLISTED` **the response tells you the address we saw**: compare it\nwith what you registered.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "antifraud",
                    "script"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [
                    {
                      "key": "shortCode",
                      "value": "1234"
                    },
                    {
                      "key": "serviceId",
                      "value": "4821"
                    },
                    {
                      "key": "ti",
                      "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                    },
                    {
                      "key": "ts",
                      "value": "1757500000"
                    },
                    {
                      "key": "te",
                      "value": "#confirm-button"
                    },
                    {
                      "key": "flow",
                      "value": "lp"
                    }
                  ],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "GET",
                "body": {}
              },
              "status": "Forbidden",
              "code": 403,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "05856564-fc69-42af-8da0-7c6c3725d30b",
              "name": "`VALIDATION_FAILED`, `INVALID_MSISDN`, `SERVICE_NOT_ON_SHORT_CODE`,\n`PIN_NOT_REQUESTED`, `PIN_INVALID`, `PIN_EXPIRED`, `PIN_ATTEMPTS_EXCEEDED`,\n`CONTENT_TOO_LONG`, `FRAUD_TRANSACTION_UNKNOWN`.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "antifraud",
                    "script"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [
                    {
                      "key": "shortCode",
                      "value": "1234"
                    },
                    {
                      "key": "serviceId",
                      "value": "4821"
                    },
                    {
                      "key": "ti",
                      "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                    },
                    {
                      "key": "ts",
                      "value": "1757500000"
                    },
                    {
                      "key": "te",
                      "value": "#confirm-button"
                    },
                    {
                      "key": "flow",
                      "value": "lp"
                    }
                  ],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "GET",
                "body": {}
              },
              "status": "Unprocessable Entity (WebDAV) (RFC 4918)",
              "code": 422,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "0907c641-bd12-4d69-a488-b214ee32b91b",
              "name": "`RATE_LIMITED` and `PIN_RATE_LIMITED` (both retryable), plus the limit ceilings\n`CONTENT_LIMIT_EXCEEDED`, `PURCHASE_DAILY_LIMIT_REACHED`,\n`PURCHASE_AMOUNT_LIMIT_REACHED` and `SHORT_CODE_PART_LIMIT_REACHED`, which are\nceilings on the subscriber or the short code rather than on you.\n\nUse the reset header rather than guessing: it is exact.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "antifraud",
                    "script"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [
                    {
                      "key": "shortCode",
                      "value": "1234"
                    },
                    {
                      "key": "serviceId",
                      "value": "4821"
                    },
                    {
                      "key": "ti",
                      "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                    },
                    {
                      "key": "ts",
                      "value": "1757500000"
                    },
                    {
                      "key": "te",
                      "value": "#confirm-button"
                    },
                    {
                      "key": "flow",
                      "value": "lp"
                    }
                  ],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "GET",
                "body": {}
              },
              "status": "Too Many Requests",
              "code": 429,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "ed364ae7-71b1-431f-afd9-51e9b0e329b6",
              "name": "`INTERNAL_ERROR`, retryable. Retry with backoff and quote the `requestId` if it persists.",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "antifraud",
                    "script"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [
                    {
                      "key": "shortCode",
                      "value": "1234"
                    },
                    {
                      "key": "serviceId",
                      "value": "4821"
                    },
                    {
                      "key": "ti",
                      "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                    },
                    {
                      "key": "ts",
                      "value": "1757500000"
                    },
                    {
                      "key": "te",
                      "value": "#confirm-button"
                    },
                    {
                      "key": "flow",
                      "value": "lp"
                    }
                  ],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "GET",
                "body": {}
              },
              "status": "Internal Server Error",
              "code": 500,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            },
            {
              "id": "ae1876ad-cf0a-4d23-a064-1e77b092c7d1",
              "name": "`FRAUD_CHECK_UNAVAILABLE` and `ANTIFRAUD_SCRIPT_UNAVAILABLE`, both retryable.\n**`FRAUD_CHECK_UNAVAILABLE` consumes nothing**: retry with the same\n`spTransactionId` and the same PIN.\n",
              "originalRequest": {
                "url": {
                  "path": [
                    "dcb",
                    "antifraud",
                    "script"
                  ],
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "query": [
                    {
                      "key": "shortCode",
                      "value": "1234"
                    },
                    {
                      "key": "serviceId",
                      "value": "4821"
                    },
                    {
                      "key": "ti",
                      "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                    },
                    {
                      "key": "ts",
                      "value": "1757500000"
                    },
                    {
                      "key": "te",
                      "value": "#confirm-button"
                    },
                    {
                      "key": "flow",
                      "value": "lp"
                    }
                  ],
                  "variable": [
                    {
                      "description": "Supplied by the operator team.",
                      "type": "any",
                      "value": "{{apiHost}}",
                      "key": "apiHost"
                    }
                  ]
                },
                "header": [
                  {
                    "key": "Accept",
                    "value": "application/json"
                  }
                ],
                "method": "GET",
                "body": {}
              },
              "status": "Service Unavailable",
              "code": 503,
              "header": [
                {
                  "disabled": false,
                  "description": "Unique to this call, and also present as `requestId` in the body. **Keep it.** It\nresolves to a specific row in our logs, so quoting it in a support request is the\ndifference between finding your call in seconds and asking you twenty questions.\n",
                  "key": "X-Request-Id",
                  "value": "01JB2K9WQ4X7YH3M8N5P6R7T8V"
                },
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"requestId\": \"01JB2K9WQ4X7YH3M8N5P6R7T8V\",\n  \"code\": \"PIN_EXPIRED\",\n  \"message\": \"The PIN has expired. Request a new one.\",\n  \"retryable\": false\n}",
              "cookie": [],
              "_postman_previewlanguage": "json"
            }
          ],
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        }
      ],
      "event": []
    }
  ],
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "type": "text/javascript",
        "exec": [
          "const ENC = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; // Crockford base32",
          "",
          "function ulid() {",
          "  let t = Date.now();",
          "  let time = '';",
          "  for (let i = 9; i >= 0; i--) { time = ENC[t % 32] + time; t = Math.floor(t / 32); }",
          "  let rand = '';",
          "  for (let i = 0; i < 16; i++) rand += ENC[Math.floor(Math.random() * 32)];",
          "  return time + rand;",
          "}",
          "",
          "const replay = String(pm.environment.get('replayLastTransactionId') || '').toLowerCase() === 'true';",
          "",
          "if (replay) {",
          "  const last = pm.environment.get('lastSpTransactionId');",
          "  if (last) {",
          "    pm.environment.set('spTransactionId', last);",
          "    console.log('Replaying spTransactionId ' + last + ' — expect the stored outcome, not a second operation.');",
          "  } else {",
          "    console.warn('replayLastTransactionId is true but nothing has been sent yet, so there is no id to replay.');",
          "  }",
          "} else {",
          "  const id = ulid();",
          "  pm.environment.set('spTransactionId', id);",
          "  pm.environment.set('lastSpTransactionId', id);",
          "}",
          "",
          "if (!pm.environment.get('apiHost') || String(pm.environment.get('apiHost')).indexOf('invalid') !== -1) {",
          "  console.warn('apiHost is not set. Ask the operator team for your host: no host is published in the docs.');",
          "}",
          "if (!pm.environment.get('token')) {",
          "  console.warn('token is empty. Every call needs Authorization: Bearer <token>.');",
          "}"
        ]
      }
    },
    {
      "listen": "test",
      "script": {
        "type": "text/javascript",
        "exec": [
          "pm.test('X-Request-Id header is present', function () {",
          "  pm.response.to.have.header('X-Request-Id');",
          "});",
          "",
          "const contentType = pm.response.headers.get('Content-Type') || '';",
          "",
          "if (contentType.indexOf('json') === -1) {",
          "  // Anti-fraud script success: the body is the script, not an envelope.",
          "  console.log('Non-JSON response (' + contentType + '), skipping envelope checks.');",
          "} else {",
          "  const body = pm.response.json();",
          "",
          "  console.log('code = ' + body.code + '   requestId = ' + body.requestId);",
          "",
          "  pm.test('Envelope carries requestId and code', function () {",
          "    pm.expect(body).to.have.property('requestId');",
          "    pm.expect(body).to.have.property('code');",
          "  });",
          "",
          "  if (pm.response.code >= 200 && pm.response.code < 300) {",
          "    pm.test('A 2xx means the operation succeeded, so code is OK', function () {",
          "      pm.expect(body.code).to.eql('OK');",
          "    });",
          "  } else {",
          "    pm.test('Failure envelope carries message and retryable', function () {",
          "      pm.expect(body).to.have.property('message');",
          "      pm.expect(body).to.have.property('retryable');",
          "    });",
          "",
          "    if (body.retryable === false) {",
          "      console.log('retryable = false: retrying this identical request will fail identically. The fix is upstream of the call.');",
          "    }",
          "",
          "    if (body.code === 'IP_NOT_ALLOWLISTED') {",
          "      console.warn('IP_NOT_ALLOWLISTED. Postman is calling from an address that is not registered. This is the usual reason the collection fails from a laptop: compare the address in the response with what you registered.');",
          "    }",
          "    if (body.code === 'DUPLICATE_TRANSACTION_ID') {",
          "      console.warn('DUPLICATE_TRANSACTION_ID. This spTransactionId was already used for a DIFFERENT request. The pre-request script normally generates a fresh one; check whether replayLastTransactionId is set to true.');",
          "    }",
          "    if (body.code === 'FRAUD_TRANSACTION_UNKNOWN') {",
          "      console.warn('FRAUD_TRANSACTION_UNKNOWN. This is NOT a fraud decline: the ti was never registered by a script call, so retrying will not help. Fetch the anti-fraud script with this exact ti first.');",
          "    }",
          "  }",
          "}"
        ]
      }
    }
  ],
  "variable": [
    {
      "key": "baseUrl",
      "value": "{{baseUrl}}",
      "type": "string"
    }
  ],
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{token}}",
        "type": "string"
      }
    ]
  },
  "info": {
    "_postman_id": "4f016378-d574-4ea1-9cca-2c96c8daec2a",
    "name": "Tornet SDP v1",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
    "description": "# Tornet SDP v1 — SP API\n\n**Spec 1.0.0 · build `8656f7d6`.** Quote that build id in a support request: it is\nhow we tell which copy of this collection you are holding. It changes when the requests change and\nat no other time, so two downloads with the same id are the same collection.\n\nGenerated from `api/openapi.yaml`. **Do not edit this collection by hand:** regenerate it with\n`npm run build:postman` in the developer-docs repository, or your changes are lost on the next build.\n\n## Read this before you press Send\n\n**Requests are refused by source address before your credential is even considered.** If you run\nthis collection from a laptop you will almost certainly get `IP_NOT_ALLOWLISTED`, and that is not\na sign your token is wrong. Run it from a server whose public address the operator team has\nregistered, or ask them to register the address you are testing from.\n\n**There is no self-service sandbox.** Credentials, allowlisted addresses and a service grant are\nall arranged with the operator team. For end-to-end testing they can point a test short code at\nyour receiver and drive a real opt-in on a test service.\n\n**Anti-fraud is mandatory and it starts on your page.** A flow whose page never loaded the\nprotection script is refused at the final step, with a refusal that looks like a fraud decline.\nFetch the script from your backend, never from the browser: calling that endpoint from a page\npublishes your API token to every visitor.\n\n## How to set it up\n\n1. Import both files: the collection and the environment.\n2. Select the **Tornet SDP v1** environment.\n3. Fill in `apiHost`, `token`, `shortCode` and `serviceId`. The token is stored as a secret\n   variable and is empty in the shipped file.\n4. Start with **Read whether a number is subscribed**. It changes nothing and exercises your token,\n   your allowlisted address, your grant and your capability in one call. If it succeeds, your\n   integration is authorised.\n\n## What the scripts do for you\n\n`spTransactionId` is **generated fresh on every send**. The API requires it to be unique per\nattempt, so a static value would return `DUPLICATE_TRANSACTION_ID` on your second click.\n\nTo exercise idempotent replay deliberately, set `replayLastTransactionId` to `true`. The next\nsend reuses the previous id, and you should get the stored outcome back rather than a second\noperation. Set it back to `false` afterwards.\n\nEvery response is checked against the envelope, and `code` and `requestId` are logged first.\n**Keep the `requestId`**: it resolves to a specific row in the platform's logs, and quoting it in\na support request is the difference between your call being found in seconds and twenty questions.\n\n## What is deliberately not here\n\n**Header enrichment** (`GET /he/v1/subscribe`) is a browser redirect, not a server-to-server call.\nSending it from Postman proves nothing.\n\n**DataSync** is delivered *to* you. There is no request to make: you stand up a receiver, verify\nthe signature over the raw body before parsing, and acknowledge with any `2xx`.\n\nBoth are covered in the documentation.",
    "version": "1.0.0+8656f7d6"
  }
}
