{
  "info": {
    "name": "InlineShield API",
    "description": "The InlineShield API screens sign-ups for bonus abuse, fake accounts and bots, and gives one of three verdicts: ALLOWED, QUARANTINED (hold for review) or BLOCKED.\n\nThere are two ways to integrate:\n\n- **Server only:** your backend calls `POST /api/v1/verify` with the player's email, IP and User-Agent.\n- **Browser script and backend:** `inlineshield.js` on your sign-up page calls `POST /api/v1/check` with your site key and gets a single-use token; your backend sends that token to `POST /api/v1/siteverify` with its secret key and gets the decision.\n\nA held sign-up (`action: \"hold\"`) carries a `reviewId`. Poll `GET /api/v1/reviews/{reviewId}` or wait for the `signup.approved` / `signup.rejected` webhook. Report real outcomes with `POST /api/v1/feedback`.\n\n## Authentication\n\n- **Secret API key** (`bs_live_…` live, `bs_test_…` test), sent in the `X-Api-Key` header, for `/verify`, `/siteverify`, `/feedback` and `/reviews/{reviewId}`. Keep it on your server. Create keys in the console under Settings › Keys.\n- **Site key** (`bs_site_…` live, `bs_site_test_…` test), sent in the `siteKey` field of the `/check` body. It is public. A check is accepted only from a browser `Origin` on the site key's list of domains.\n\n## Test mode\n\nA test API key or a test site key puts the request in test mode. Test requests are screened and recorded (History shows them with \"Show test data\"), but they never count against your monthly quota and never create a review, a webhook, a label or alert data. Test traffic has its own per-minute limits, separate from live traffic: 300 per minute per account on each of `/verify` and `/check` (`/check` is also limited to 30 per minute per client IP), and 300 per minute per test key on `/siteverify`. On top of that, 10,000 test screenings (`/verify` and `/check`) per account per UTC day (then `429 TEST_LIMIT`).\n\nIn test mode these five addresses always give the same result without running the engine (the part before @ is case-insensitive; the domain must be exactly `test.inlineshield.io`):\n\n| Address | decision | action | recommendedAction | riskScore |\n|---|---|---|---|---|\n| allow@test.inlineshield.io | ALLOWED | allow | allow | 0 |\n| nobonus@test.inlineshield.io | ALLOWED | allow | allow_no_bonus | 30 |\n| review@test.inlineshield.io | QUARANTINED | hold | review | 50 |\n| kyc@test.inlineshield.io | QUARANTINED | hold | require_kyc | 60 |\n| block@test.inlineshield.io | BLOCKED | block | block | 95 |\n\nA live key screens these addresses like any other. A held test screening has no `reviewId`: test mode creates no review, so the `signup.*` webhooks cannot be triggered with test traffic. Use the console's \"Send test ping\" for a signed `test.ping` delivery.\n\n## Quota and rate limits\n\nEach live `/verify` or `/check` screening counts against the monthly quota of your plan. Over the quota (after a grace margin) both answer `402 QUOTA_EXCEEDED` until the next UTC month; `/siteverify` then answers `{ success: false, error: \"QUOTA_EXCEEDED\" }` for a missing token. Live responses carry `X-Quota-Limit`, `X-Quota-Used`, `X-Quota-Reset` and `X-Quota-State`.\n\nPer-minute limits answer `429 RATE_LIMIT_EXCEEDED` with `Retry-After` (seconds). `/verify`, `/siteverify` and `/feedback` also send `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset` (seconds until the window resets); `/check` and `/reviews/{reviewId}` send only `Retry-After`, on a 429. Browser code can read the quota and rate-limit headers and `Retry-After` (they are listed in `Access-Control-Expose-Headers`).\n\n## Webhooks\n\nInlineShield sends `registration.allowed`, `registration.blocked`, `signup.approved`, `signup.rejected` and `test.ping` (see `webhooks`). A held sign-up arrives as `registration.blocked` with `data.decision: \"QUARANTINED\"`, and is resolved later by `signup.approved` or `signup.rejected`. The event names `incident.created` and `registration.review_required` can appear in an endpoint's subscription list (`incident.created` is there by default), but they are never sent: no delivery ever carries either name.\n\n## Errors\n\nErrors are JSON: `{ \"error\": \"CODE\", \"message\": \"…\" }`. Branch on `error`, not on `message`. A body that is not valid JSON gets `400 BAD_REQUEST`; a body over 1 MB gets `413 PAYLOAD_TOO_LARGE`.\n\n`/siteverify` answers token problems with HTTP 200 and `{ \"success\": false, \"error\": \"…\" }`.\n\nGenerated from openapi.json (version 1.0.0). Set the collection variables apiKey (a test key, bs_test_…, to start), siteKey and, for /check, origin (one of the site key's domains, e.g. https://www.example.com).",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "item": [
    {
      "name": "Screening",
      "description": "Screen a sign-up from your backend.",
      "item": [
        {
          "name": "Screen a sign-up",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "X-Api-Key",
                "value": "{{apiKey}}",
                "description": "Your secret API key (collection variable apiKey)."
              },
              {
                "key": "X-Response-Mode",
                "value": "http-status",
                "description": "Answer a BLOCKED screening with HTTP 403 instead of 200.",
                "disabled": true
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/verify",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "verify"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\": \"allow@test.inlineshield.io\",\n  \"ip\": \"203.0.113.24\",\n  \"userAgent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36\",\n  \"clientDwellMs\": 8200\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Screens one sign-up and returns the verdict, the action to take and the reasons. Call it from your backend before you create the account.\n\n- `action`: `allow` (create the account), `hold` (create it but keep it on hold until the review is decided), `block` (refuse it).\n- `recommendedAction`: advice next to `action`, never instead of it. ALLOWED with `riskScore` 25 or more gives `allow_no_bonus`; QUARANTINED gives `review`; BLOCKED gives `block`.\n- A live hold has a `reviewId`; a test hold has none.\n\nWith the header `X-Response-Mode: http-status` (or `?mode=http-status`) a BLOCKED screening is answered with HTTP 403 and the same body.\n\n`POST /api/v1/evaluate` is a deprecated alias with identical behaviour; use `/api/v1/verify`."
          },
          "response": [
            {
              "name": "200 Magic address: ALLOWED, allow",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  },
                  {
                    "key": "X-Response-Mode",
                    "value": "http-status",
                    "description": "Answer a BLOCKED screening with HTTP 403 instead of 200.",
                    "disabled": true
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/verify",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "verify"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"email\": \"allow@test.inlineshield.io\",\n  \"ip\": \"203.0.113.24\",\n  \"userAgent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36\",\n  \"clientDwellMs\": 8200\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Screens one sign-up and returns the verdict, the action to take and the reasons. Call it from your backend before you create the account.\n\n- `action`: `allow` (create the account), `hold` (create it but keep it on hold until the review is decided), `block` (refuse it).\n- `recommendedAction`: advice next to `action`, never instead of it. ALLOWED with `riskScore` 25 or more gives `allow_no_bonus`; QUARANTINED gives `review`; BLOCKED gives `block`.\n- A live hold has a `reviewId`; a test hold has none.\n\nWith the header `X-Response-Mode: http-status` (or `?mode=http-status`) a BLOCKED screening is answered with HTTP 403 and the same body.\n\n`POST /api/v1/evaluate` is a deprecated alias with identical behaviour; use `/api/v1/verify`."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"requestId\": \"AUD-MHH3K2QZ-4F1C9B2E7D10\",\n  \"decision\": \"ALLOWED\",\n  \"action\": \"allow\",\n  \"recommendedAction\": \"allow\",\n  \"verdict\": \"ALLOWED\",\n  \"riskScore\": 0,\n  \"reasons\": [\n    \"Test mode: allow@test.inlineshield.io always gives ALLOWED / allow.\"\n  ],\n  \"triggers\": [\n    \"TEST_MAGIC_ADDRESS\"\n  ],\n  \"policyVersion\": \"1\",\n  \"processingTimeMs\": 0,\n  \"forwardedToDatabase\": true,\n  \"emailAnalysis\": {\n    \"normalizedEmail\": \"allow@test.inlineshield.io\",\n    \"localPart\": \"allow\",\n    \"domain\": \"test.inlineshield.io\",\n    \"isDisposable\": false,\n    \"isPlusAliased\": false,\n    \"isRoleAccount\": false,\n    \"hasTypoRisk\": false,\n    \"mxValid\": false,\n    \"mx\": {\n      \"status\": \"unknown\",\n      \"records\": []\n    },\n    \"mxRecords\": [],\n    \"mailServers\": \"unknown\",\n    \"spf\": {\n      \"exists\": false,\n      \"status\": \"unknown\",\n      \"qualifier\": \"NONE\",\n      \"isPermissive\": false,\n      \"mechanisms\": []\n    },\n    \"dmarc\": {\n      \"exists\": false,\n      \"status\": \"unknown\",\n      \"policy\": \"missing\",\n      \"compliant\": false\n    },\n    \"dkim\": {\n      \"selectorChecked\": \"\",\n      \"exists\": false,\n      \"status\": \"UNVERIFIABLE\"\n    },\n    \"localPartRandomness\": null\n  },\n  \"botAnalysis\": {\n    \"dwellTimeMs\": 8200,\n    \"isFastSubmission\": false,\n    \"honeypotTriggered\": false,\n    \"isHeadlessBrowser\": false,\n    \"isAutomationAgent\": false,\n    \"scriptedUserAgent\": false,\n    \"scriptedClient\": null,\n    \"entropyScore\": 0\n  },\n  \"ipRisk\": {\n    \"ip\": \"203.0.113.24\",\n    \"isDatacenter\": null,\n    \"isTorExit\": null,\n    \"isVpnOrProxy\": false,\n    \"isVpn\": null,\n    \"country\": \"Unknown\",\n    \"countryCode\": null,\n    \"org\": \"Unknown\",\n    \"asn\": null\n  }\n}"
            },
            {
              "name": "200 Magic address: ALLOWED, allow_no_bonus",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  },
                  {
                    "key": "X-Response-Mode",
                    "value": "http-status",
                    "description": "Answer a BLOCKED screening with HTTP 403 instead of 200.",
                    "disabled": true
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/verify",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "verify"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"email\": \"allow@test.inlineshield.io\",\n  \"ip\": \"203.0.113.24\",\n  \"userAgent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36\",\n  \"clientDwellMs\": 8200\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Screens one sign-up and returns the verdict, the action to take and the reasons. Call it from your backend before you create the account.\n\n- `action`: `allow` (create the account), `hold` (create it but keep it on hold until the review is decided), `block` (refuse it).\n- `recommendedAction`: advice next to `action`, never instead of it. ALLOWED with `riskScore` 25 or more gives `allow_no_bonus`; QUARANTINED gives `review`; BLOCKED gives `block`.\n- A live hold has a `reviewId`; a test hold has none.\n\nWith the header `X-Response-Mode: http-status` (or `?mode=http-status`) a BLOCKED screening is answered with HTTP 403 and the same body.\n\n`POST /api/v1/evaluate` is a deprecated alias with identical behaviour; use `/api/v1/verify`."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"requestId\": \"AUD-MHH3K30A-91B7C2D40E55\",\n  \"decision\": \"ALLOWED\",\n  \"action\": \"allow\",\n  \"recommendedAction\": \"allow_no_bonus\",\n  \"verdict\": \"ALLOWED\",\n  \"riskScore\": 30,\n  \"reasons\": [\n    \"Test mode: nobonus@test.inlineshield.io always gives ALLOWED / allow_no_bonus.\"\n  ],\n  \"triggers\": [\n    \"TEST_MAGIC_ADDRESS\"\n  ],\n  \"policyVersion\": \"1\",\n  \"processingTimeMs\": 0,\n  \"forwardedToDatabase\": true,\n  \"emailAnalysis\": {\n    \"normalizedEmail\": \"nobonus@test.inlineshield.io\",\n    \"localPart\": \"nobonus\",\n    \"domain\": \"test.inlineshield.io\",\n    \"isDisposable\": false,\n    \"isPlusAliased\": false,\n    \"isRoleAccount\": false,\n    \"hasTypoRisk\": false,\n    \"mxValid\": false,\n    \"mx\": {\n      \"status\": \"unknown\",\n      \"records\": []\n    },\n    \"mxRecords\": [],\n    \"mailServers\": \"unknown\",\n    \"spf\": {\n      \"exists\": false,\n      \"status\": \"unknown\",\n      \"qualifier\": \"NONE\",\n      \"isPermissive\": false,\n      \"mechanisms\": []\n    },\n    \"dmarc\": {\n      \"exists\": false,\n      \"status\": \"unknown\",\n      \"policy\": \"missing\",\n      \"compliant\": false\n    },\n    \"dkim\": {\n      \"selectorChecked\": \"\",\n      \"exists\": false,\n      \"status\": \"UNVERIFIABLE\"\n    },\n    \"localPartRandomness\": null\n  },\n  \"botAnalysis\": {\n    \"dwellTimeMs\": 8200,\n    \"isFastSubmission\": false,\n    \"honeypotTriggered\": false,\n    \"isHeadlessBrowser\": false,\n    \"isAutomationAgent\": false,\n    \"scriptedUserAgent\": false,\n    \"scriptedClient\": null,\n    \"entropyScore\": 0\n  },\n  \"ipRisk\": {\n    \"ip\": \"203.0.113.24\",\n    \"isDatacenter\": null,\n    \"isTorExit\": null,\n    \"isVpnOrProxy\": false,\n    \"isVpn\": null,\n    \"country\": \"Unknown\",\n    \"countryCode\": null,\n    \"org\": \"Unknown\",\n    \"asn\": null\n  }\n}"
            },
            {
              "name": "200 Magic address: QUARANTINED, review (test mode: no reviewId)",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  },
                  {
                    "key": "X-Response-Mode",
                    "value": "http-status",
                    "description": "Answer a BLOCKED screening with HTTP 403 instead of 200.",
                    "disabled": true
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/verify",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "verify"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"email\": \"allow@test.inlineshield.io\",\n  \"ip\": \"203.0.113.24\",\n  \"userAgent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36\",\n  \"clientDwellMs\": 8200\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Screens one sign-up and returns the verdict, the action to take and the reasons. Call it from your backend before you create the account.\n\n- `action`: `allow` (create the account), `hold` (create it but keep it on hold until the review is decided), `block` (refuse it).\n- `recommendedAction`: advice next to `action`, never instead of it. ALLOWED with `riskScore` 25 or more gives `allow_no_bonus`; QUARANTINED gives `review`; BLOCKED gives `block`.\n- A live hold has a `reviewId`; a test hold has none.\n\nWith the header `X-Response-Mode: http-status` (or `?mode=http-status`) a BLOCKED screening is answered with HTTP 403 and the same body.\n\n`POST /api/v1/evaluate` is a deprecated alias with identical behaviour; use `/api/v1/verify`."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"requestId\": \"AUD-MHH3K31C-0C3D5E7F9A21\",\n  \"decision\": \"QUARANTINED\",\n  \"action\": \"hold\",\n  \"recommendedAction\": \"review\",\n  \"verdict\": \"QUARANTINED\",\n  \"riskScore\": 50,\n  \"reasons\": [\n    \"Test mode: review@test.inlineshield.io always gives QUARANTINED / review.\"\n  ],\n  \"triggers\": [\n    \"TEST_MAGIC_ADDRESS\"\n  ],\n  \"policyVersion\": \"1\",\n  \"processingTimeMs\": 0,\n  \"forwardedToDatabase\": false,\n  \"emailAnalysis\": {\n    \"normalizedEmail\": \"review@test.inlineshield.io\",\n    \"localPart\": \"review\",\n    \"domain\": \"test.inlineshield.io\",\n    \"isDisposable\": false,\n    \"isPlusAliased\": false,\n    \"isRoleAccount\": false,\n    \"hasTypoRisk\": false,\n    \"mxValid\": false,\n    \"mx\": {\n      \"status\": \"unknown\",\n      \"records\": []\n    },\n    \"mxRecords\": [],\n    \"mailServers\": \"unknown\",\n    \"spf\": {\n      \"exists\": false,\n      \"status\": \"unknown\",\n      \"qualifier\": \"NONE\",\n      \"isPermissive\": false,\n      \"mechanisms\": []\n    },\n    \"dmarc\": {\n      \"exists\": false,\n      \"status\": \"unknown\",\n      \"policy\": \"missing\",\n      \"compliant\": false\n    },\n    \"dkim\": {\n      \"selectorChecked\": \"\",\n      \"exists\": false,\n      \"status\": \"UNVERIFIABLE\"\n    },\n    \"localPartRandomness\": null\n  },\n  \"botAnalysis\": {\n    \"dwellTimeMs\": 8200,\n    \"isFastSubmission\": false,\n    \"honeypotTriggered\": false,\n    \"isHeadlessBrowser\": false,\n    \"isAutomationAgent\": false,\n    \"scriptedUserAgent\": false,\n    \"scriptedClient\": null,\n    \"entropyScore\": 0\n  },\n  \"ipRisk\": {\n    \"ip\": \"203.0.113.24\",\n    \"isDatacenter\": null,\n    \"isTorExit\": null,\n    \"isVpnOrProxy\": false,\n    \"isVpn\": null,\n    \"country\": \"Unknown\",\n    \"countryCode\": null,\n    \"org\": \"Unknown\",\n    \"asn\": null\n  }\n}"
            },
            {
              "name": "200 Magic address: QUARANTINED, require_kyc (test mode: no reviewId)",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  },
                  {
                    "key": "X-Response-Mode",
                    "value": "http-status",
                    "description": "Answer a BLOCKED screening with HTTP 403 instead of 200.",
                    "disabled": true
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/verify",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "verify"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"email\": \"allow@test.inlineshield.io\",\n  \"ip\": \"203.0.113.24\",\n  \"userAgent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36\",\n  \"clientDwellMs\": 8200\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Screens one sign-up and returns the verdict, the action to take and the reasons. Call it from your backend before you create the account.\n\n- `action`: `allow` (create the account), `hold` (create it but keep it on hold until the review is decided), `block` (refuse it).\n- `recommendedAction`: advice next to `action`, never instead of it. ALLOWED with `riskScore` 25 or more gives `allow_no_bonus`; QUARANTINED gives `review`; BLOCKED gives `block`.\n- A live hold has a `reviewId`; a test hold has none.\n\nWith the header `X-Response-Mode: http-status` (or `?mode=http-status`) a BLOCKED screening is answered with HTTP 403 and the same body.\n\n`POST /api/v1/evaluate` is a deprecated alias with identical behaviour; use `/api/v1/verify`."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"requestId\": \"AUD-MHH3K32F-7E2A4C6B8D90\",\n  \"decision\": \"QUARANTINED\",\n  \"action\": \"hold\",\n  \"recommendedAction\": \"require_kyc\",\n  \"verdict\": \"QUARANTINED\",\n  \"riskScore\": 60,\n  \"reasons\": [\n    \"Test mode: kyc@test.inlineshield.io always gives QUARANTINED / require_kyc.\"\n  ],\n  \"triggers\": [\n    \"TEST_MAGIC_ADDRESS\"\n  ],\n  \"policyVersion\": \"1\",\n  \"processingTimeMs\": 0,\n  \"forwardedToDatabase\": false,\n  \"emailAnalysis\": {\n    \"normalizedEmail\": \"kyc@test.inlineshield.io\",\n    \"localPart\": \"kyc\",\n    \"domain\": \"test.inlineshield.io\",\n    \"isDisposable\": false,\n    \"isPlusAliased\": false,\n    \"isRoleAccount\": false,\n    \"hasTypoRisk\": false,\n    \"mxValid\": false,\n    \"mx\": {\n      \"status\": \"unknown\",\n      \"records\": []\n    },\n    \"mxRecords\": [],\n    \"mailServers\": \"unknown\",\n    \"spf\": {\n      \"exists\": false,\n      \"status\": \"unknown\",\n      \"qualifier\": \"NONE\",\n      \"isPermissive\": false,\n      \"mechanisms\": []\n    },\n    \"dmarc\": {\n      \"exists\": false,\n      \"status\": \"unknown\",\n      \"policy\": \"missing\",\n      \"compliant\": false\n    },\n    \"dkim\": {\n      \"selectorChecked\": \"\",\n      \"exists\": false,\n      \"status\": \"UNVERIFIABLE\"\n    },\n    \"localPartRandomness\": null\n  },\n  \"botAnalysis\": {\n    \"dwellTimeMs\": 8200,\n    \"isFastSubmission\": false,\n    \"honeypotTriggered\": false,\n    \"isHeadlessBrowser\": false,\n    \"isAutomationAgent\": false,\n    \"scriptedUserAgent\": false,\n    \"scriptedClient\": null,\n    \"entropyScore\": 0\n  },\n  \"ipRisk\": {\n    \"ip\": \"203.0.113.24\",\n    \"isDatacenter\": null,\n    \"isTorExit\": null,\n    \"isVpnOrProxy\": false,\n    \"isVpn\": null,\n    \"country\": \"Unknown\",\n    \"countryCode\": null,\n    \"org\": \"Unknown\",\n    \"asn\": null\n  }\n}"
            },
            {
              "name": "200 Magic address: BLOCKED, block",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  },
                  {
                    "key": "X-Response-Mode",
                    "value": "http-status",
                    "description": "Answer a BLOCKED screening with HTTP 403 instead of 200.",
                    "disabled": true
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/verify",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "verify"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"email\": \"allow@test.inlineshield.io\",\n  \"ip\": \"203.0.113.24\",\n  \"userAgent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36\",\n  \"clientDwellMs\": 8200\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Screens one sign-up and returns the verdict, the action to take and the reasons. Call it from your backend before you create the account.\n\n- `action`: `allow` (create the account), `hold` (create it but keep it on hold until the review is decided), `block` (refuse it).\n- `recommendedAction`: advice next to `action`, never instead of it. ALLOWED with `riskScore` 25 or more gives `allow_no_bonus`; QUARANTINED gives `review`; BLOCKED gives `block`.\n- A live hold has a `reviewId`; a test hold has none.\n\nWith the header `X-Response-Mode: http-status` (or `?mode=http-status`) a BLOCKED screening is answered with HTTP 403 and the same body.\n\n`POST /api/v1/evaluate` is a deprecated alias with identical behaviour; use `/api/v1/verify`."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"requestId\": \"AUD-MHH3K33H-5B9D1F3A7C02\",\n  \"decision\": \"BLOCKED\",\n  \"action\": \"block\",\n  \"recommendedAction\": \"block\",\n  \"verdict\": \"BLOCKED\",\n  \"riskScore\": 95,\n  \"reasons\": [\n    \"Test mode: block@test.inlineshield.io always gives BLOCKED / block.\"\n  ],\n  \"triggers\": [\n    \"TEST_MAGIC_ADDRESS\"\n  ],\n  \"policyVersion\": \"1\",\n  \"processingTimeMs\": 0,\n  \"forwardedToDatabase\": false,\n  \"emailAnalysis\": {\n    \"normalizedEmail\": \"block@test.inlineshield.io\",\n    \"localPart\": \"block\",\n    \"domain\": \"test.inlineshield.io\",\n    \"isDisposable\": false,\n    \"isPlusAliased\": false,\n    \"isRoleAccount\": false,\n    \"hasTypoRisk\": false,\n    \"mxValid\": false,\n    \"mx\": {\n      \"status\": \"unknown\",\n      \"records\": []\n    },\n    \"mxRecords\": [],\n    \"mailServers\": \"unknown\",\n    \"spf\": {\n      \"exists\": false,\n      \"status\": \"unknown\",\n      \"qualifier\": \"NONE\",\n      \"isPermissive\": false,\n      \"mechanisms\": []\n    },\n    \"dmarc\": {\n      \"exists\": false,\n      \"status\": \"unknown\",\n      \"policy\": \"missing\",\n      \"compliant\": false\n    },\n    \"dkim\": {\n      \"selectorChecked\": \"\",\n      \"exists\": false,\n      \"status\": \"UNVERIFIABLE\"\n    },\n    \"localPartRandomness\": null\n  },\n  \"botAnalysis\": {\n    \"dwellTimeMs\": 8200,\n    \"isFastSubmission\": false,\n    \"honeypotTriggered\": false,\n    \"isHeadlessBrowser\": false,\n    \"isAutomationAgent\": false,\n    \"scriptedUserAgent\": false,\n    \"scriptedClient\": null,\n    \"entropyScore\": 0\n  },\n  \"ipRisk\": {\n    \"ip\": \"203.0.113.24\",\n    \"isDatacenter\": null,\n    \"isTorExit\": null,\n    \"isVpnOrProxy\": false,\n    \"isVpn\": null,\n    \"country\": \"Unknown\",\n    \"countryCode\": null,\n    \"org\": \"Unknown\",\n    \"asn\": null\n  }\n}"
            },
            {
              "name": "400 missingEmail",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  },
                  {
                    "key": "X-Response-Mode",
                    "value": "http-status",
                    "description": "Answer a BLOCKED screening with HTTP 403 instead of 200.",
                    "disabled": true
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/verify",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "verify"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"email\": \"allow@test.inlineshield.io\",\n  \"ip\": \"203.0.113.24\",\n  \"userAgent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36\",\n  \"clientDwellMs\": 8200\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Screens one sign-up and returns the verdict, the action to take and the reasons. Call it from your backend before you create the account.\n\n- `action`: `allow` (create the account), `hold` (create it but keep it on hold until the review is decided), `block` (refuse it).\n- `recommendedAction`: advice next to `action`, never instead of it. ALLOWED with `riskScore` 25 or more gives `allow_no_bonus`; QUARANTINED gives `review`; BLOCKED gives `block`.\n- A live hold has a `reviewId`; a test hold has none.\n\nWith the header `X-Response-Mode: http-status` (or `?mode=http-status`) a BLOCKED screening is answered with HTTP 403 and the same body.\n\n`POST /api/v1/evaluate` is a deprecated alias with identical behaviour; use `/api/v1/verify`."
              },
              "status": "Bad Request",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"error\": \"BAD_REQUEST\",\n  \"message\": \"Field \\\"email\\\" is required for registration verification.\"\n}"
            },
            {
              "name": "400 invalidIp",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  },
                  {
                    "key": "X-Response-Mode",
                    "value": "http-status",
                    "description": "Answer a BLOCKED screening with HTTP 403 instead of 200.",
                    "disabled": true
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/verify",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "verify"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"email\": \"allow@test.inlineshield.io\",\n  \"ip\": \"203.0.113.24\",\n  \"userAgent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36\",\n  \"clientDwellMs\": 8200\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Screens one sign-up and returns the verdict, the action to take and the reasons. Call it from your backend before you create the account.\n\n- `action`: `allow` (create the account), `hold` (create it but keep it on hold until the review is decided), `block` (refuse it).\n- `recommendedAction`: advice next to `action`, never instead of it. ALLOWED with `riskScore` 25 or more gives `allow_no_bonus`; QUARANTINED gives `review`; BLOCKED gives `block`.\n- A live hold has a `reviewId`; a test hold has none.\n\nWith the header `X-Response-Mode: http-status` (or `?mode=http-status`) a BLOCKED screening is answered with HTTP 403 and the same body.\n\n`POST /api/v1/evaluate` is a deprecated alias with identical behaviour; use `/api/v1/verify`."
              },
              "status": "Bad Request",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"error\": \"INVALID_IP\",\n  \"message\": \"ip must be a valid IPv4 or IPv6 address.\"\n}"
            },
            {
              "name": "401 missing",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  },
                  {
                    "key": "X-Response-Mode",
                    "value": "http-status",
                    "description": "Answer a BLOCKED screening with HTTP 403 instead of 200.",
                    "disabled": true
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/verify",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "verify"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"email\": \"allow@test.inlineshield.io\",\n  \"ip\": \"203.0.113.24\",\n  \"userAgent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36\",\n  \"clientDwellMs\": 8200\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Screens one sign-up and returns the verdict, the action to take and the reasons. Call it from your backend before you create the account.\n\n- `action`: `allow` (create the account), `hold` (create it but keep it on hold until the review is decided), `block` (refuse it).\n- `recommendedAction`: advice next to `action`, never instead of it. ALLOWED with `riskScore` 25 or more gives `allow_no_bonus`; QUARANTINED gives `review`; BLOCKED gives `block`.\n- A live hold has a `reviewId`; a test hold has none.\n\nWith the header `X-Response-Mode: http-status` (or `?mode=http-status`) a BLOCKED screening is answered with HTTP 403 and the same body.\n\n`POST /api/v1/evaluate` is a deprecated alias with identical behaviour; use `/api/v1/verify`."
              },
              "status": "Unauthorized",
              "code": 401,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"error\": \"UNAUTHORIZED\",\n  \"message\": \"Access denied: Missing required X-Api-Key header.\"\n}"
            },
            {
              "name": "401 invalid",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  },
                  {
                    "key": "X-Response-Mode",
                    "value": "http-status",
                    "description": "Answer a BLOCKED screening with HTTP 403 instead of 200.",
                    "disabled": true
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/verify",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "verify"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"email\": \"allow@test.inlineshield.io\",\n  \"ip\": \"203.0.113.24\",\n  \"userAgent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36\",\n  \"clientDwellMs\": 8200\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Screens one sign-up and returns the verdict, the action to take and the reasons. Call it from your backend before you create the account.\n\n- `action`: `allow` (create the account), `hold` (create it but keep it on hold until the review is decided), `block` (refuse it).\n- `recommendedAction`: advice next to `action`, never instead of it. ALLOWED with `riskScore` 25 or more gives `allow_no_bonus`; QUARANTINED gives `review`; BLOCKED gives `block`.\n- A live hold has a `reviewId`; a test hold has none.\n\nWith the header `X-Response-Mode: http-status` (or `?mode=http-status`) a BLOCKED screening is answered with HTTP 403 and the same body.\n\n`POST /api/v1/evaluate` is a deprecated alias with identical behaviour; use `/api/v1/verify`."
              },
              "status": "Unauthorized",
              "code": 401,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"error\": \"INVALID_API_KEY\",\n  \"message\": \"Invalid API key provided.\"\n}"
            },
            {
              "name": "402 quota",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  },
                  {
                    "key": "X-Response-Mode",
                    "value": "http-status",
                    "description": "Answer a BLOCKED screening with HTTP 403 instead of 200.",
                    "disabled": true
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/verify",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "verify"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"email\": \"allow@test.inlineshield.io\",\n  \"ip\": \"203.0.113.24\",\n  \"userAgent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36\",\n  \"clientDwellMs\": 8200\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Screens one sign-up and returns the verdict, the action to take and the reasons. Call it from your backend before you create the account.\n\n- `action`: `allow` (create the account), `hold` (create it but keep it on hold until the review is decided), `block` (refuse it).\n- `recommendedAction`: advice next to `action`, never instead of it. ALLOWED with `riskScore` 25 or more gives `allow_no_bonus`; QUARANTINED gives `review`; BLOCKED gives `block`.\n- A live hold has a `reviewId`; a test hold has none.\n\nWith the header `X-Response-Mode: http-status` (or `?mode=http-status`) a BLOCKED screening is answered with HTTP 403 and the same body.\n\n`POST /api/v1/evaluate` is a deprecated alias with identical behaviour; use `/api/v1/verify`."
              },
              "status": "Payment Required",
              "code": 402,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"error\": \"QUOTA_EXCEEDED\",\n  \"message\": \"Monthly check limit reached for this account. Checks resume at 2026-12-01T00:00:00.000Z.\",\n  \"used\": 27500,\n  \"limit\": 25000,\n  \"resetsAt\": \"2026-12-01T00:00:00.000Z\"\n}"
            },
            {
              "name": "429 rateLimit",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  },
                  {
                    "key": "X-Response-Mode",
                    "value": "http-status",
                    "description": "Answer a BLOCKED screening with HTTP 403 instead of 200.",
                    "disabled": true
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/verify",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "verify"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"email\": \"allow@test.inlineshield.io\",\n  \"ip\": \"203.0.113.24\",\n  \"userAgent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36\",\n  \"clientDwellMs\": 8200\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Screens one sign-up and returns the verdict, the action to take and the reasons. Call it from your backend before you create the account.\n\n- `action`: `allow` (create the account), `hold` (create it but keep it on hold until the review is decided), `block` (refuse it).\n- `recommendedAction`: advice next to `action`, never instead of it. ALLOWED with `riskScore` 25 or more gives `allow_no_bonus`; QUARANTINED gives `review`; BLOCKED gives `block`.\n- A live hold has a `reviewId`; a test hold has none.\n\nWith the header `X-Response-Mode: http-status` (or `?mode=http-status`) a BLOCKED screening is answered with HTTP 403 and the same body.\n\n`POST /api/v1/evaluate` is a deprecated alias with identical behaviour; use `/api/v1/verify`."
              },
              "status": "Too Many Requests",
              "code": 429,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"error\": \"RATE_LIMIT_EXCEEDED\",\n  \"message\": \"Tenant verification rate limit of 600 req/min exceeded. Try again in 12 seconds.\"\n}"
            },
            {
              "name": "429 testLimit",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  },
                  {
                    "key": "X-Response-Mode",
                    "value": "http-status",
                    "description": "Answer a BLOCKED screening with HTTP 403 instead of 200.",
                    "disabled": true
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/verify",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "verify"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"email\": \"allow@test.inlineshield.io\",\n  \"ip\": \"203.0.113.24\",\n  \"userAgent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36\",\n  \"clientDwellMs\": 8200\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Screens one sign-up and returns the verdict, the action to take and the reasons. Call it from your backend before you create the account.\n\n- `action`: `allow` (create the account), `hold` (create it but keep it on hold until the review is decided), `block` (refuse it).\n- `recommendedAction`: advice next to `action`, never instead of it. ALLOWED with `riskScore` 25 or more gives `allow_no_bonus`; QUARANTINED gives `review`; BLOCKED gives `block`.\n- A live hold has a `reviewId`; a test hold has none.\n\nWith the header `X-Response-Mode: http-status` (or `?mode=http-status`) a BLOCKED screening is answered with HTTP 403 and the same body.\n\n`POST /api/v1/evaluate` is a deprecated alias with identical behaviour; use `/api/v1/verify`."
              },
              "status": "Too Many Requests",
              "code": 429,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"error\": \"TEST_LIMIT\",\n  \"message\": \"Test mode is limited to 10,000 test screenings (/verify and /check) per account per UTC day. Use a live key for production traffic.\"\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Browser check",
      "description": "The browser script and the backend token check.",
      "item": [
        {
          "name": "Browser check (site key)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Origin",
                "value": "{{origin}}",
                "description": "Set by the browser. Must be an https or http origin on the site key's list of domains."
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/check",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "check"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"siteKey\": \"{{siteKey}}\",\n  \"email\": \"allow@test.inlineshield.io\",\n  \"clientDwellMs\": 8200\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Called by `inlineshield.js` in the player's browser. Authenticated by the site key in the body and the browser's `Origin`, which must be one of the site key's domains. Screens the sign-up and returns the verdict and a single-use `token` (valid for 10 minutes) for `/siteverify`.\n\nThe IP and User-Agent are taken from the request itself, never from the body. Reasons produced by learned signals are shown as one generic line here; `/siteverify` returns them in full.\n\nPer-minute limits: 30 checks per client IP, and your plan's limit per account (300 for test site keys)."
          },
          "response": [
            {
              "name": "200 Magic address: ALLOWED, allow",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Origin",
                    "value": "{{origin}}",
                    "description": "Set by the browser. Must be an https or http origin on the site key's list of domains."
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/check",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "check"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"siteKey\": \"{{siteKey}}\",\n  \"email\": \"allow@test.inlineshield.io\",\n  \"clientDwellMs\": 8200\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Called by `inlineshield.js` in the player's browser. Authenticated by the site key in the body and the browser's `Origin`, which must be one of the site key's domains. Screens the sign-up and returns the verdict and a single-use `token` (valid for 10 minutes) for `/siteverify`.\n\nThe IP and User-Agent are taken from the request itself, never from the body. Reasons produced by learned signals are shown as one generic line here; `/siteverify` returns them in full.\n\nPer-minute limits: 30 checks per client IP, and your plan's limit per account (300 for test site keys)."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"decision\": \"ALLOWED\",\n  \"riskScore\": 0,\n  \"reasons\": [\n    \"Test mode: allow@test.inlineshield.io always gives ALLOWED / allow.\"\n  ],\n  \"requestId\": \"AUD-MHH3K2QZ-4F1C9B2E7D10\",\n  \"token\": \"bst_q3Jm0b8vN2kXo7rT5wYz1cE4hL6pA9sD0fG2jK8uV3i\"\n}"
            },
            {
              "name": "200 Magic address: ALLOWED, allow_no_bonus",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Origin",
                    "value": "{{origin}}",
                    "description": "Set by the browser. Must be an https or http origin on the site key's list of domains."
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/check",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "check"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"siteKey\": \"{{siteKey}}\",\n  \"email\": \"allow@test.inlineshield.io\",\n  \"clientDwellMs\": 8200\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Called by `inlineshield.js` in the player's browser. Authenticated by the site key in the body and the browser's `Origin`, which must be one of the site key's domains. Screens the sign-up and returns the verdict and a single-use `token` (valid for 10 minutes) for `/siteverify`.\n\nThe IP and User-Agent are taken from the request itself, never from the body. Reasons produced by learned signals are shown as one generic line here; `/siteverify` returns them in full.\n\nPer-minute limits: 30 checks per client IP, and your plan's limit per account (300 for test site keys)."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"decision\": \"ALLOWED\",\n  \"riskScore\": 30,\n  \"reasons\": [\n    \"Test mode: nobonus@test.inlineshield.io always gives ALLOWED / allow_no_bonus.\"\n  ],\n  \"requestId\": \"AUD-MHH3K30A-91B7C2D40E55\",\n  \"token\": \"bst_q3Jm0b8vN2kXo7rT5wYz1cE4hL6pA9sD0fG2jK8uV3i\"\n}"
            },
            {
              "name": "200 Magic address: QUARANTINED, review",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Origin",
                    "value": "{{origin}}",
                    "description": "Set by the browser. Must be an https or http origin on the site key's list of domains."
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/check",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "check"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"siteKey\": \"{{siteKey}}\",\n  \"email\": \"allow@test.inlineshield.io\",\n  \"clientDwellMs\": 8200\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Called by `inlineshield.js` in the player's browser. Authenticated by the site key in the body and the browser's `Origin`, which must be one of the site key's domains. Screens the sign-up and returns the verdict and a single-use `token` (valid for 10 minutes) for `/siteverify`.\n\nThe IP and User-Agent are taken from the request itself, never from the body. Reasons produced by learned signals are shown as one generic line here; `/siteverify` returns them in full.\n\nPer-minute limits: 30 checks per client IP, and your plan's limit per account (300 for test site keys)."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"decision\": \"QUARANTINED\",\n  \"riskScore\": 50,\n  \"reasons\": [\n    \"Test mode: review@test.inlineshield.io always gives QUARANTINED / review.\"\n  ],\n  \"requestId\": \"AUD-MHH3K31C-0C3D5E7F9A21\",\n  \"token\": \"bst_q3Jm0b8vN2kXo7rT5wYz1cE4hL6pA9sD0fG2jK8uV3i\"\n}"
            },
            {
              "name": "200 Magic address: QUARANTINED, require_kyc",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Origin",
                    "value": "{{origin}}",
                    "description": "Set by the browser. Must be an https or http origin on the site key's list of domains."
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/check",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "check"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"siteKey\": \"{{siteKey}}\",\n  \"email\": \"allow@test.inlineshield.io\",\n  \"clientDwellMs\": 8200\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Called by `inlineshield.js` in the player's browser. Authenticated by the site key in the body and the browser's `Origin`, which must be one of the site key's domains. Screens the sign-up and returns the verdict and a single-use `token` (valid for 10 minutes) for `/siteverify`.\n\nThe IP and User-Agent are taken from the request itself, never from the body. Reasons produced by learned signals are shown as one generic line here; `/siteverify` returns them in full.\n\nPer-minute limits: 30 checks per client IP, and your plan's limit per account (300 for test site keys)."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"decision\": \"QUARANTINED\",\n  \"riskScore\": 60,\n  \"reasons\": [\n    \"Test mode: kyc@test.inlineshield.io always gives QUARANTINED / require_kyc.\"\n  ],\n  \"requestId\": \"AUD-MHH3K32F-7E2A4C6B8D90\",\n  \"token\": \"bst_q3Jm0b8vN2kXo7rT5wYz1cE4hL6pA9sD0fG2jK8uV3i\"\n}"
            },
            {
              "name": "200 Magic address: BLOCKED, block",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Origin",
                    "value": "{{origin}}",
                    "description": "Set by the browser. Must be an https or http origin on the site key's list of domains."
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/check",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "check"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"siteKey\": \"{{siteKey}}\",\n  \"email\": \"allow@test.inlineshield.io\",\n  \"clientDwellMs\": 8200\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Called by `inlineshield.js` in the player's browser. Authenticated by the site key in the body and the browser's `Origin`, which must be one of the site key's domains. Screens the sign-up and returns the verdict and a single-use `token` (valid for 10 minutes) for `/siteverify`.\n\nThe IP and User-Agent are taken from the request itself, never from the body. Reasons produced by learned signals are shown as one generic line here; `/siteverify` returns them in full.\n\nPer-minute limits: 30 checks per client IP, and your plan's limit per account (300 for test site keys)."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"decision\": \"BLOCKED\",\n  \"riskScore\": 95,\n  \"reasons\": [\n    \"Test mode: block@test.inlineshield.io always gives BLOCKED / block.\"\n  ],\n  \"requestId\": \"AUD-MHH3K33H-5B9D1F3A7C02\",\n  \"token\": \"bst_q3Jm0b8vN2kXo7rT5wYz1cE4hL6pA9sD0fG2jK8uV3i\"\n}"
            },
            {
              "name": "401 invalid",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Origin",
                    "value": "{{origin}}",
                    "description": "Set by the browser. Must be an https or http origin on the site key's list of domains."
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/check",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "check"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"siteKey\": \"{{siteKey}}\",\n  \"email\": \"allow@test.inlineshield.io\",\n  \"clientDwellMs\": 8200\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Called by `inlineshield.js` in the player's browser. Authenticated by the site key in the body and the browser's `Origin`, which must be one of the site key's domains. Screens the sign-up and returns the verdict and a single-use `token` (valid for 10 minutes) for `/siteverify`.\n\nThe IP and User-Agent are taken from the request itself, never from the body. Reasons produced by learned signals are shown as one generic line here; `/siteverify` returns them in full.\n\nPer-minute limits: 30 checks per client IP, and your plan's limit per account (300 for test site keys)."
              },
              "status": "Unauthorized",
              "code": 401,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"error\": \"INVALID_SITE_KEY\",\n  \"message\": \"Unknown or revoked site key.\"\n}"
            },
            {
              "name": "403 origin",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "Origin",
                    "value": "{{origin}}",
                    "description": "Set by the browser. Must be an https or http origin on the site key's list of domains."
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/check",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "check"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"siteKey\": \"{{siteKey}}\",\n  \"email\": \"allow@test.inlineshield.io\",\n  \"clientDwellMs\": 8200\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Called by `inlineshield.js` in the player's browser. Authenticated by the site key in the body and the browser's `Origin`, which must be one of the site key's domains. Screens the sign-up and returns the verdict and a single-use `token` (valid for 10 minutes) for `/siteverify`.\n\nThe IP and User-Agent are taken from the request itself, never from the body. Reasons produced by learned signals are shown as one generic line here; `/siteverify` returns them in full.\n\nPer-minute limits: 30 checks per client IP, and your plan's limit per account (300 for test site keys)."
              },
              "status": "Forbidden",
              "code": 403,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"error\": \"ORIGIN_NOT_ALLOWED\",\n  \"message\": \"Requests from evil.test are not allowed for this site key. Add evil.test to the site's domains.\"\n}"
            }
          ]
        },
        {
          "name": "Redeem a check token",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "X-Api-Key",
                "value": "{{apiKey}}",
                "description": "Your secret API key (collection variable apiKey)."
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/siteverify",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "siteverify"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"token\": \"bst_q3Jm0b8vN2kXo7rT5wYz1cE4hL6pA9sD0fG2jK8uV3i\",\n  \"email\": \"allow@test.inlineshield.io\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Your backend sends the token that `inlineshield.js` put in the form, with the email the player submitted, and gets the decision recorded by `/check`. A token works once, for 10 minutes, for the same email (compared without case or surrounding spaces), and only with a secret key of the same account.\n\nToken problems are answered with HTTP 200 and `success: false`. `QUOTA_EXCEEDED` means the token is missing because the account is over its quota (`/check` issued none). Nothing here counts against the quota.\n\nLimited per API key to the key's own per-minute limit (1,200 for a live key, 300 for a test key, as created)."
          },
          "response": [
            {
              "name": "200 allow",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/siteverify",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "siteverify"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"token\": \"bst_q3Jm0b8vN2kXo7rT5wYz1cE4hL6pA9sD0fG2jK8uV3i\",\n  \"email\": \"allow@test.inlineshield.io\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Your backend sends the token that `inlineshield.js` put in the form, with the email the player submitted, and gets the decision recorded by `/check`. A token works once, for 10 minutes, for the same email (compared without case or surrounding spaces), and only with a secret key of the same account.\n\nToken problems are answered with HTTP 200 and `success: false`. `QUOTA_EXCEEDED` means the token is missing because the account is over its quota (`/check` issued none). Nothing here counts against the quota.\n\nLimited per API key to the key's own per-minute limit (1,200 for a live key, 300 for a test key, as created)."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"success\": true,\n  \"decision\": \"ALLOWED\",\n  \"riskScore\": 0,\n  \"reasons\": [\n    \"Test mode: allow@test.inlineshield.io always gives ALLOWED / allow.\"\n  ],\n  \"requestId\": \"AUD-MHH3K2QZ-4F1C9B2E7D10\",\n  \"action\": \"allow\",\n  \"recommendedAction\": \"allow\"\n}"
            },
            {
              "name": "200 kyc",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/siteverify",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "siteverify"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"token\": \"bst_q3Jm0b8vN2kXo7rT5wYz1cE4hL6pA9sD0fG2jK8uV3i\",\n  \"email\": \"allow@test.inlineshield.io\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Your backend sends the token that `inlineshield.js` put in the form, with the email the player submitted, and gets the decision recorded by `/check`. A token works once, for 10 minutes, for the same email (compared without case or surrounding spaces), and only with a secret key of the same account.\n\nToken problems are answered with HTTP 200 and `success: false`. `QUOTA_EXCEEDED` means the token is missing because the account is over its quota (`/check` issued none). Nothing here counts against the quota.\n\nLimited per API key to the key's own per-minute limit (1,200 for a live key, 300 for a test key, as created)."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"success\": true,\n  \"decision\": \"QUARANTINED\",\n  \"riskScore\": 60,\n  \"reasons\": [\n    \"Test mode: kyc@test.inlineshield.io always gives QUARANTINED / require_kyc.\"\n  ],\n  \"requestId\": \"AUD-MHH3K32F-7E2A4C6B8D90\",\n  \"action\": \"hold\",\n  \"recommendedAction\": \"require_kyc\"\n}"
            },
            {
              "name": "200 noToken",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/siteverify",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "siteverify"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"token\": \"bst_q3Jm0b8vN2kXo7rT5wYz1cE4hL6pA9sD0fG2jK8uV3i\",\n  \"email\": \"allow@test.inlineshield.io\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Your backend sends the token that `inlineshield.js` put in the form, with the email the player submitted, and gets the decision recorded by `/check`. A token works once, for 10 minutes, for the same email (compared without case or surrounding spaces), and only with a secret key of the same account.\n\nToken problems are answered with HTTP 200 and `success: false`. `QUOTA_EXCEEDED` means the token is missing because the account is over its quota (`/check` issued none). Nothing here counts against the quota.\n\nLimited per API key to the key's own per-minute limit (1,200 for a live key, 300 for a test key, as created)."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"success\": false,\n  \"error\": \"NO_TOKEN\"\n}"
            },
            {
              "name": "200 invalidToken",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/siteverify",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "siteverify"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"token\": \"bst_q3Jm0b8vN2kXo7rT5wYz1cE4hL6pA9sD0fG2jK8uV3i\",\n  \"email\": \"allow@test.inlineshield.io\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Your backend sends the token that `inlineshield.js` put in the form, with the email the player submitted, and gets the decision recorded by `/check`. A token works once, for 10 minutes, for the same email (compared without case or surrounding spaces), and only with a secret key of the same account.\n\nToken problems are answered with HTTP 200 and `success: false`. `QUOTA_EXCEEDED` means the token is missing because the account is over its quota (`/check` issued none). Nothing here counts against the quota.\n\nLimited per API key to the key's own per-minute limit (1,200 for a live key, 300 for a test key, as created)."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"success\": false,\n  \"error\": \"INVALID_TOKEN\"\n}"
            },
            {
              "name": "401 missing",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/siteverify",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "siteverify"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"token\": \"bst_q3Jm0b8vN2kXo7rT5wYz1cE4hL6pA9sD0fG2jK8uV3i\",\n  \"email\": \"allow@test.inlineshield.io\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Your backend sends the token that `inlineshield.js` put in the form, with the email the player submitted, and gets the decision recorded by `/check`. A token works once, for 10 minutes, for the same email (compared without case or surrounding spaces), and only with a secret key of the same account.\n\nToken problems are answered with HTTP 200 and `success: false`. `QUOTA_EXCEEDED` means the token is missing because the account is over its quota (`/check` issued none). Nothing here counts against the quota.\n\nLimited per API key to the key's own per-minute limit (1,200 for a live key, 300 for a test key, as created)."
              },
              "status": "Unauthorized",
              "code": 401,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"error\": \"UNAUTHORIZED\",\n  \"message\": \"Access denied: Missing required X-Api-Key header.\"\n}"
            },
            {
              "name": "401 invalid",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/siteverify",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "siteverify"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"token\": \"bst_q3Jm0b8vN2kXo7rT5wYz1cE4hL6pA9sD0fG2jK8uV3i\",\n  \"email\": \"allow@test.inlineshield.io\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Your backend sends the token that `inlineshield.js` put in the form, with the email the player submitted, and gets the decision recorded by `/check`. A token works once, for 10 minutes, for the same email (compared without case or surrounding spaces), and only with a secret key of the same account.\n\nToken problems are answered with HTTP 200 and `success: false`. `QUOTA_EXCEEDED` means the token is missing because the account is over its quota (`/check` issued none). Nothing here counts against the quota.\n\nLimited per API key to the key's own per-minute limit (1,200 for a live key, 300 for a test key, as created)."
              },
              "status": "Unauthorized",
              "code": 401,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"error\": \"INVALID_API_KEY\",\n  \"message\": \"Invalid API key provided.\"\n}"
            },
            {
              "name": "429 rateLimit",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/siteverify",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "siteverify"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"token\": \"bst_q3Jm0b8vN2kXo7rT5wYz1cE4hL6pA9sD0fG2jK8uV3i\",\n  \"email\": \"allow@test.inlineshield.io\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Your backend sends the token that `inlineshield.js` put in the form, with the email the player submitted, and gets the decision recorded by `/check`. A token works once, for 10 minutes, for the same email (compared without case or surrounding spaces), and only with a secret key of the same account.\n\nToken problems are answered with HTTP 200 and `success: false`. `QUOTA_EXCEEDED` means the token is missing because the account is over its quota (`/check` issued none). Nothing here counts against the quota.\n\nLimited per API key to the key's own per-minute limit (1,200 for a live key, 300 for a test key, as created)."
              },
              "status": "Too Many Requests",
              "code": 429,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"error\": \"RATE_LIMIT_EXCEEDED\",\n  \"message\": \"Siteverify rate limit of 1200 req/min exceeded. Try again in 12 seconds.\"\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Reviews",
      "description": "Held sign-ups.",
      "item": [
        {
          "name": "Get a held sign-up's review",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{apiKey}}",
                "description": "Your secret API key (collection variable apiKey)."
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/reviews/:reviewId",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "reviews",
                ":reviewId"
              ],
              "variable": [
                {
                  "key": "reviewId",
                  "value": "rev_Hk3pQ9xZ2mV7cN4bL1kJ8hG5",
                  "description": "The `reviewId` of a held screening."
                }
              ]
            },
            "description": "The status of a held sign-up: `pending` until someone decides it in the console, then `approved` or `rejected`. A review nobody decides is rejected when it expires (`decisionReason: \"expired\"`). Limited to 60 requests per minute per key; not counted against the quota. Test mode creates no reviews."
          },
          "response": [
            {
              "name": "200 pending",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/reviews/:reviewId",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "reviews",
                    ":reviewId"
                  ],
                  "variable": [
                    {
                      "key": "reviewId",
                      "value": "rev_Hk3pQ9xZ2mV7cN4bL1kJ8hG5",
                      "description": "The `reviewId` of a held screening."
                    }
                  ]
                },
                "description": "The status of a held sign-up: `pending` until someone decides it in the console, then `approved` or `rejected`. A review nobody decides is rejected when it expires (`decisionReason: \"expired\"`). Limited to 60 requests per minute per key; not counted against the quota. Test mode creates no reviews."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"reviewId\": \"rev_Hk3pQ9xZ2mV7cN4bL1kJ8hG5\",\n  \"status\": \"pending\",\n  \"decisionReason\": null,\n  \"decidedAt\": null,\n  \"expiresAt\": \"2026-11-09T12:00:00.000Z\"\n}"
            },
            {
              "name": "200 approved",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/reviews/:reviewId",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "reviews",
                    ":reviewId"
                  ],
                  "variable": [
                    {
                      "key": "reviewId",
                      "value": "rev_Hk3pQ9xZ2mV7cN4bL1kJ8hG5",
                      "description": "The `reviewId` of a held screening."
                    }
                  ]
                },
                "description": "The status of a held sign-up: `pending` until someone decides it in the console, then `approved` or `rejected`. A review nobody decides is rejected when it expires (`decisionReason: \"expired\"`). Limited to 60 requests per minute per key; not counted against the quota. Test mode creates no reviews."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"reviewId\": \"rev_Hk3pQ9xZ2mV7cN4bL1kJ8hG5\",\n  \"status\": \"approved\",\n  \"decisionReason\": \"operator\",\n  \"decidedAt\": \"2026-11-02T14:31:07.000Z\",\n  \"expiresAt\": \"2026-11-09T12:00:00.000Z\"\n}"
            },
            {
              "name": "401 missing",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/reviews/:reviewId",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "reviews",
                    ":reviewId"
                  ],
                  "variable": [
                    {
                      "key": "reviewId",
                      "value": "rev_Hk3pQ9xZ2mV7cN4bL1kJ8hG5",
                      "description": "The `reviewId` of a held screening."
                    }
                  ]
                },
                "description": "The status of a held sign-up: `pending` until someone decides it in the console, then `approved` or `rejected`. A review nobody decides is rejected when it expires (`decisionReason: \"expired\"`). Limited to 60 requests per minute per key; not counted against the quota. Test mode creates no reviews."
              },
              "status": "Unauthorized",
              "code": 401,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"error\": \"UNAUTHORIZED\",\n  \"message\": \"Access denied: Missing required X-Api-Key header.\"\n}"
            },
            {
              "name": "401 invalid",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/reviews/:reviewId",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "reviews",
                    ":reviewId"
                  ],
                  "variable": [
                    {
                      "key": "reviewId",
                      "value": "rev_Hk3pQ9xZ2mV7cN4bL1kJ8hG5",
                      "description": "The `reviewId` of a held screening."
                    }
                  ]
                },
                "description": "The status of a held sign-up: `pending` until someone decides it in the console, then `approved` or `rejected`. A review nobody decides is rejected when it expires (`decisionReason: \"expired\"`). Limited to 60 requests per minute per key; not counted against the quota. Test mode creates no reviews."
              },
              "status": "Unauthorized",
              "code": 401,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"error\": \"INVALID_API_KEY\",\n  \"message\": \"Invalid API key provided.\"\n}"
            },
            {
              "name": "404 notFound",
              "originalRequest": {
                "method": "GET",
                "header": [
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/reviews/:reviewId",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "reviews",
                    ":reviewId"
                  ],
                  "variable": [
                    {
                      "key": "reviewId",
                      "value": "rev_Hk3pQ9xZ2mV7cN4bL1kJ8hG5",
                      "description": "The `reviewId` of a held screening."
                    }
                  ]
                },
                "description": "The status of a held sign-up: `pending` until someone decides it in the console, then `approved` or `rejected`. A review nobody decides is rejected when it expires (`decisionReason: \"expired\"`). Limited to 60 requests per minute per key; not counted against the quota. Test mode creates no reviews."
              },
              "status": "Not Found",
              "code": 404,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"error\": \"NOT_FOUND\",\n  \"message\": \"Review not found.\"\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Feedback",
      "description": "Report what a player turned out to be.",
      "item": [
        {
          "name": "Report a screening's outcome",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "X-Api-Key",
                "value": "{{apiKey}}",
                "description": "Your secret API key (collection variable apiKey)."
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/feedback",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "feedback"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"requestId\": \"AUD-MHH3K33H-5B9D1F3A7C02\",\n  \"outcome\": \"fraud\",\n  \"category\": \"bonus_abuse\",\n  \"note\": \"Second account, same payment card.\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Tell InlineShield what a screened player turned out to be (`fraud` or `legit`), by the `requestId` the API returned or by the `/check` token. Accepted for screenings up to 180 days old by `requestId`; a `/check` token is kept for about a day after the screening, so later feedback must use the `requestId`. Sending the same feedback again changes nothing (`changed: false`).\n\nFeedback on a test screening is accepted but never recorded (`changed: false`). Limited per key to your plan's per-minute limit; never counted against the quota and accepted while the account is over it."
          },
          "response": [
            {
              "name": "200 byRequestId",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/feedback",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "feedback"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"requestId\": \"AUD-MHH3K33H-5B9D1F3A7C02\",\n  \"outcome\": \"fraud\",\n  \"category\": \"bonus_abuse\",\n  \"note\": \"Second account, same payment card.\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Tell InlineShield what a screened player turned out to be (`fraud` or `legit`), by the `requestId` the API returned or by the `/check` token. Accepted for screenings up to 180 days old by `requestId`; a `/check` token is kept for about a day after the screening, so later feedback must use the `requestId`. Sending the same feedback again changes nothing (`changed: false`).\n\nFeedback on a test screening is accepted but never recorded (`changed: false`). Limited per key to your plan's per-minute limit; never counted against the quota and accepted while the account is over it."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"success\": true,\n  \"outcome\": \"fraud\",\n  \"category\": \"bonus_abuse\",\n  \"changed\": false\n}"
            },
            {
              "name": "200 byToken",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/feedback",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "feedback"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"requestId\": \"AUD-MHH3K33H-5B9D1F3A7C02\",\n  \"outcome\": \"fraud\",\n  \"category\": \"bonus_abuse\",\n  \"note\": \"Second account, same payment card.\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Tell InlineShield what a screened player turned out to be (`fraud` or `legit`), by the `requestId` the API returned or by the `/check` token. Accepted for screenings up to 180 days old by `requestId`; a `/check` token is kept for about a day after the screening, so later feedback must use the `requestId`. Sending the same feedback again changes nothing (`changed: false`).\n\nFeedback on a test screening is accepted but never recorded (`changed: false`). Limited per key to your plan's per-minute limit; never counted against the quota and accepted while the account is over it."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"success\": true,\n  \"outcome\": \"legit\",\n  \"category\": null,\n  \"changed\": false\n}"
            },
            {
              "name": "401 missing",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/feedback",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "feedback"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"requestId\": \"AUD-MHH3K33H-5B9D1F3A7C02\",\n  \"outcome\": \"fraud\",\n  \"category\": \"bonus_abuse\",\n  \"note\": \"Second account, same payment card.\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Tell InlineShield what a screened player turned out to be (`fraud` or `legit`), by the `requestId` the API returned or by the `/check` token. Accepted for screenings up to 180 days old by `requestId`; a `/check` token is kept for about a day after the screening, so later feedback must use the `requestId`. Sending the same feedback again changes nothing (`changed: false`).\n\nFeedback on a test screening is accepted but never recorded (`changed: false`). Limited per key to your plan's per-minute limit; never counted against the quota and accepted while the account is over it."
              },
              "status": "Unauthorized",
              "code": 401,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"error\": \"UNAUTHORIZED\",\n  \"message\": \"Access denied: Missing required X-Api-Key header.\"\n}"
            },
            {
              "name": "401 invalid",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  },
                  {
                    "key": "X-Api-Key",
                    "value": "{{apiKey}}",
                    "description": "Your secret API key (collection variable apiKey)."
                  }
                ],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/feedback",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "feedback"
                  ]
                },
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"requestId\": \"AUD-MHH3K33H-5B9D1F3A7C02\",\n  \"outcome\": \"fraud\",\n  \"category\": \"bonus_abuse\",\n  \"note\": \"Second account, same payment card.\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                },
                "description": "Tell InlineShield what a screened player turned out to be (`fraud` or `legit`), by the `requestId` the API returned or by the `/check` token. Accepted for screenings up to 180 days old by `requestId`; a `/check` token is kept for about a day after the screening, so later feedback must use the `requestId`. Sending the same feedback again changes nothing (`changed: false`).\n\nFeedback on a test screening is accepted but never recorded (`changed: false`). Limited per key to your plan's per-minute limit; never counted against the quota and accepted while the account is over it."
              },
              "status": "Unauthorized",
              "code": 401,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"error\": \"INVALID_API_KEY\",\n  \"message\": \"Invalid API key provided.\"\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Health",
      "description": "Service status.",
      "item": [
        {
          "name": "Service health",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/health",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "health"
              ]
            },
            "description": "Whether the API and its database are up. No authentication."
          },
          "response": [
            {
              "name": "200 operational",
              "originalRequest": {
                "method": "GET",
                "header": [],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/health",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "health"
                  ]
                },
                "description": "Whether the API and its database are up. No authentication."
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"status\": \"operational\",\n  \"database\": {\n    \"status\": \"connected\"\n  }\n}"
            },
            {
              "name": "503 degraded",
              "originalRequest": {
                "method": "GET",
                "header": [],
                "url": {
                  "raw": "{{baseUrl}}/api/v1/health",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "api",
                    "v1",
                    "health"
                  ]
                },
                "description": "Whether the API and its database are up. No authentication."
              },
              "status": "Service Unavailable",
              "code": 503,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json; charset=utf-8"
                }
              ],
              "body": "{\n  \"status\": \"degraded\",\n  \"database\": {\n    \"status\": \"disconnected\"\n  }\n}"
            }
          ]
        }
      ]
    }
  ],
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://api.inlineshield.io",
      "type": "string"
    },
    {
      "key": "apiKey",
      "value": "",
      "type": "string"
    },
    {
      "key": "siteKey",
      "value": "",
      "type": "string"
    },
    {
      "key": "origin",
      "value": "",
      "type": "string",
      "description": "For /check: an origin on the site key's list of domains, e.g. https://www.example.com."
    }
  ]
}
