{
  "info": {
    "_postman_id": "dp-sandbox-v1",
    "name": "Datapoint Sandbox API",
    "description": "Interactive sandbox for Datapoint Analytics API. All operations return deterministic dummy data — no real PII is submitted or retained.\n\n**Getting started:**\n1. Import this collection and the companion `datapoint-sandbox.postman_environment.json`.\n2. Select the **Datapoint Sandbox** environment.\n3. Run **Auth → Get Sandbox Token** — it will auto-set `{{sandbox_key}}`.\n4. Run any other request.\n\n**Scenario IDs for Instant Check / Client Validation:**\n- `12345678` → Jane Mwangi — PASS (all checks clear)\n- `28944075` → Abdikheir Sheikh — PASS (vehicle check included)\n- `99999999` → Generic — FAIL (identity mismatch)\n- `00000000` → Generic — ESCALATED (manual review)",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{sandbox_key}}",
        "type": "string"
      }
    ]
  },
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "type": "text/javascript",
        "exec": [""]
      }
    },
    {
      "listen": "test",
      "script": {
        "type": "text/javascript",
        "exec": [""]
      }
    }
  ],
  "item": [
    {
      "name": "Auth",
      "item": [
        {
          "name": "Get Sandbox Token",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const json = pm.response.json();",
                  "if (json.token) {",
                  "  pm.environment.set('sandbox_key', json.token);",
                  "  console.log('Sandbox key set:', json.token);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\": \"dev@savannadigital.co.ke\",\n  \"name\": \"Savanna Developer\"\n}"
            },
            "url": {
              "raw": "{{token_url}}",
              "host": ["{{token_url}}"]
            },
            "description": "Exchange your email for a 30-day sandbox bearer token. The test script auto-saves it as `{{sandbox_key}}` so all subsequent requests work immediately."
          }
        }
      ]
    },
    {
      "name": "Identity Verification",
      "item": [
        {
          "name": "Request Verification (B2B)",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"operationName\": \"RequestVerification\",\n  \"query\": \"mutation RequestVerification($input: VerificationRequestInput!) {\\n  requestVerification(input: $input) {\\n    success\\n    message\\n  }\\n}\",\n  \"variables\": {\n    \"input\": {\n      \"requester\": {\n        \"organisation\": \"Savanna Digital Ltd\",\n        \"contactPerson\": \"Wanjiku Maina\",\n        \"email\": \"api@savannadigital.co.ke\",\n        \"telephone\": \"+254712000000\"\n      },\n      \"verification\": {\n        \"category\": \"KYC\",\n        \"requiredTiming\": \"STANDARD\",\n        \"subjectVolume\": \"1-10\",\n        \"scope\": {\n          \"mode\": \"recommended\",\n          \"selectedChecks\": [\"IDENTITY\", \"CRIMINAL_RECORD\"],\n          \"optionalChecks\": null,\n          \"preset\": null,\n          \"customScope\": null\n        },\n        \"additionalDetails\": null,\n        \"decisionSupported\": null\n      },\n      \"authorityConfirmed\": true,\n      \"website\": \"https://savannadigital.co.ke\"\n    }\n  }\n}"
            },
            "url": {
              "raw": "{{base_url}}",
              "host": ["{{base_url}}"]
            },
            "description": "Submit a B2B verification request on behalf of an organisation. Returns a request reference. The sandbox always returns PENDING."
          }
        },
        {
          "name": "Client Validation (KYC — PASS)",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"operationName\": \"ClientValidation\",\n  \"query\": \"mutation ClientValidation($clientValidation: ClientValidationInput!) {\\n  clientValidation(clientValidation: $clientValidation) {\\n    success\\n    message\\n  }\\n}\",\n  \"variables\": {\n    \"clientValidation\": {\n      \"verificationType\": \"INSTANT_CHECK\",\n      \"personalInfo\": {\n        \"firstName\": \"Jane\",\n        \"lastName\": \"Mwangi\",\n        \"phone\": \"254712345678\",\n        \"email\": \"j.mwangi@gmail.com\"\n      },\n      \"identificationInfo\": {\n        \"idNumber\": \"12345678\",\n        \"idFront\": null,\n        \"idBack\": null\n      },\n      \"diditSessionId\": null,\n      \"selfiePhoto\": null,\n      \"criminalVerificationInfo\": null,\n      \"phoneVerificationToken\": null,\n      \"organizationCode\": null,\n      \"consent\": true\n    }\n  }\n}"
            },
            "url": {
              "raw": "{{base_url}}",
              "host": ["{{base_url}}"]
            },
            "description": "Submit KYC subject data. ID `12345678` triggers a PASS scenario — Jane Mwangi, IPRS matched, good conduct clear."
          }
        },
        {
          "name": "Instant Check Request (PASS — vehicle)",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"operationName\": \"InstantCheckRequest\",\n  \"query\": \"mutation InstantCheckRequest($input: InstantCheckRequestInput!) {\\n  instantCheckRequest(input: $input) {\\n    success\\n    message\\n    data { id }\\n  }\\n}\",\n  \"variables\": {\n    \"input\": {\n      \"personalInfo\": {\n        \"firstName\": \"Abdikheir\",\n        \"lastName\": \"Sheikh\",\n        \"phone\": \"254707361705\",\n        \"email\": \"abdikheir.sheikh@gmail.com\"\n      },\n      \"identificationInfo\": {\n        \"idNumber\": \"28944075\",\n        \"idFront\": null,\n        \"idBack\": null\n      },\n      \"selectedChecks\": [\"IDENTITY\", \"NTSA_VEHICLE\"],\n      \"diditSessionId\": null,\n      \"selfiePhoto\": null,\n      \"criminalVerificationInfo\": null,\n      \"phoneNumber\": null,\n      \"phoneVerificationToken\": null,\n      \"organizationCode\": null,\n      \"passportInfo\": null,\n      \"alienIdInfo\": null,\n      \"consent\": true\n    }\n  }\n}"
            },
            "url": {
              "raw": "{{base_url}}",
              "host": ["{{base_url}}"]
            },
            "description": "ID `28944075` returns PASS with vehicle check (NTSA KCB329L). See the certificate request for the full NTSA payload."
          }
        },
        {
          "name": "Instant Check Request (FAIL)",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"operationName\": \"InstantCheckRequest\",\n  \"query\": \"mutation InstantCheckRequest($input: InstantCheckRequestInput!) {\\n  instantCheckRequest(input: $input) {\\n    success\\n    message\\n    data { id }\\n  }\\n}\",\n  \"variables\": {\n    \"input\": {\n      \"personalInfo\": {\n        \"firstName\": \"Test\",\n        \"lastName\": \"Subject\",\n        \"phone\": \"254700000000\",\n        \"email\": \"test.user@sandbox.dp\"\n      },\n      \"identificationInfo\": {\n        \"idNumber\": \"99999999\",\n        \"idFront\": null,\n        \"idBack\": null\n      },\n      \"selectedChecks\": [\"IDENTITY\"],\n      \"diditSessionId\": null,\n      \"selfiePhoto\": null,\n      \"criminalVerificationInfo\": null,\n      \"phoneNumber\": null,\n      \"phoneVerificationToken\": null,\n      \"organizationCode\": null,\n      \"passportInfo\": null,\n      \"alienIdInfo\": null,\n      \"consent\": true\n    }\n  }\n}"
            },
            "url": {
              "raw": "{{base_url}}",
              "host": ["{{base_url}}"]
            },
            "description": "ID `99999999` triggers a FAIL scenario — identity mismatch. Use this to test your error-handling flow."
          }
        },
        {
          "name": "Instant Check Request (ESCALATED)",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"operationName\": \"InstantCheckRequest\",\n  \"query\": \"mutation InstantCheckRequest($input: InstantCheckRequestInput!) {\\n  instantCheckRequest(input: $input) {\\n    success\\n    message\\n    data { id }\\n  }\\n}\",\n  \"variables\": {\n    \"input\": {\n      \"personalInfo\": {\n        \"firstName\": \"Test\",\n        \"lastName\": \"Subject\",\n        \"phone\": \"254700000001\",\n        \"email\": \"escalate.user@sandbox.dp\"\n      },\n      \"identificationInfo\": {\n        \"idNumber\": \"00000000\",\n        \"idFront\": null,\n        \"idBack\": null\n      },\n      \"selectedChecks\": [\"IDENTITY\"],\n      \"diditSessionId\": null,\n      \"selfiePhoto\": null,\n      \"criminalVerificationInfo\": null,\n      \"phoneNumber\": null,\n      \"phoneVerificationToken\": null,\n      \"organizationCode\": null,\n      \"passportInfo\": null,\n      \"alienIdInfo\": null,\n      \"consent\": true\n    }\n  }\n}"
            },
            "url": {
              "raw": "{{base_url}}",
              "host": ["{{base_url}}"]
            },
            "description": "ID `00000000` triggers an ESCALATED scenario — manual review required. Use this to test your escalation UI."
          }
        }
      ]
    },
    {
      "name": "Liveness & Biometrics",
      "item": [
        {
          "name": "Create Didit Session",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"operationName\": \"CreateDiditSession\",\n  \"query\": \"mutation CreateDiditSession($firstName: String, $lastName: String, $email: String, $phone: String, $dateOfBirth: String, $documentNumber: String, $verificationRequestId: String) {\\n  createDiditSession(firstName: $firstName, lastName: $lastName, email: $email, phone: $phone, dateOfBirth: $dateOfBirth, documentNumber: $documentNumber, verificationRequestId: $verificationRequestId) {\\n    sessionRowId\\n    diditSessionId\\n    sessionToken\\n    workflowId\\n    url\\n    status\\n    vendorRef\\n  }\\n}\",\n  \"variables\": {\n    \"firstName\": \"Jane\",\n    \"lastName\": \"Mwangi\",\n    \"email\": \"j.mwangi@gmail.com\",\n    \"phone\": \"254712345678\",\n    \"dateOfBirth\": \"1990-03-14\",\n    \"documentNumber\": \"12345678\",\n    \"verificationRequestId\": null\n  }\n}"
            },
            "url": {
              "raw": "{{base_url}}",
              "host": ["{{base_url}}"]
            },
            "description": "Creates a sandbox liveness session. Returns a fake session URL and token — the URL will not load but the shape mirrors production."
          }
        }
      ]
    },
    {
      "name": "Certificates",
      "item": [
        {
          "name": "Get Certificate by ID (PASS)",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"operationName\": \"CertificateById\",\n  \"query\": \"query CertificateById($certNo: String!) {\\n  certificateById(certNo: $certNo) {\\n    verificationType\\n    certNo\\n    clientEmail\\n    clientName\\n    clientPhone\\n    createdAt\\n    expiresAt\\n    finalOutcome\\n    id\\n    issuedAt\\n    status\\n    checks {\\n      certId\\n      extras\\n      createdAt\\n      documentNo\\n      id\\n      name\\n      result\\n    }\\n  }\\n}\",\n  \"variables\": {\n    \"certNo\": \"DP-SANDBOX-00001\"\n  }\n}"
            },
            "url": {
              "raw": "{{base_url}}",
              "host": ["{{base_url}}"]
            },
            "description": "Fetch a sandbox certificate. Returns Jane Mwangi with IPRS and Good Conduct checks — both PASS. The `extras` field on each check contains the raw source-API payload."
          }
        },
        {
          "name": "Get Certificate by ID (with NTSA vehicle check)",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"operationName\": \"CertificateById\",\n  \"query\": \"query CertificateById($certNo: String!) {\\n  certificateById(certNo: $certNo) {\\n    verificationType\\n    certNo\\n    clientEmail\\n    clientName\\n    clientPhone\\n    createdAt\\n    expiresAt\\n    finalOutcome\\n    id\\n    issuedAt\\n    status\\n    checks {\\n      certId\\n      extras\\n      createdAt\\n      documentNo\\n      id\\n      name\\n      result\\n    }\\n  }\\n}\",\n  \"variables\": {\n    \"certNo\": \"DP-SANDBOX-VEHICLE\"\n  }\n}"
            },
            "url": {
              "raw": "{{base_url}}",
              "host": ["{{base_url}}"]
            },
            "description": "Pass `DP-SANDBOX-VEHICLE` to get a certificate that includes the full NTSA vehicle check (KCB329L, ABDIKHEIR SHEIKH) in the `extras` field."
          }
        },
        {
          "name": "Confirm & Deliver Certificate",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"operationName\": \"ConfirmAndDeliverCertificate\",\n  \"query\": \"mutation ConfirmAndDeliverCertificate($verificationRequestId: String!) {\\n  confirmAndDeliverCertificate(verificationRequestId: $verificationRequestId) {\\n    success\\n    message\\n  }\\n}\",\n  \"variables\": {\n    \"verificationRequestId\": \"req_01SANDBOX0000000\"\n  }\n}"
            },
            "url": {
              "raw": "{{base_url}}",
              "host": ["{{base_url}}"]
            },
            "description": "Confirms and delivers a certificate to the subject. Always returns success in the sandbox."
          }
        },
        {
          "name": "Certificate Subscription (simulated event)",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"operationName\": \"CertificateGeneration\",\n  \"query\": \"subscription CertificateGeneration($verificationRequestId: String!) {\\n  certificate(verificationRequestId: $verificationRequestId) {\\n    status\\n    state\\n    message\\n    data {\\n      fileUrl\\n      verificationRequestId\\n    }\\n  }\\n}\",\n  \"variables\": {\n    \"verificationRequestId\": \"req_01SANDBOX0000000\"\n  }\n}"
            },
            "url": {
              "raw": "{{base_url}}",
              "host": ["{{base_url}}"]
            },
            "description": "Simulates a certificate subscription event. The sandbox returns a single READY event immediately. In production this is a WebSocket subscription."
          }
        }
      ]
    },
    {
      "name": "Payments",
      "item": [
        {
          "name": "Initiate STK Push (M-Pesa)",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"operationName\": \"InitiateStkPush\",\n  \"query\": \"mutation InitiateStkPush($phoneNumber: String!) {\\n  initiateStkPush(phoneNumber: $phoneNumber) {\\n    success\\n    message\\n    data {\\n      merchantRequestID\\n      verificationRequestId\\n    }\\n  }\\n}\",\n  \"variables\": {\n    \"phoneNumber\": \"254712345678\"\n  }\n}"
            },
            "url": {
              "raw": "{{base_url}}",
              "host": ["{{base_url}}"]
            },
            "description": "Initiates a sandbox M-Pesa STK push. Always returns success with a dummy merchant request ID. No real money is moved."
          }
        },
        {
          "name": "M-Pesa Payment Subscription (simulated event)",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"operationName\": \"MpesaPayment\",\n  \"query\": \"subscription MpesaPayment($merchantRequestID: String!) {\\n  mpesaPayment(merchantRequestID: $merchantRequestID) {\\n    status\\n    resultDesc\\n    receiptNumber\\n    amount\\n    merchantRequestID\\n  }\\n}\",\n  \"variables\": {\n    \"merchantRequestID\": \"sandbox-mrq-00000001\"\n  }\n}"
            },
            "url": {
              "raw": "{{base_url}}",
              "host": ["{{base_url}}"]
            },
            "description": "Simulates a settled M-Pesa payment event. Returns SUCCESS immediately. In production this is a WebSocket subscription."
          }
        }
      ]
    },
    {
      "name": "Error scenarios",
      "item": [
        {
          "name": "Unauthorized (no token)",
          "request": {
            "auth": { "type": "noauth" },
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"operationName\": \"RequestVerification\",\n  \"query\": \"mutation RequestVerification($input: VerificationRequestInput!) { requestVerification(input: $input) { success } }\",\n  \"variables\": {}\n}"
            },
            "url": {
              "raw": "{{base_url}}",
              "host": ["{{base_url}}"]
            },
            "description": "Sends a request with no Authorization header. Expect HTTP 401 with an UNAUTHORIZED error."
          }
        }
      ]
    }
  ]
}
