{
  "openapi": "3.1.1",
  "info": {
    "title": "Datasource Wholesale Background Check API",
    "description": "Order and track background checks from your own platform, billed to your account at wholesale prices. You\ncollect each applicant's details and consent in your own flow and send them with the order; we run the check\nand send you signed webhooks as it progresses. Nothing is ever sent to the applicant by us.\n\nFull guide: [/docs/guide.md](https://api.datasourcecorp.app/docs/guide.md) · error catalog:\n[/docs/errors.md](https://api.datasourcecorp.app/docs/errors.md) · for AI agents: [/llms.txt](https://api.datasourcecorp.app/llms.txt)\nand [/llms-full.txt](https://api.datasourcecorp.app/llms-full.txt) (everything in one file).\n\n## How it works (start here)\n| Environment | Base URL | API keys | Checks |\n|---|---|---|---|\n| Test (sandbox) | `https://sandbox.datasourcecorp.app` | `pk_test_...` | Not real; nothing is charged |\n| Production | `https://api.datasourcecorp.app` | `pk_live_...` | Real and billed |\n\n1. `GET /status` with your test key: `200` means it works.\n2. `PUT /settings` with your webhook URL.\n3. `GET /products` for the levels you can order and your prices.\n4. `POST /clients/account/checks/direct` with the applicant's details, a `level` (1 to 6) and your `certification`.\n5. Handle `check.updated` webhooks, and reconcile nightly with `GET /clients/account/checks`.\n\n## Concepts\n- **Account**: yours. Address it as `{clientRef}` `account`. Every check is billed to it.\n- **Sub-account** (optional): created with `POST /clients` to keep one of your customers' checks and portal\n  users apart. Address it by our `clientId` or your `externalClientId`. Still billed to your account.\n- **Check**: one background check for one applicant, with a contract-stable `status` and a finer `stage`.\n  Use `externalIdentifier` (your id, unique across your account and sub-accounts) to match it to your records.\n- **Level**: products are levels 1 to 6 (`GET /products`), priced at your wholesale rates.\n- **Certification**: on every order you certify the permissible purpose, that you gave the applicant the\n  disclosure, and that you have their written authorization.\n\n## Authentication\nSend your API key on every request as `X-Api-Key: <key>` or `Authorization: Bearer <key>`. Keys are issued by\nDatasource, shown once, and belong in a secret manager (never in browser or app code). You can have two active\nkeys, so you can rotate without downtime. Repeated invalid keys from one IP address are answered with\n`429 rate_limited` for a minute; requests with a valid key are never throttled that way.\n\n## Applicant data\nOrders carry Social Security numbers and dates of birth. Send them only from your servers, over TLS (the API\naccepts nothing else), and never log request bodies. We pass them to the screening provider for that order and\nnever store or log them: the SSN is kept only as a keyed one-way hash, to catch duplicate orders. Error\nresponses name the fields that failed and never repeat their values.\n\n## Conventions\n- JSON in and out, camelCase names, UTC ISO 8601 timestamps; dates of birth as `YYYY-MM-DD`.\n- Errors are [RFC 9457 problem details](https://www.rfc-editor.org/rfc/rfc9457) with a stable `code` and a `type`\n  link to its catalog entry. Branch on `code`. Two documented bodies aren't problem details: `409 duplicate_check`\n  (the existing check) and `502` on ordering (the `PENDING` check).\n- Always send an `externalIdentifier` and reuse it on retries: a retry never creates a second check or bill.\n- Ignore fields and webhook events you don't know. Changes are additive; a breaking change gets 90 days' notice\n  in the changelog (`/docs/changelog.md`).\n\n## Compliance\nDatasource is the consumer reporting agency. You are the user of the report: you certify a permissible purpose\non every order, give the applicant a standalone written disclosure and get their written authorization before\nyou order, and make, and are responsible for, every decision based on a report, including the adverse action\nprocess (pre-adverse and adverse action notices).",
    "version": "1.0"
  },
  "servers": [
    {
      "url": "https://api.datasourcecorp.app",
      "description": "Production"
    },
    {
      "url": "https://sandbox.datasourcecorp.app",
      "description": "Test (sandbox)"
    }
  ],
  "paths": {
    "/clients": {
      "post": {
        "tags": [
          "Clients"
        ],
        "summary": "Create a client",
        "description": "Creates a sub-account under your account. You don't need one to order: order on `account`. Use\nsub-accounts to keep one of your customers' checks, reports and portal users apart from the rest. Checks\nordered on a sub-account are billed to your account, at your prices.\n\nA portal login is created for the primary contact, and Datasource emails them their username and a\ntemporary password (changed at first sign-in), so they can read their reports. No password is ever\nreturned to you; `welcomeEmailSent` says whether the email went.\n\nSend your own id for the customer as `externalClientId` and you never have to store ours: every\n`{clientRef}` path accepts it. It is unique among your clients (`409` if already used).",
        "operationId": "CreateClient",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateClientRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "The client was created, with a portal login for its primary contact. The contact gets their username and a temporary password by email from Datasource; no password is ever returned to you. `welcomeEmailSent` is false if that email couldn't be sent (contact support).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateClientResponse"
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: a required field is missing or too long. `errors` names each field. Nothing was created; fix the request and send it again.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#validation_failed",
                      "title": "One or more validation errors occurred.",
                      "status": 400,
                      "errors": {
                        "primaryContactEmail": [
                          "primaryContactEmail is required."
                        ]
                      },
                      "code": "validation_failed"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`invalid_api_key`: the API key is missing, invalid or revoked, or it's a test key on production (or the reverse). Don't retry until the key is fixed.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#invalid_api_key",
                      "title": "Invalid API key",
                      "status": 401,
                      "detail": "The API key is missing, invalid or revoked.",
                      "code": "invalid_api_key"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`external_client_id_in_use`: another of your clients already has this `externalClientId`. Nothing was created; use the existing client (`GET /clients?externalClientId=`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "external_client_id_in_use": {
                    "summary": "external_client_id_in_use",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#external_client_id_in_use",
                      "title": "External client id in use",
                      "status": 409,
                      "detail": "Another of your clients already uses externalClientId 'org-1042'.",
                      "code": "external_client_id_in_use"
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`upstream_unavailable`: the screening provider didn't answer. Nothing was recorded on our side; it's safe to retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "upstream_unavailable": {
                    "summary": "upstream_unavailable",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#upstream_unavailable",
                      "title": "Screening provider unavailable",
                      "status": 502,
                      "detail": "The screening provider did not accept the request. Nothing was created; it is safe to retry.",
                      "code": "upstream_unavailable"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: too many requests with an invalid API key from your IP address. Wait the number of seconds in `Retry-After`. Requests with a valid key are never throttled this way.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#rate_limited",
                      "title": "Too many requests",
                      "status": 429,
                      "detail": "Too many requests with an invalid API key from your IP address. Wait for the number of seconds in the Retry-After header.",
                      "code": "rate_limited"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Clients"
        ],
        "summary": "List clients",
        "description": "Returns your account (`account`, the first item) and every sub-account, oldest first. Pass `externalClientId` to look up one sub-account by your own id: the list then holds that sub-account, or nothing.",
        "operationId": "ListClients",
        "parameters": [
          {
            "name": "externalClientId",
            "in": "query",
            "description": "Return only the client with this `externalClientId` (your own id for the customer, at most 100 characters). The list then has 0 or 1 items.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Your account first, then your sub-accounts, oldest first. With `externalClientId`, a list of 0 or 1 items.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ClientResponse"
                  }
                }
              }
            }
          },
          "401": {
            "description": "`invalid_api_key`: the API key is missing, invalid or revoked, or it's a test key on production (or the reverse). Don't retry until the key is fixed.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#invalid_api_key",
                      "title": "Invalid API key",
                      "status": 401,
                      "detail": "The API key is missing, invalid or revoked.",
                      "code": "invalid_api_key"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: too many requests with an invalid API key from your IP address. Wait the number of seconds in `Retry-After`. Requests with a valid key are never throttled this way.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#rate_limited",
                      "title": "Too many requests",
                      "status": 429,
                      "detail": "Too many requests with an invalid API key from your IP address. Wait for the number of seconds in the Retry-After header.",
                      "code": "rate_limited"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/clients/{clientRef}": {
      "get": {
        "tags": [
          "Clients"
        ],
        "summary": "Get a client",
        "description": "Returns one of your clients.",
        "operationId": "GetClient",
        "parameters": [
          {
            "name": "clientRef",
            "in": "path",
            "description": "Where the check is ordered: `account` (your own account), or a sub-account's `clientId` (`cl_…`) or your `externalClientId` for it. Every check is billed to your account. Anything else is `404 client_not_found`.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The client.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientResponse"
                }
              }
            }
          },
          "401": {
            "description": "`invalid_api_key`: the API key is missing, invalid or revoked, or it's a test key on production (or the reverse). Don't retry until the key is fixed.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#invalid_api_key",
                      "title": "Invalid API key",
                      "status": 401,
                      "detail": "The API key is missing, invalid or revoked.",
                      "code": "invalid_api_key"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`client_not_found`: no client with that `clientId` or `externalClientId` exists under your account. Don't retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "client_not_found": {
                    "summary": "client_not_found",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#client_not_found",
                      "title": "Client not found",
                      "status": 404,
                      "detail": "No client 'org-1042' exists under your account.",
                      "code": "client_not_found"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: too many requests with an invalid API key from your IP address. Wait the number of seconds in `Retry-After`. Requests with a valid key are never throttled this way.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#rate_limited",
                      "title": "Too many requests",
                      "status": 429,
                      "detail": "Too many requests with an invalid API key from your IP address. Wait for the number of seconds in the Retry-After header.",
                      "code": "rate_limited"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/clients/{clientRef}/settings": {
      "get": {
        "tags": [
          "Clients"
        ],
        "summary": "Get a client's settings",
        "description": "Returns the client's own settings and the values that apply to it (its own, else your account's defaults).",
        "operationId": "GetClientSettings",
        "parameters": [
          {
            "name": "clientRef",
            "in": "path",
            "description": "Where the check is ordered: `account` (your own account), or a sub-account's `clientId` (`cl_…`) or your `externalClientId` for it. Every check is billed to your account. Anything else is `404 client_not_found`.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientSettingsResponse"
                }
              }
            }
          },
          "401": {
            "description": "`invalid_api_key`: the API key is missing, invalid or revoked, or it's a test key on production (or the reverse). Don't retry until the key is fixed.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#invalid_api_key",
                      "title": "Invalid API key",
                      "status": 401,
                      "detail": "The API key is missing, invalid or revoked.",
                      "code": "invalid_api_key"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: too many requests with an invalid API key from your IP address. Wait the number of seconds in `Retry-After`. Requests with a valid key are never throttled this way.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#rate_limited",
                      "title": "Too many requests",
                      "status": 429,
                      "detail": "Too many requests with an invalid API key from your IP address. Wait for the number of seconds in the Retry-After header.",
                      "code": "rate_limited"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Clients"
        ],
        "summary": "Update a client's settings",
        "description": "Sets one client's own settings. This call replaces them; send the complete set.\n\n`checkValidityYears` (1 to 5) is how long this client's `CLEAR` or `REVIEW` checks stay valid: their\n`expirationDate` is completion plus that many years, and until then ordering the same applicant again needs\n`forceReorder`. Null or omitted uses your account's default (`checkValidityYears` in `PUT /settings`). A\nchange applies to checks completed after it.",
        "operationId": "UpdateClientSettings",
        "parameters": [
          {
            "name": "clientRef",
            "in": "path",
            "description": "Where the check is ordered: `account` (your own account), or a sub-account's `clientId` (`cl_…`) or your `externalClientId` for it. Every check is billed to your account. Anything else is `404 client_not_found`.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClientSettingsRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientSettingsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "`invalid_api_key`: the API key is missing, invalid or revoked, or it's a test key on production (or the reverse). Don't retry until the key is fixed.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#invalid_api_key",
                      "title": "Invalid API key",
                      "status": 401,
                      "detail": "The API key is missing, invalid or revoked.",
                      "code": "invalid_api_key"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: too many requests with an invalid API key from your IP address. Wait the number of seconds in `Retry-After`. Requests with a valid key are never throttled this way.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#rate_limited",
                      "title": "Too many requests",
                      "status": 429,
                      "detail": "Too many requests with an invalid API key from your IP address. Wait for the number of seconds in the Retry-After header.",
                      "code": "rate_limited"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/products": {
      "get": {
        "tags": [
          "Products"
        ],
        "summary": "List product levels",
        "description": "Returns every product level (1 to 6) you can order, sorted by level, with its name, description and\nbase price. Send the `level` when ordering a check; you never need to know which product that maps to.\nPrices are base prices: third-party fees are added (\"Plus pass-through fees.\"). Fees can differ per\nclient, so use `GET /clients/{clientRef}/products` to show a client's own prices.",
        "operationId": "ListProducts",
        "responses": {
          "200": {
            "description": "Every level, 1 to 6, with its base price from your account's products. Show `feesNote` next to prices.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ProductResponse"
                  }
                }
              }
            }
          },
          "401": {
            "description": "`invalid_api_key`: the API key is missing, invalid or revoked, or it's a test key on production (or the reverse). Don't retry until the key is fixed.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#invalid_api_key",
                      "title": "Invalid API key",
                      "status": 401,
                      "detail": "The API key is missing, invalid or revoked.",
                      "code": "invalid_api_key"
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`upstream_unavailable`: the screening provider didn't answer. Safe to retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "upstream_unavailable": {
                    "summary": "upstream_unavailable",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#upstream_unavailable",
                      "title": "Screening provider unavailable",
                      "status": 502,
                      "detail": "The screening provider did not accept the request. Nothing was created; it is safe to retry.",
                      "code": "upstream_unavailable"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: too many requests with an invalid API key from your IP address. Wait the number of seconds in `Retry-After`. Requests with a valid key are never throttled this way.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#rate_limited",
                      "title": "Too many requests",
                      "status": 429,
                      "detail": "Too many requests with an invalid API key from your IP address. Wait for the number of seconds in the Retry-After header.",
                      "code": "rate_limited"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/clients/{clientRef}/products": {
      "get": {
        "tags": [
          "Products"
        ],
        "summary": "List a client's product levels",
        "description": "Returns the product levels this client can order, priced for this client (fees can differ per client).\nLevels the client doesn't have are left out.",
        "operationId": "ListClientProducts",
        "parameters": [
          {
            "name": "clientRef",
            "in": "path",
            "description": "Where the check is ordered: `account` (your own account), or a sub-account's `clientId` (`cl_…`) or your `externalClientId` for it. Every check is billed to your account. Anything else is `404 client_not_found`.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The levels this client can order, priced for it. Levels it doesn't have are left out.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ProductResponse"
                  }
                }
              }
            }
          },
          "401": {
            "description": "`invalid_api_key`: the API key is missing, invalid or revoked, or it's a test key on production (or the reverse). Don't retry until the key is fixed.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#invalid_api_key",
                      "title": "Invalid API key",
                      "status": 401,
                      "detail": "The API key is missing, invalid or revoked.",
                      "code": "invalid_api_key"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`client_not_found`: no client with that `clientId` or `externalClientId` exists under your account. Don't retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "client_not_found": {
                    "summary": "client_not_found",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#client_not_found",
                      "title": "Client not found",
                      "status": 404,
                      "detail": "No client 'org-1042' exists under your account.",
                      "code": "client_not_found"
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`upstream_unavailable`: the screening provider didn't answer. Safe to retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "upstream_unavailable": {
                    "summary": "upstream_unavailable",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#upstream_unavailable",
                      "title": "Screening provider unavailable",
                      "status": 502,
                      "detail": "The screening provider did not accept the request. Nothing was created; it is safe to retry.",
                      "code": "upstream_unavailable"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: too many requests with an invalid API key from your IP address. Wait the number of seconds in `Retry-After`. Requests with a valid key are never throttled this way.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#rate_limited",
                      "title": "Too many requests",
                      "status": 429,
                      "detail": "Too many requests with an invalid API key from your IP address. Wait for the number of seconds in the Retry-After header.",
                      "code": "rate_limited"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/status": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Check your API key",
        "description": "Returns `200` with a short message when the API key is valid. Useful for verifying setup and key rotation.",
        "operationId": "CheckApiKey",
        "responses": {
          "200": {
            "description": "The key is valid. The body is plain text.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "description": "`invalid_api_key`: the API key is missing, invalid or revoked, or it's a test key on production (or the reverse). Don't retry until the key is fixed.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#invalid_api_key",
                      "title": "Invalid API key",
                      "status": 401,
                      "detail": "The API key is missing, invalid or revoked.",
                      "code": "invalid_api_key"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: too many requests with an invalid API key from your IP address. Wait the number of seconds in `Retry-After`. Requests with a valid key are never throttled this way.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#rate_limited",
                      "title": "Too many requests",
                      "status": 429,
                      "detail": "Too many requests with an invalid API key from your IP address. Wait for the number of seconds in the Retry-After header.",
                      "code": "rate_limited"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/settings": {
      "get": {
        "tags": [
          "Settings"
        ],
        "summary": "Get your settings",
        "description": "Returns the webhook URL and the connect return URLs you registered, and how many years a completed check stays valid.",
        "operationId": "GetSettings",
        "responses": {
          "200": {
            "description": "Your registered webhook URL and connect return URLs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SettingsResponse"
                }
              }
            }
          },
          "401": {
            "description": "`invalid_api_key`: the API key is missing, invalid or revoked, or it's a test key on production (or the reverse). Don't retry until the key is fixed.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#invalid_api_key",
                      "title": "Invalid API key",
                      "status": 401,
                      "detail": "The API key is missing, invalid or revoked.",
                      "code": "invalid_api_key"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: too many requests with an invalid API key from your IP address. Wait the number of seconds in `Retry-After`. Requests with a valid key are never throttled this way.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#rate_limited",
                      "title": "Too many requests",
                      "status": 429,
                      "detail": "Too many requests with an invalid API key from your IP address. Wait for the number of seconds in the Retry-After header.",
                      "code": "rate_limited"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Settings"
        ],
        "summary": "Update your settings",
        "description": "Registers where we send webhooks.\n\n`webhookUrl` must be an https:// URL whose host resolves only to public addresses; it is checked again\nwhenever a webhook is sent. Send an empty `webhookUrl` to stop webhooks (poll instead).\nThis call replaces your settings; send the complete set. (`connectReturnUrls` isn't used by wholesale accounts.)\n\n`checkValidityYears` (1 to 5, default 2) is how long a `CLEAR` or `REVIEW` check stays valid: its\n`expirationDate` is its completion plus that many years, and until then ordering the same applicant\nagain needs `forceReorder`. Omit it to keep the current value. A change applies to checks completed\nafter it.",
        "operationId": "UpdateSettings",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SettingsRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The saved settings. Both values were replaced with what you sent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SettingsResponse"
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: a URL isn't `https://`, has credentials or a fragment, or its host resolves to a private address, or there are more than 10 return URLs. Nothing was changed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#validation_failed",
                      "title": "One or more validation errors occurred.",
                      "status": 400,
                      "errors": {
                        "webhookUrl": [
                          "webhookUrl must use https://."
                        ]
                      },
                      "code": "validation_failed"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`invalid_api_key`: the API key is missing, invalid or revoked, or it's a test key on production (or the reverse). Don't retry until the key is fixed.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#invalid_api_key",
                      "title": "Invalid API key",
                      "status": 401,
                      "detail": "The API key is missing, invalid or revoked.",
                      "code": "invalid_api_key"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: too many requests with an invalid API key from your IP address. Wait the number of seconds in `Retry-After`. Requests with a valid key are never throttled this way.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#rate_limited",
                      "title": "Too many requests",
                      "status": 429,
                      "detail": "Too many requests with an invalid API key from your IP address. Wait for the number of seconds in the Retry-After header.",
                      "code": "rate_limited"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/settings/webhook-secret": {
      "post": {
        "tags": [
          "Settings"
        ],
        "summary": "Rotate your webhook secret",
        "description": "Creates a new webhook signing secret and returns it. **It is shown only once**; store it before switching\nyour signature check over. The old secret stops working immediately, so webhooks sent before you switch\nwill fail verification until you do.",
        "operationId": "RotateWebhookSecret",
        "responses": {
          "200": {
            "description": "The new secret, shown only this once. The old one stopped working immediately.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerWebhookSecretResponse"
                }
              }
            }
          },
          "401": {
            "description": "`invalid_api_key`: the API key is missing, invalid or revoked, or it's a test key on production (or the reverse). Don't retry until the key is fixed.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#invalid_api_key",
                      "title": "Invalid API key",
                      "status": 401,
                      "detail": "The API key is missing, invalid or revoked.",
                      "code": "invalid_api_key"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: too many requests with an invalid API key from your IP address. Wait the number of seconds in `Retry-After`. Requests with a valid key are never throttled this way.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#rate_limited",
                      "title": "Too many requests",
                      "status": 429,
                      "detail": "Too many requests with an invalid API key from your IP address. Wait for the number of seconds in the Retry-After header.",
                      "code": "rate_limited"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/settings/webhook-test": {
      "post": {
        "tags": [
          "Settings"
        ],
        "summary": "Send a test webhook",
        "description": "Sends a signed `ping` event to your webhook URL, so you can verify your endpoint and your signature check.\nDelivery is asynchronous and retried like any other webhook.",
        "operationId": "TestWebhook",
        "responses": {
          "202": {
            "description": "A signed `ping` was queued for delivery to your webhook URL.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookTestResponse"
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: no webhook URL is registered. Register one with `PUT /settings` first.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#validation_failed",
                      "title": "One or more validation errors occurred.",
                      "status": 400,
                      "errors": {
                        "webhookUrl": [
                          "Register a webhookUrl with PUT /settings first."
                        ]
                      },
                      "code": "validation_failed"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`invalid_api_key`: the API key is missing, invalid or revoked, or it's a test key on production (or the reverse). Don't retry until the key is fixed.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#invalid_api_key",
                      "title": "Invalid API key",
                      "status": 401,
                      "detail": "The API key is missing, invalid or revoked.",
                      "code": "invalid_api_key"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: too many requests with an invalid API key from your IP address. Wait the number of seconds in `Retry-After`. Requests with a valid key are never throttled this way.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#rate_limited",
                      "title": "Too many requests",
                      "status": 429,
                      "detail": "Too many requests with an invalid API key from your IP address. Wait for the number of seconds in the Retry-After header.",
                      "code": "rate_limited"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/settings/webhook-deliveries": {
      "get": {
        "tags": [
          "Settings"
        ],
        "summary": "List recent webhook deliveries",
        "description": "Every attempt to deliver a webhook to your endpoint in the last 30 days, newest first: the event, its\n`eventId`, the check (for check events), your endpoint's HTTP status and how long it took. Use it to see\nwhat was sent and how your endpoint answered. Filter with `eventId` or `checkId`; `limit` is 1 to 200\n(default 50). Bodies are never stored, ours or yours: re-send a check's current state with\n`POST /clients/{clientRef}/checks/{checkRef}/replay-webhook`.",
        "operationId": "ListWebhookDeliveries",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Page size, 1 to 500 (larger values are clamped). Defaults to 100.",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            }
          },
          {
            "name": "eventId",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "checkId",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookDeliveryResponse"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "`invalid_api_key`: the API key is missing, invalid or revoked, or it's a test key on production (or the reverse). Don't retry until the key is fixed.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#invalid_api_key",
                      "title": "Invalid API key",
                      "status": 401,
                      "detail": "The API key is missing, invalid or revoked.",
                      "code": "invalid_api_key"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: too many requests with an invalid API key from your IP address. Wait the number of seconds in `Retry-After`. Requests with a valid key are never throttled this way.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#rate_limited",
                      "title": "Too many requests",
                      "status": 429,
                      "detail": "Too many requests with an invalid API key from your IP address. Wait for the number of seconds in the Retry-After header.",
                      "code": "rate_limited"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/clients/{clientRef}/checks/direct": {
      "post": {
        "tags": [
          "Checks"
        ],
        "summary": "Order a background check",
        "description": "Orders a background check with the applicant's full details. Nothing is sent to the applicant: you collect\ntheir details, give them the disclosure and get their written authorization before you order, and certify\nthat you did in `certification`. The details go to the screening provider for this order only; we never\nstore or log them (the SSN is kept only as a keyed one-way hash, to catch duplicate orders).\n\n**Where it's billed.** Order on your own account with `{clientRef}` `account`: every check is billed to you at\nyour wholesale prices. If you created sub-accounts (`POST /clients`) to keep your customers' checks apart,\norder on one with its `clientId` or your `externalClientId`; those checks are billed to you as well.\n\n**What to order.** Send the `level` (1 to 6, see `GET /products`). `422 level_not_available` means the account\ndoesn't have that level (contact support). Levels that include a driving record need `applicant.driversLicense`.\n\n**Job location.** Some levels need `jobLocation` and `stateOfEmployment` (where the applicant will work; send\nboth or neither). They decide which state's rules apply.\n\n**Duplicate protection.** An order is rejected with `409 Conflict` (and nothing is billed) when the same\n`externalIdentifier`, or the same applicant (by SSN) on this account, already has a check that is in progress\n(`PENDING`, `CREATED`) or completed and not yet expired (`CLEAR`, `REVIEW`). Set `forceReorder` to order\nanyway; that is billed as a new check.\n\n**Retries.** Always send an `externalIdentifier`, and reuse it when retrying after a timeout or network\nerror: a retry can never create a second check.\n\n**502 responses.** If submission to the screening provider fails, the check is kept as `PENDING` and returned\nin the body; it resolves on its own (`check.updated` follows). Don't retry with `forceReorder`.",
        "operationId": "OrderDirectCheck",
        "parameters": [
          {
            "name": "clientRef",
            "in": "path",
            "description": "Where the check is ordered: `account` (your own account), or a sub-account's `clientId` (`cl_…`) or your `externalClientId` for it. Every check is billed to your account. Anything else is `404 client_not_found`.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DirectOrderRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "The check was submitted (`status` `CREATED`). Billable. `Location` points at the check. Nothing was sent to the applicant.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckResponse"
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: a field is missing or invalid, or the certification is incomplete. `errors` names each field; it never repeats the values you sent. Nothing was ordered.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#validation_failed",
                      "title": "One or more validation errors occurred.",
                      "status": 400,
                      "errors": {
                        "applicant.ssn": [
                          "applicant.ssn must be a valid 9-digit Social Security number."
                        ]
                      },
                      "code": "validation_failed"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`invalid_api_key`: the API key is missing, invalid or revoked, or it's a test key on production (or the reverse). Don't retry until the key is fixed.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#invalid_api_key",
                      "title": "Invalid API key",
                      "status": 401,
                      "detail": "The API key is missing, invalid or revoked.",
                      "code": "invalid_api_key"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`not_available_for_account_type`: this key belongs to an invitation-based (CHMS) account, which orders with `POST /clients/{clientRef}/checks`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "not_available_for_account_type": {
                    "summary": "not_available_for_account_type",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#not_available_for_account_type",
                      "title": "Not available for your account type",
                      "status": 403,
                      "detail": "This operation is for wholesale accounts.",
                      "code": "not_available_for_account_type"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`client_not_found`: `{clientRef}` isn't `account` or one of your sub-accounts. Don't retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "client_not_found": {
                    "summary": "client_not_found",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#client_not_found",
                      "title": "Client not found",
                      "status": 404,
                      "detail": "No client 'acct-7731' exists under your account.",
                      "code": "client_not_found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Nothing was ordered or billed. Two cases, told apart by `code`: `duplicate_check` (this body: this applicant, matched by SSN, already has a check in progress or unexpired on this account, in `order`), or `external_identifier_in_use` (problem details: the `externalIdentifier` belongs to a check on another of your accounts; use a different one).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderConflictResponse"
                },
                "examples": {
                  "duplicate_check": {
                    "summary": "duplicate_check",
                    "value": {
                      "code": "duplicate_check",
                      "message": "A background check is currently in progress with status 'CREATED'.",
                      "currentStatus": "CREATED",
                      "instructions": "To force a re-order, submit the request with 'forceReorder': true.",
                      "order": {
                        "id": "chk_9c2e4f6a1b3d4e5f8a7b6c5d",
                        "externalIdentifier": "app-20931",
                        "clientId": "cl_7d1a3c5e9b2f4a6c8e0d1b3f",
                        "status": "CREATED",
                        "stage": "in_progress",
                        "level": 2,
                        "expirationDate": null,
                        "completedAt": null,
                        "createdAt": "2026-11-14T15:10:00Z",
                        "updatedAt": "2026-11-14T15:10:01Z"
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "`level_not_available`: the account has no product for that level. Contact support. Nothing was ordered.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "level_not_available": {
                    "summary": "level_not_available",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#level_not_available",
                      "title": "Level not available",
                      "status": 422,
                      "detail": "This client has no product for level 4. Contact support.",
                      "code": "level_not_available"
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "Two cases. If the body is a check (`status` `PENDING`, no `code`), the submission's answer was lost: the check may exist upstream, is kept `PENDING`, and resolves on its own within about an hour (`check.updated` follows). Retry only with the same `externalIdentifier`, never with `forceReorder`. If the body is problem details with `upstream_unavailable`, nothing was created, and a retry is safe.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckResponse"
                },
                "examples": {
                  "pending_check": {
                    "summary": "pending_check",
                    "value": {
                      "id": "chk_9c2e4f6a1b3d4e5f8a7b6c5d",
                      "externalIdentifier": "app-20931",
                      "clientId": "cl_7d1a3c5e9b2f4a6c8e0d1b3f",
                      "status": "PENDING",
                      "stage": "submitting",
                      "level": 2,
                      "expirationDate": null,
                      "completedAt": null,
                      "createdAt": "2026-11-14T15:10:00Z",
                      "updatedAt": "2026-11-14T15:10:00Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: too many requests with an invalid API key from your IP address. Wait the number of seconds in `Retry-After`. Requests with a valid key are never throttled this way.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#rate_limited",
                      "title": "Too many requests",
                      "status": 429,
                      "detail": "Too many requests with an invalid API key from your IP address. Wait for the number of seconds in the Retry-After header.",
                      "code": "rate_limited"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/clients/{clientRef}/checks/{checkRef}": {
      "patch": {
        "tags": [
          "Checks"
        ],
        "summary": "Set your identifier on a check",
        "description": "Sets `externalIdentifier` on a check that doesn't have one yet, so you can link a check (for example one found\nwith `POST /clients/{clientRef}/checks/lookup`) to your own record. `409` if the check already has an\nidentifier, or if another of your checks uses that value. `checkRef` is the check's `id` (`chk_…`).",
        "operationId": "UpdateCheck",
        "parameters": [
          {
            "name": "clientRef",
            "in": "path",
            "description": "Where the check is ordered: `account` (your own account), or a sub-account's `clientId` (`cl_…`) or your `externalClientId` for it. Every check is billed to your account. Anything else is `404 client_not_found`.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "checkRef",
            "in": "path",
            "description": "The check: its `id` (`chk_…`) or your `externalIdentifier`. Resolves only among your own checks (of that client, where the path names one).",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCheckRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The check, now with your `externalIdentifier`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckResponse"
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: `externalIdentifier` is missing or longer than 100 characters.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#validation_failed",
                      "title": "One or more validation errors occurred.",
                      "status": 400,
                      "errors": {
                        "externalIdentifier": [
                          "externalIdentifier is required."
                        ]
                      },
                      "code": "validation_failed"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`invalid_api_key`: the API key is missing, invalid or revoked, or it's a test key on production (or the reverse). Don't retry until the key is fixed.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#invalid_api_key",
                      "title": "Invalid API key",
                      "status": 401,
                      "detail": "The API key is missing, invalid or revoked.",
                      "code": "invalid_api_key"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`client_not_found` or `check_not_found`: the client, or the check within it, doesn't exist under your account. Don't retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "check_not_found": {
                    "summary": "check_not_found",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#check_not_found",
                      "title": "Check not found",
                      "status": 404,
                      "detail": "No check 'vol-8841' exists for client 'org-1042'.",
                      "code": "check_not_found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`external_identifier_in_use`: the check already has an `externalIdentifier` (it can be set once), or another of your checks uses that value. Nothing changed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "external_identifier_in_use": {
                    "summary": "external_identifier_in_use",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#external_identifier_in_use",
                      "title": "External identifier in use",
                      "status": 409,
                      "detail": "Another of your checks already uses that externalIdentifier.",
                      "code": "external_identifier_in_use"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: too many requests with an invalid API key from your IP address. Wait the number of seconds in `Retry-After`. Requests with a valid key are never throttled this way.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#rate_limited",
                      "title": "Too many requests",
                      "status": 429,
                      "detail": "Too many requests with an invalid API key from your IP address. Wait for the number of seconds in the Retry-After header.",
                      "code": "rate_limited"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Checks"
        ],
        "summary": "Get a check",
        "description": "Returns one check. `checkRef` may be the check's `id` (`chk_…`) or your `externalIdentifier`.",
        "operationId": "GetCheck",
        "parameters": [
          {
            "name": "clientRef",
            "in": "path",
            "description": "Where the check is ordered: `account` (your own account), or a sub-account's `clientId` (`cl_…`) or your `externalClientId` for it. Every check is billed to your account. Anything else is `404 client_not_found`.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "checkRef",
            "in": "path",
            "description": "The check: its `id` (`chk_…`) or your `externalIdentifier`. Resolves only among your own checks (of that client, where the path names one).",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The check's current state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckResponse"
                }
              }
            }
          },
          "401": {
            "description": "`invalid_api_key`: the API key is missing, invalid or revoked, or it's a test key on production (or the reverse). Don't retry until the key is fixed.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#invalid_api_key",
                      "title": "Invalid API key",
                      "status": 401,
                      "detail": "The API key is missing, invalid or revoked.",
                      "code": "invalid_api_key"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`client_not_found` or `check_not_found`: the client, or the check within it, doesn't exist under your account. Don't retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "check_not_found": {
                    "summary": "check_not_found",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#check_not_found",
                      "title": "Check not found",
                      "status": 404,
                      "detail": "No check 'vol-8841' exists for client 'org-1042'.",
                      "code": "check_not_found"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: too many requests with an invalid API key from your IP address. Wait the number of seconds in `Retry-After`. Requests with a valid key are never throttled this way.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#rate_limited",
                      "title": "Too many requests",
                      "status": 429,
                      "detail": "Too many requests with an invalid API key from your IP address. Wait for the number of seconds in the Retry-After header.",
                      "code": "rate_limited"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/clients/{clientRef}/checks": {
      "get": {
        "tags": [
          "Checks"
        ],
        "summary": "List checks",
        "description": "Returns a client's checks, oldest change first, one page at a time. Use it for reconciliation, e.g. a\nnightly job that catches any webhook you missed.\n\nPass `updated_since` to get only checks that changed at or after that time, and follow `nextCursor` until it\nis null. A check that changes while you are paging may appear again on a later page, so process items\nidempotently (by `id`).",
        "operationId": "ListChecks",
        "parameters": [
          {
            "name": "clientRef",
            "in": "path",
            "description": "Where the check is ordered: `account` (your own account), or a sub-account's `clientId` (`cl_…`) or your `externalClientId` for it. Every check is billed to your account. Anything else is `404 client_not_found`.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "description": "Only return checks whose `updatedAt` is at or after this time. ISO 8601; a time with no offset is treated as UTC. Omit for all checks.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size, 1 to 500 (larger values are clamped). Defaults to 100.",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "The `nextCursor` from the previous page. Omit for the first page. An unknown value is `400 invalid_cursor`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of the client's checks, oldest change first. Follow `nextCursor` until it is null.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckPage"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_cursor`: `cursor` isn't a `nextCursor` we issued; start again from the first page. (`invalid_json`: `updated_since` or `limit` isn't a valid value.)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                },
                "examples": {
                  "invalid_cursor": {
                    "summary": "invalid_cursor",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#invalid_cursor",
                      "title": "One or more validation errors occurred.",
                      "status": 400,
                      "errors": {
                        "cursor": [
                          "cursor is not valid. Use the nextCursor value from a previous page."
                        ]
                      },
                      "code": "invalid_cursor"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`invalid_api_key`: the API key is missing, invalid or revoked, or it's a test key on production (or the reverse). Don't retry until the key is fixed.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#invalid_api_key",
                      "title": "Invalid API key",
                      "status": 401,
                      "detail": "The API key is missing, invalid or revoked.",
                      "code": "invalid_api_key"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`client_not_found`: no client with that `clientId` or `externalClientId` exists under your account. Don't retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "client_not_found": {
                    "summary": "client_not_found",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#client_not_found",
                      "title": "Client not found",
                      "status": 404,
                      "detail": "No client 'org-1042' exists under your account.",
                      "code": "client_not_found"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: too many requests with an invalid API key from your IP address. Wait the number of seconds in `Retry-After`. Requests with a valid key are never throttled this way.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#rate_limited",
                      "title": "Too many requests",
                      "status": 429,
                      "detail": "Too many requests with an invalid API key from your IP address. Wait for the number of seconds in the Retry-After header.",
                      "code": "rate_limited"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/clients/{clientRef}/checks/{checkRef}/cancel": {
      "post": {
        "tags": [
          "Checks"
        ],
        "summary": "Cancel a check",
        "description": "Cancels a check, e.g. one ordered by mistake. Cancel before the applicant submits their information to avoid\ncharges. `checkRef` may be the check's `id` (`chk_…`) or your `externalIdentifier`.\n\nThe check is marked `CANCELLED` either way. `upstreamCancelled` tells you whether the screening provider\nconfirmed it; if it's false, the check may still be processed, so contact support.",
        "operationId": "CancelCheck",
        "parameters": [
          {
            "name": "clientRef",
            "in": "path",
            "description": "Where the check is ordered: `account` (your own account), or a sub-account's `clientId` (`cl_…`) or your `externalClientId` for it. Every check is billed to your account. Anything else is `404 client_not_found`.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "checkRef",
            "in": "path",
            "description": "The check: its `id` (`chk_…`) or your `externalIdentifier`. Resolves only among your own checks (of that client, where the path names one).",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The check is now `CANCELLED`. If `upstreamCancelled` is false the screening provider didn't confirm it and the check may still be processed and billed: contact support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CancelCheckResponse"
                }
              }
            }
          },
          "401": {
            "description": "`invalid_api_key`: the API key is missing, invalid or revoked, or it's a test key on production (or the reverse). Don't retry until the key is fixed.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#invalid_api_key",
                      "title": "Invalid API key",
                      "status": 401,
                      "detail": "The API key is missing, invalid or revoked.",
                      "code": "invalid_api_key"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`client_not_found` or `check_not_found`: the client, or the check within it, doesn't exist under your account. Don't retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "check_not_found": {
                    "summary": "check_not_found",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#check_not_found",
                      "title": "Check not found",
                      "status": 404,
                      "detail": "No check 'vol-8841' exists for client 'org-1042'.",
                      "code": "check_not_found"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: too many requests with an invalid API key from your IP address. Wait the number of seconds in `Retry-After`. Requests with a valid key are never throttled this way.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#rate_limited",
                      "title": "Too many requests",
                      "status": 429,
                      "detail": "Too many requests with an invalid API key from your IP address. Wait for the number of seconds in the Retry-After header.",
                      "code": "rate_limited"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/clients/{clientRef}/checks/{checkRef}/replay-webhook": {
      "post": {
        "tags": [
          "Checks"
        ],
        "summary": "Re-send a check's webhook",
        "description": "Queues a new delivery of the `check.updated` webhook with the check's current state, e.g. after your endpoint\nwas down. Delivery is asynchronous and retried like any other webhook. `checkRef` may be the check's `id` (`chk_…`) or your `externalIdentifier`.",
        "operationId": "ReplayWebhook",
        "parameters": [
          {
            "name": "clientRef",
            "in": "path",
            "description": "Where the check is ordered: `account` (your own account), or a sub-account's `clientId` (`cl_…`) or your `externalClientId` for it. Every check is billed to your account. Anything else is `404 client_not_found`.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "checkRef",
            "in": "path",
            "description": "The check: its `id` (`chk_…`) or your `externalIdentifier`. Resolves only among your own checks (of that client, where the path names one).",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A new `check.updated` delivery with the check's current state was queued (a new `eventId`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReplayWebhookResponse"
                }
              }
            }
          },
          "401": {
            "description": "`invalid_api_key`: the API key is missing, invalid or revoked, or it's a test key on production (or the reverse). Don't retry until the key is fixed.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#invalid_api_key",
                      "title": "Invalid API key",
                      "status": 401,
                      "detail": "The API key is missing, invalid or revoked.",
                      "code": "invalid_api_key"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`client_not_found` or `check_not_found`: the client, or the check within it, doesn't exist under your account. Don't retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "check_not_found": {
                    "summary": "check_not_found",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#check_not_found",
                      "title": "Check not found",
                      "status": 404,
                      "detail": "No check 'vol-8841' exists for client 'org-1042'.",
                      "code": "check_not_found"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: too many requests with an invalid API key from your IP address. Wait the number of seconds in `Retry-After`. Requests with a valid key are never throttled this way.",
            "content": {
              "application/problem+json": {
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "type": "https://api.datasourcecorp.app/docs/errors.md#rate_limited",
                      "title": "Too many requests",
                      "status": 429,
                      "detail": "Too many requests with an invalid API key from your IP address. Wait for the number of seconds in the Retry-After header.",
                      "code": "rate_limited"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "CancelCheckResponse": {
        "examples": [
          {
            "id": "chk_9c2e4f6a1b3d4e5f8a7b6c5d",
            "externalIdentifier": "vol-8841",
            "clientId": "cl_5b0e6f2a8c1d4e7b9a3f2d6c",
            "status": "CANCELLED",
            "stage": "closed",
            "level": 2,
            "expirationDate": null,
            "completedAt": "2026-10-16T16:00:00Z",
            "createdAt": "2026-10-16T15:10:00Z",
            "updatedAt": "2026-10-16T16:00:00Z",
            "upstreamCancelled": true
          }
        ],
        "type": "object",
        "properties": {
          "upstreamCancelled": {
            "type": "boolean",
            "description": "Whether the cancellation was confirmed by the screening provider. If false, the check is cancelled here but may still be processed and billed; contact support."
          },
          "id": {
            "type": "string",
            "description": "Identifier of the check (`chk_…`). Can be used as `{checkRef}` in paths."
          },
          "externalIdentifier": {
            "type": [
              "null",
              "string"
            ],
            "description": "Your identifier for this check, as sent when ordering. Can be used as `{checkRef}` in paths."
          },
          "clientId": {
            "type": "string",
            "description": "Client the check belongs to (its `clientId`)."
          },
          "status": {
            "enum": [
              "QUEUED",
              "PENDING",
              "CREATED",
              "CLEAR",
              "REVIEW",
              "ERROR",
              "CANCELLED"
            ],
            "type": "string",
            "description": "`QUEUED`: in a batch, not yet submitted. `PENDING`: accepted, being submitted. `CREATED`: submitted; the applicant has been invited to complete their information. `CLEAR`: completed, no search found records. `REVIEW`: completed and flagged (records found, or the result needs a person to look). `ERROR`: could not be completed. `CANCELLED`: cancelled. `CLEAR`, `REVIEW`, `ERROR` and `CANCELLED` are final."
          },
          "stage": {
            "enum": [
              "queued",
              "submitting",
              "awaiting_applicant",
              "applicant_ready",
              "in_progress",
              "complete",
              "closed"
            ],
            "type": "string",
            "description": "Where the check is, finer than `status`: `queued` (in a batch, not yet sent), `submitting` (being sent), `applicant_ready` (held: someone must review and release the order in the Datasource portal, e.g. a possible duplicate or a jurisdiction question), `in_progress` (searches are running), `complete` (final result ready: `CLEAR` or `REVIEW`), `closed` (will not complete: `ERROR` or `CANCELLED`). `applicant_ready` and `in_progress` are both `CREATED`; each move between them sends `check.updated`."
          },
          "level": {
            "maximum": 6,
            "minimum": 1,
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Product level the check was ordered with (1 to 6), or null for a check imported from the account's history.",
            "format": "int32"
          },
          "expirationDate": {
            "type": [
              "null",
              "string"
            ],
            "description": "When a completed check expires (UTC). Until then, re-ordering the same applicant is rejected unless `forceReorder` is set.",
            "format": "date-time"
          },
          "completedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "When the check reached a final status (UTC).",
            "format": "date-time"
          },
          "reportUrl": {
            "type": [
              "null",
              "string"
            ],
            "description": "Only for `CLEAR` and `REVIEW`: the report in the church's Datasource portal. It needs the church's own sign-in. Null otherwise, or while unknown."
          },
          "charges": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Only for a final status: what the screening provider charged for the check, in US dollars. Null while open or unknown.",
            "format": "double"
          },
          "errorCode": {
            "type": [
              "null",
              "string"
            ],
            "description": "Only for `ERROR`: why, as a stable code (`missing_job_location`, `missing_information`, `invalid_applicant_details`, `provider_rejected`, `not_submitted`, `provider_error`, `invitation_expired`; `simulated` in the test environment). Null otherwise."
          },
          "errorMessage": {
            "type": [
              "null",
              "string"
            ],
            "description": "Only for `ERROR`: one sentence for your staff saying what went wrong and what to do. Null otherwise."
          },
          "createdAt": {
            "type": "string",
            "description": "When the check was ordered (UTC).",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "description": "When the check last changed (UTC).",
            "format": "date-time"
          }
        },
        "description": "A cancelled check."
      },
      "CheckExpiringWebhook": {
        "examples": [
          {
            "event": "check.expiring",
            "eventId": "a4c6e8f0-2b4d-4f6a-8c0e-1a3c5e7f9b2d",
            "timestamp": "2028-09-18T14:00:03Z",
            "id": "chk_9c2e4f6a1b3d4e5f8a7b6c5d",
            "externalIdentifier": "vol-8841",
            "clientId": "cl_5b0e6f2a8c1d4e7b9a3f2d6c",
            "status": "CLEAR",
            "expirationDate": "2028-10-18T18:22:41Z",
            "daysLeft": 30
          }
        ],
        "type": "object",
        "properties": {
          "event": {
            "type": "string",
            "description": "Always `check.expiring`."
          },
          "eventId": {
            "type": "string",
            "description": "Unique id of this event, the same on every retry of its delivery. Use it to drop duplicate deliveries."
          },
          "timestamp": {
            "type": "string",
            "description": "When this webhook was generated (UTC).",
            "format": "date-time"
          },
          "id": {
            "type": "string",
            "description": "The check's `id` (`chk_…`)."
          },
          "externalIdentifier": {
            "type": [
              "null",
              "string"
            ],
            "description": "Your identifier for the check, as sent when ordering."
          },
          "clientId": {
            "type": "string",
            "description": "The account or sub-account the check belongs to (`cl_…`)."
          },
          "status": {
            "type": "string",
            "description": "`CLEAR` or `REVIEW`."
          },
          "expirationDate": {
            "type": "string",
            "description": "When the check expires (UTC).",
            "format": "date-time"
          },
          "daysLeft": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Whole days until `expirationDate` (30 or fewer).",
            "format": "int32"
          }
        },
        "description": "Body of the `check.expiring` webhook: a `CLEAR` or `REVIEW` check expires soon. Sent 30 days and 7 days before `expirationDate` (once each)."
      },
      "CheckPage": {
        "examples": [
          {
            "items": [
              {
                "id": "chk_9c2e4f6a1b3d4e5f8a7b6c5d",
                "externalIdentifier": "vol-8841",
                "clientId": "cl_5b0e6f2a8c1d4e7b9a3f2d6c",
                "status": "CLEAR",
                "stage": "complete",
                "level": 2,
                "expirationDate": "2028-10-18T18:22:41Z",
                "completedAt": "2026-10-18T18:22:41Z",
                "createdAt": "2026-10-16T15:10:00Z",
                "updatedAt": "2026-10-18T18:22:41Z"
              }
            ],
            "nextCursor": "NjM4OTYxNjU3NjE0MDAwMDAwOjEwNDI"
          }
        ],
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CheckResponse"
            },
            "description": "Checks on this page."
          },
          "nextCursor": {
            "type": [
              "null",
              "string"
            ],
            "description": "Pass as `cursor` to fetch the next page. Null when there are no more results."
          }
        },
        "description": "One page of checks, ordered by `updatedAt` then `id`."
      },
      "CheckResponse": {
        "examples": [
          {
            "id": "chk_9c2e4f6a1b3d4e5f8a7b6c5d",
            "externalIdentifier": "vol-8841",
            "clientId": "cl_5b0e6f2a8c1d4e7b9a3f2d6c",
            "status": "CREATED",
            "stage": "awaiting_applicant",
            "level": 2,
            "expirationDate": null,
            "completedAt": null,
            "createdAt": "2026-10-16T15:10:00Z",
            "updatedAt": "2026-10-16T15:10:01Z"
          }
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Identifier of the check (`chk_…`). Can be used as `{checkRef}` in paths."
          },
          "externalIdentifier": {
            "type": [
              "null",
              "string"
            ],
            "description": "Your identifier for this check, as sent when ordering. Can be used as `{checkRef}` in paths."
          },
          "clientId": {
            "type": "string",
            "description": "Client the check belongs to (its `clientId`)."
          },
          "status": {
            "enum": [
              "QUEUED",
              "PENDING",
              "CREATED",
              "CLEAR",
              "REVIEW",
              "ERROR",
              "CANCELLED"
            ],
            "type": "string",
            "description": "`QUEUED`: in a batch, not yet submitted. `PENDING`: accepted, being submitted. `CREATED`: submitted; the applicant has been invited to complete their information. `CLEAR`: completed, no search found records. `REVIEW`: completed and flagged (records found, or the result needs a person to look). `ERROR`: could not be completed. `CANCELLED`: cancelled. `CLEAR`, `REVIEW`, `ERROR` and `CANCELLED` are final."
          },
          "stage": {
            "enum": [
              "queued",
              "submitting",
              "awaiting_applicant",
              "applicant_ready",
              "in_progress",
              "complete",
              "closed"
            ],
            "type": "string",
            "description": "Where the check is, finer than `status`: `queued` (in a batch, not yet sent), `submitting` (being sent), `applicant_ready` (held: someone must review and release the order in the Datasource portal, e.g. a possible duplicate or a jurisdiction question), `in_progress` (searches are running), `complete` (final result ready: `CLEAR` or `REVIEW`), `closed` (will not complete: `ERROR` or `CANCELLED`). `applicant_ready` and `in_progress` are both `CREATED`; each move between them sends `check.updated`."
          },
          "level": {
            "maximum": 6,
            "minimum": 1,
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Product level the check was ordered with (1 to 6), or null for a check imported from the account's history.",
            "format": "int32"
          },
          "expirationDate": {
            "type": [
              "null",
              "string"
            ],
            "description": "When a completed check expires (UTC). Until then, re-ordering the same applicant is rejected unless `forceReorder` is set.",
            "format": "date-time"
          },
          "completedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "When the check reached a final status (UTC).",
            "format": "date-time"
          },
          "reportUrl": {
            "type": [
              "null",
              "string"
            ],
            "description": "Only for `CLEAR` and `REVIEW`: the report in the church's Datasource portal. It needs the church's own sign-in. Null otherwise, or while unknown."
          },
          "charges": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Only for a final status: what the screening provider charged for the check, in US dollars. Null while open or unknown.",
            "format": "double"
          },
          "errorCode": {
            "type": [
              "null",
              "string"
            ],
            "description": "Only for `ERROR`: why, as a stable code (`missing_job_location`, `missing_information`, `invalid_applicant_details`, `provider_rejected`, `not_submitted`, `provider_error`, `invitation_expired`; `simulated` in the test environment). Null otherwise."
          },
          "errorMessage": {
            "type": [
              "null",
              "string"
            ],
            "description": "Only for `ERROR`: one sentence for your staff saying what went wrong and what to do. Null otherwise."
          },
          "createdAt": {
            "type": "string",
            "description": "When the check was ordered (UTC).",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "description": "When the check last changed (UTC).",
            "format": "date-time"
          }
        },
        "description": "A background check."
      },
      "ClientResponse": {
        "examples": [
          {
            "clientId": "cl_2e4c6a8b0d1f3e5a7c9b1d3f",
            "externalClientId": "acct-7731",
            "name": "Northwind Staffing - Denver",
            "status": "Active",
            "createdAt": "2026-11-14T15:04:05Z",
            "portalUrl": "https://portal.example.com"
          }
        ],
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "description": "Identifier of the client (`cl_…`). Can be used as `{clientRef}` in the path of every client and check operation."
          },
          "externalClientId": {
            "type": [
              "null",
              "string"
            ],
            "description": "Your own identifier for the client, if you sent one. Can be used as `{clientRef}` in paths."
          },
          "name": {
            "type": [
              "null",
              "string"
            ],
            "description": "The client's display name, if known."
          },
          "status": {
            "type": "string",
            "description": "Client status, e.g. `Active`."
          },
          "createdAt": {
            "type": "string",
            "description": "When the client was created (UTC).",
            "format": "date-time"
          },
          "portalUrl": {
            "type": [
              "null",
              "string"
            ],
            "description": "Where the client's staff sign in to the portal (open it in a new tab; they use their own login). Null if no portal address is configured.",
            "format": "uri"
          }
        },
        "description": "One of your customers, provisioned as a client under your account."
      },
      "ClientSettingsRequest": {
        "type": "object",
        "properties": {
          "checkValidityYears": {
            "maximum": 5,
            "minimum": 1,
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "How many years this client's `CLEAR` or `REVIEW` checks stay valid: their `expirationDate` is completion plus this. A whole number from 1 to 5, or null (or omitted) to use your account's default (`checkValidityYears` in `PUT /settings`). Applies to checks completed after the change.",
            "format": "int32"
          }
        },
        "description": "One client's settings."
      },
      "ClientSettingsResponse": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "description": "The client's `id` (`cl_…`)."
          },
          "checkValidityYears": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "The client's own validity in years, or null if it uses your account's default.",
            "format": "int32"
          },
          "effectiveCheckValidityYears": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "The validity in years that applies to this client: its own, else your account's default.",
            "format": "int32"
          }
        },
        "description": "One client's settings, and the values that apply to it."
      },
      "CreateClientRequest": {
        "examples": [
          {
            "externalClientId": "acct-7731",
            "legalCompanyName": "Northwind Staffing LLC",
            "dbaCompanyName": "Northwind Staffing - Denver",
            "primaryContactFirstName": "Riley",
            "primaryContactLastName": "Chen",
            "primaryContactEmail": "riley.chen@northwind.example",
            "primaryContactPhone": "(303) 555-0142",
            "streetLine1": "1600 Champa St",
            "streetLine2": "Suite 500",
            "city": "Denver",
            "state": "CO",
            "postalCode": "80202",
            "country": "US"
          }
        ],
        "required": [
          "legalCompanyName",
          "primaryContactFirstName",
          "primaryContactLastName",
          "primaryContactEmail",
          "primaryContactPhone",
          "streetLine1",
          "city",
          "state",
          "postalCode"
        ],
        "type": "object",
        "properties": {
          "externalClientId": {
            "maxLength": 100,
            "type": [
              "null",
              "string"
            ],
            "description": "Your own identifier for this customer (max 100 characters, unique among your clients). Lets you address the client by your id instead of ours: use it wherever `{clientRef}` appears."
          },
          "legalCompanyName": {
            "type": "string",
            "description": "Legal registered entity name of the company or organization."
          },
          "dbaCompanyName": {
            "type": [
              "null",
              "string"
            ],
            "description": "Optional 'Doing Business As' (DBA) or trade name."
          },
          "primaryContactFirstName": {
            "type": "string",
            "description": "First name of the primary administrator contact."
          },
          "primaryContactLastName": {
            "type": "string",
            "description": "Last name of the primary administrator contact."
          },
          "primaryContactEmail": {
            "type": "string",
            "description": "Email address of the primary contact. Becomes the username of their portal login.",
            "format": "email"
          },
          "primaryContactPhone": {
            "type": [
              "null",
              "string"
            ],
            "description": "Phone number of the primary contact."
          },
          "companyPhone": {
            "type": [
              "null",
              "string"
            ],
            "description": "Optional main company phone number."
          },
          "streetLine1": {
            "type": "string",
            "description": "Physical street address (line 1)."
          },
          "streetLine2": {
            "type": [
              "null",
              "string"
            ],
            "description": "Optional physical street address (line 2, suite/unit)."
          },
          "city": {
            "type": "string",
            "description": "Physical city."
          },
          "state": {
            "type": "string",
            "description": "State or province: 2-letter code (e.g. `CO`) or full name."
          },
          "postalCode": {
            "type": "string",
            "description": "Physical postal / ZIP code."
          },
          "country": {
            "type": "string",
            "description": "Country code (US or CA). Defaults to `US`."
          },
          "billingStreetLine1": {
            "type": [
              "null",
              "string"
            ],
            "description": "Optional separate billing street address (line 1). If omitted, physical address is used."
          },
          "billingStreetLine2": {
            "type": [
              "null",
              "string"
            ],
            "description": "Optional separate billing street address (line 2)."
          },
          "billingCity": {
            "type": [
              "null",
              "string"
            ],
            "description": "Optional separate billing city."
          },
          "billingState": {
            "type": [
              "null",
              "string"
            ],
            "description": "Optional separate billing state."
          },
          "billingPostalCode": {
            "type": [
              "null",
              "string"
            ],
            "description": "Optional separate billing postal / ZIP code."
          },
          "billingCountry": {
            "type": [
              "null",
              "string"
            ],
            "description": "Optional separate billing country code (defaults to 'US')."
          }
        },
        "description": "Details of the customer to provision as a client under your account. A portal login is created for the primary contact."
      },
      "CreateClientResponse": {
        "examples": [
          {
            "clientId": "cl_2e4c6a8b0d1f3e5a7c9b1d3f",
            "externalClientId": "acct-7731",
            "name": "Northwind Staffing - Denver",
            "status": "ACTIVE",
            "createdAt": "2026-11-14T15:04:05Z",
            "portalUrl": "https://portal.example.com",
            "primaryUsername": "riley.chen@northwind.example",
            "welcomeEmailSent": true
          }
        ],
        "type": "object",
        "properties": {
          "primaryUsername": {
            "type": [
              "null",
              "string"
            ],
            "description": "Username of the portal login created for the primary contact: their email address, or a derived name such as `dana-3f9a1c` if that email is already a login. Null if the login couldn't be created (contact support)."
          },
          "welcomeEmailSent": {
            "type": "boolean",
            "description": "Whether the welcome email with the sign-in details was sent to the primary contact. If false, contact support to re-send it."
          },
          "clientId": {
            "type": "string",
            "description": "Identifier of the client (`cl_…`). Can be used as `{clientRef}` in the path of every client and check operation."
          },
          "externalClientId": {
            "type": [
              "null",
              "string"
            ],
            "description": "Your own identifier for the client, if you sent one. Can be used as `{clientRef}` in paths."
          },
          "name": {
            "type": [
              "null",
              "string"
            ],
            "description": "The client's display name, if known."
          },
          "status": {
            "type": "string",
            "description": "Client status, e.g. `Active`."
          },
          "createdAt": {
            "type": "string",
            "description": "When the client was created (UTC).",
            "format": "date-time"
          },
          "portalUrl": {
            "type": [
              "null",
              "string"
            ],
            "description": "Where the client's staff sign in to the portal (open it in a new tab; they use their own login). Null if no portal address is configured.",
            "format": "uri"
          }
        },
        "description": "A newly created client, with the username of the portal login created for its primary contact. The contact receives their sign-in details (with a temporary password) by email from us; no password is ever returned by the API."
      },
      "DirectAddress": {
        "examples": [
          {
            "street": "1200 Larimer St",
            "street2": "Apt 4",
            "city": "Denver",
            "state": "CO",
            "postalCode": "80202"
          }
        ],
        "required": [
          "street",
          "city",
          "state",
          "postalCode"
        ],
        "type": "object",
        "properties": {
          "street": {
            "maxLength": 100,
            "type": "string",
            "description": "Street address, e.g. `1200 Larimer St`."
          },
          "street2": {
            "maxLength": 100,
            "type": [
              "null",
              "string"
            ],
            "description": "Optional second line, e.g. `Apt 4`."
          },
          "city": {
            "maxLength": 100,
            "type": "string"
          },
          "state": {
            "type": "string",
            "description": "2-letter state code, e.g. `CO`."
          },
          "postalCode": {
            "type": "string",
            "description": "ZIP code: `80202` or `80202-1234`."
          }
        },
        "description": "The applicant's current home address."
      },
      "DirectApplicant": {
        "examples": [
          {
            "firstName": "Jordan",
            "middleName": "Lee",
            "lastName": "Kim",
            "dateOfBirth": "1990-04-12",
            "ssn": "078-05-1120",
            "email": "jordan.kim@example.com",
            "phone": "303-555-0187",
            "address": {
              "street": "1200 Larimer St",
              "street2": "Apt 4",
              "city": "Denver",
              "state": "CO",
              "postalCode": "80202"
            }
          }
        ],
        "required": [
          "firstName",
          "lastName",
          "dateOfBirth",
          "ssn",
          "address"
        ],
        "type": "object",
        "properties": {
          "firstName": {
            "maxLength": 100,
            "type": "string",
            "description": "Legal first name."
          },
          "middleName": {
            "maxLength": 100,
            "type": [
              "null",
              "string"
            ],
            "description": "Middle name. Omit (or send null) if the applicant has none; some searches match on it, so send it whenever there is one."
          },
          "lastName": {
            "maxLength": 100,
            "type": "string",
            "description": "Legal last name."
          },
          "dateOfBirth": {
            "type": "string",
            "description": "Date of birth, `YYYY-MM-DD`. The applicant must be at least 14.",
            "format": "date"
          },
          "ssn": {
            "type": "string",
            "description": "Social Security number: 9 digits, with or without dashes (`123-45-6789` or `123456789`). Used for this order and, as a keyed one-way hash, to detect duplicate orders; never stored or logged."
          },
          "email": {
            "maxLength": 254,
            "type": [
              "null",
              "string"
            ],
            "description": "Optional: the applicant's email address. No invitation is sent to it.",
            "format": "email"
          },
          "phone": {
            "type": [
              "null",
              "string"
            ],
            "description": "Optional: the applicant's phone number, 10-digit US or Canadian in any format. Nothing is sent to it."
          },
          "address": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The applicant's current home address.",
                "$ref": "#/components/schemas/DirectAddress"
              }
            ],
            "description": "The applicant's current home address."
          },
          "driversLicense": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Optional: the applicant's driver's license. Required by levels that include a motor vehicle record.",
                "$ref": "#/components/schemas/DriversLicense"
              }
            ],
            "description": "Optional: the applicant's driver's license. Required by levels that include a motor vehicle record."
          }
        },
        "description": "The applicant's identifying details. Used for this order only; never stored or logged by us."
      },
      "DirectOrderRequest": {
        "examples": [
          {
            "externalIdentifier": "app-20931",
            "level": 2,
            "applicant": {
              "firstName": "Jordan",
              "middleName": "Lee",
              "lastName": "Kim",
              "dateOfBirth": "1990-04-12",
              "ssn": "078-05-1120",
              "email": "jordan.kim@example.com",
              "phone": "303-555-0187",
              "address": {
                "street": "1200 Larimer St",
                "street2": "Apt 4",
                "city": "Denver",
                "state": "CO",
                "postalCode": "80202"
              }
            },
            "certification": {
              "permissiblePurpose": "employment",
              "disclosureProvided": true,
              "authorizationObtained": true
            },
            "jobLocation": "Denver, CO",
            "stateOfEmployment": "CO",
            "orderedBy": {
              "email": "hr@northwind.example",
              "firstName": "Riley",
              "lastName": "Chen"
            },
            "forceReorder": false
          }
        ],
        "required": [
          "level",
          "applicant",
          "certification"
        ],
        "type": "object",
        "properties": {
          "externalIdentifier": {
            "maxLength": 100,
            "type": [
              "null",
              "string"
            ],
            "description": "Your unique identifier for this check (max 100 characters). Strongly recommended: retries with the same value never create a second check, and it is echoed in responses and webhooks."
          },
          "level": {
            "maximum": 6,
            "minimum": 1,
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Product level to order, 1 to 6 (see `GET /products`).",
            "format": "int32"
          },
          "applicant": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The applicant's identifying details. Used for this order only; never stored or logged by us.",
                "$ref": "#/components/schemas/DirectApplicant"
              }
            ],
            "description": "The applicant's identifying details. Used for this order only; never stored or logged by us."
          },
          "certification": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Your certification for this order. Every order needs it; an order without a complete certification is rejected and nothing is billed.",
                "$ref": "#/components/schemas/OrderCertification"
              }
            ],
            "description": "Your certification for this order. Every order needs it; an order without a complete certification is rejected and nothing is billed."
          },
          "jobLocation": {
            "maxLength": 100,
            "type": [
              "null",
              "string"
            ],
            "description": "Where the applicant will work, e.g. `Denver, CO` (at most 100 characters). Some levels require it with `stateOfEmployment`; send both or neither."
          },
          "stateOfEmployment": {
            "type": [
              "null",
              "string"
            ],
            "description": "The US state the applicant will work in (the employment jurisdiction), as a 2-letter code such as `CO`. Send with `jobLocation`."
          },
          "orderedBy": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Optional: who ordered this check. It is written to the order's notes so your staff can see who asked. Never stored by us and never creates a login.",
                "$ref": "#/components/schemas/OrderedBy"
              }
            ],
            "description": "Optional: who ordered this check. It is written to the order's notes so your staff can see who asked. Never stored by us and never creates a login."
          },
          "forceReorder": {
            "type": "boolean",
            "description": "Order even if this applicant (matched by SSN) already has an in-progress or unexpired check. Defaults to false. A forced re-order is billed as a new check."
          }
        },
        "description": "A background check ordered with the applicant's full details. No invitation is sent: you collect the applicant's details, give them the disclosure and get their written authorization before ordering, and certify that you did."
      },
      "DriversLicense": {
        "examples": [
          {
            "number": "123456789",
            "state": "CO"
          }
        ],
        "required": [
          "number",
          "state"
        ],
        "type": "object",
        "properties": {
          "number": {
            "maxLength": 30,
            "type": "string"
          },
          "state": {
            "type": "string",
            "description": "2-letter code of the issuing state, e.g. `CO`."
          }
        },
        "description": "Optional: the applicant's driver's license. Required by levels that include a motor vehicle record."
      },
      "HttpValidationProblemDetails": {
        "examples": [
          {
            "type": "https://api.datasourcecorp.app/docs/errors.md#validation_failed",
            "title": "One or more validation errors occurred.",
            "status": 400,
            "errors": {
              "level": [
                "level is required."
              ]
            },
            "code": "validation_failed"
          }
        ],
        "type": "object",
        "properties": {
          "type": {
            "type": [
              "null",
              "string"
            ]
          },
          "title": {
            "type": [
              "null",
              "string"
            ]
          },
          "status": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "detail": {
            "type": [
              "null",
              "string"
            ]
          },
          "instance": {
            "type": [
              "null",
              "string"
            ]
          },
          "errors": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        }
      },
      "OrderCertification": {
        "examples": [
          {
            "permissiblePurpose": "employment",
            "disclosureProvided": true,
            "authorizationObtained": true
          }
        ],
        "required": [
          "permissiblePurpose"
        ],
        "type": "object",
        "properties": {
          "permissiblePurpose": {
            "enum": [
              "employment",
              "volunteer"
            ],
            "type": "string",
            "description": "Why you are ordering the report: `employment` (hiring, promotion, retention, or a contractor) or `volunteer`."
          },
          "disclosureProvided": {
            "type": "boolean",
            "description": "Must be `true`: before ordering, you gave the applicant a clear written disclosure, in a document by itself, that a background check may be obtained."
          },
          "authorizationObtained": {
            "type": "boolean",
            "description": "Must be `true`: you have the applicant's written authorization to obtain the report, and will keep it."
          },
          "normalizedPurpose": {
            "type": [
              "null",
              "string"
            ]
          }
        },
        "description": "Your certification for this order. Every order needs it; an order without a complete certification is rejected and nothing is billed."
      },
      "OrderConflictResponse": {
        "examples": [
          {
            "code": "duplicate_check",
            "message": "A background check is currently in progress with status 'CREATED'.",
            "currentStatus": "CREATED",
            "instructions": "To force a re-order, submit the request with 'forceReorder': true.",
            "order": {
              "id": "chk_9c2e4f6a1b3d4e5f8a7b6c5d",
              "externalIdentifier": "vol-8841",
              "clientId": "cl_5b0e6f2a8c1d4e7b9a3f2d6c",
              "status": "CREATED",
              "stage": "awaiting_applicant",
              "level": 2,
              "expirationDate": null,
              "completedAt": null,
              "createdAt": "2026-10-16T15:10:00Z",
              "updatedAt": "2026-10-16T15:10:01Z"
            }
          }
        ],
        "type": "object",
        "properties": {
          "code": {
            "enum": [
              "duplicate_check"
            ],
            "type": "string",
            "description": "Always `duplicate_check`: the stable error code (see the error catalog)."
          },
          "message": {
            "type": "string",
            "description": "Why the order was rejected."
          },
          "currentStatus": {
            "enum": [
              "QUEUED",
              "PENDING",
              "CREATED",
              "CLEAR",
              "REVIEW",
              "ERROR",
              "CANCELLED"
            ],
            "type": "string",
            "description": "Status of the existing check."
          },
          "instructions": {
            "type": "string",
            "description": "How to proceed if you do want a new check."
          },
          "order": {
            "description": "The existing check.",
            "$ref": "#/components/schemas/CheckResponse"
          }
        },
        "description": "Returned when the applicant already has an in-progress or unexpired check. No new check was ordered and nothing was billed."
      },
      "OrderedBy": {
        "examples": [
          {
            "email": "hr@northwind.example",
            "firstName": "Riley",
            "lastName": "Chen"
          }
        ],
        "type": "object",
        "properties": {
          "email": {
            "maxLength": 200,
            "type": [
              "null",
              "string"
            ],
            "description": "Email address of the person who ordered the check (optional, at most 200 characters).",
            "format": "email"
          },
          "firstName": {
            "maxLength": 200,
            "type": [
              "null",
              "string"
            ],
            "description": "First name of the person who ordered the check (optional, at most 200 characters)."
          },
          "lastName": {
            "maxLength": 200,
            "type": [
              "null",
              "string"
            ],
            "description": "Last name of the person who ordered the check (optional, at most 200 characters)."
          }
        },
        "description": "Optional: who ordered this check. It is written to the order's notes so your staff can see who asked. Never stored by us and never creates a login."
      },
      "PartnerWebhookSecretResponse": {
        "examples": [
          {
            "webhookSecret": "whsec_YOUR_SECRET"
          }
        ],
        "type": "object",
        "properties": {
          "webhookSecret": {
            "type": "string",
            "description": "The webhook secret (`whsec_...`). Shown only once; store it now."
          }
        },
        "description": "A newly created webhook signing secret. Returned only once."
      },
      "PingWebhook": {
        "examples": [
          {
            "event": "ping",
            "eventId": "f1d3b5a7-9c2e-4d6f-8a0b-3c5e7f9a1b2d",
            "timestamp": "2026-10-16T15:00:00Z"
          }
        ],
        "type": "object",
        "properties": {
          "event": {
            "enum": [
              "ping"
            ],
            "type": "string",
            "description": "Always `ping`."
          },
          "eventId": {
            "type": "string",
            "description": "Unique id of this event, the same on every retry of its delivery. Use it to drop duplicate deliveries.",
            "format": "uuid"
          },
          "timestamp": {
            "type": "string",
            "description": "When this webhook was generated (UTC).",
            "format": "date-time"
          }
        },
        "description": "Body of the `ping` webhook, sent by `POST /settings/webhook-test` so you can verify your endpoint and signature check."
      },
      "ProblemDetails": {
        "examples": [
          {
            "type": "https://api.datasourcecorp.app/docs/errors.md#client_not_found",
            "title": "Client not found",
            "status": 404,
            "detail": "No client 'org-1042' exists under your account.",
            "code": "client_not_found"
          }
        ],
        "type": "object",
        "properties": {
          "type": {
            "type": [
              "null",
              "string"
            ]
          },
          "title": {
            "type": [
              "null",
              "string"
            ]
          },
          "status": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "detail": {
            "type": [
              "null",
              "string"
            ]
          },
          "instance": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "ProductResponse": {
        "examples": [
          {
            "level": 2,
            "name": "Standard",
            "description": "National criminal database, county search, SSN trace.",
            "price": 34.95,
            "feesNote": "Plus pass-through fees."
          }
        ],
        "type": "object",
        "properties": {
          "level": {
            "maximum": 6,
            "minimum": 1,
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "The level, 1 to 6. Send it as `level` when ordering a check.",
            "format": "int32"
          },
          "name": {
            "type": "string",
            "description": "Product name, as Datasource names the package (for example \"Employee - Enhanced Nationwide & US Sex Offender\"). The price is in `price`, not in the name."
          },
          "description": {
            "type": "string",
            "description": "What the level covers."
          },
          "price": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Base price in USD, or null if no price is available for it.",
            "format": "double"
          },
          "feesNote": {
            "enum": [
              "Plus pass-through fees."
            ],
            "type": "string",
            "description": "Always \"Plus pass-through fees.\": third-party fees are added to the base price."
          }
        },
        "description": "A product level you can order: send `level` when ordering a check."
      },
      "ReplayWebhookResponse": {
        "examples": [
          {
            "message": "Webhook replay request accepted",
            "id": "chk_9c2e4f6a1b3d4e5f8a7b6c5d",
            "status": "QUEUED"
          }
        ],
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "description": "Human-readable result."
          },
          "id": {
            "type": "string",
            "description": "The check's `id`."
          },
          "status": {
            "enum": [
              "QUEUED"
            ],
            "type": "string",
            "description": "Always `QUEUED`: delivery happens in the background, with retries."
          }
        },
        "description": "Acknowledgement that a webhook re-delivery was queued."
      },
      "SettingsRequest": {
        "examples": [
          {
            "webhookUrl": "https://app.example.com/cbc/webhooks",
            "connectReturnUrls": [
              "https://app.example.com/cbc/connect-done"
            ]
          }
        ],
        "type": "object",
        "properties": {
          "webhookUrl": {
            "type": [
              "null",
              "string"
            ],
            "description": "https:// URL that receives webhooks. Its host must resolve only to public addresses. Empty or omitted turns webhooks off.",
            "format": "uri"
          },
          "connectReturnUrls": {
            "maxItems": 10,
            "type": [
              "null",
              "array"
            ],
            "items": {
              "type": "string",
              "format": "uri"
            },
            "description": "Not used by wholesale accounts."
          },
          "checkValidityYears": {
            "maximum": 5,
            "minimum": 1,
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Your account's default for how many years a `CLEAR` or `REVIEW` check stays valid: its `expirationDate` is its completion plus this. A whole number from 1 to 5. A client's own setting (`PUT /clients/{clientRef}/settings`) overrides it. Omitted keeps the current value (default 2). Applies to checks completed after the change.",
            "format": "int32"
          }
        },
        "description": "Where we send webhooks and which return URLs the connect page may send a browser back to."
      },
      "SettingsResponse": {
        "examples": [
          {
            "webhookUrl": "https://app.example.com/cbc/webhooks",
            "connectReturnUrls": [
              "https://app.example.com/cbc/connect-done"
            ]
          }
        ],
        "type": "object",
        "properties": {
          "webhookUrl": {
            "type": [
              "null",
              "string"
            ],
            "description": "The URL webhooks are sent to, or null if none is registered.",
            "format": "uri"
          },
          "connectReturnUrls": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri"
            },
            "description": "The return URLs registered for the connect page."
          },
          "checkValidityYears": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Your account's default for how many years a `CLEAR` or `REVIEW` check stays valid (1 to 5), for clients without their own setting.",
            "format": "int32"
          }
        },
        "description": "Your registered webhook URL, connect return URLs and how long completed checks stay valid."
      },
      "UpdateCheckRequest": {
        "examples": [
          {
            "externalIdentifier": "vol-8841"
          }
        ],
        "required": [
          "externalIdentifier"
        ],
        "type": "object",
        "properties": {
          "externalIdentifier": {
            "maxLength": 100,
            "type": [
              "null",
              "string"
            ],
            "description": "Your identifier for the check (max 100 characters). Allowed only while the check has none, and it must be unused by your other checks."
          }
        },
        "description": "Sets your own identifier on a check that doesn't have one yet."
      },
      "WebhookDeliveryResponse": {
        "type": "object",
        "properties": {
          "event": {
            "type": "string",
            "description": "The event, e.g. `check.updated`."
          },
          "eventId": {
            "type": [
              "null",
              "string"
            ],
            "description": "The event's `eventId`, the same on every attempt."
          },
          "checkId": {
            "type": [
              "null",
              "string"
            ],
            "description": "The check's `id` for check events; null for others."
          },
          "attempt": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "1 for the first attempt of this event, then 2, 3... (up to 6: the first try and 5 retries).",
            "format": "int32"
          },
          "attemptedAt": {
            "type": "string",
            "description": "When the attempt was made (UTC).",
            "format": "date-time"
          },
          "statusCode": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Your endpoint's HTTP status, or null if it didn't answer (timeout, connection refused).",
            "format": "int32"
          },
          "succeeded": {
            "type": "boolean",
            "description": "Whether your endpoint answered 2xx."
          },
          "error": {
            "type": [
              "null",
              "string"
            ],
            "description": "For a failed attempt, a short reason (e.g. `HTTP 500`, `timeout`). Your response body is never stored."
          },
          "durationMs": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "How long the attempt took, in milliseconds.",
            "format": "int32"
          }
        },
        "description": "One attempt to deliver a webhook to your endpoint."
      },
      "WebhookPayload": {
        "examples": [
          {
            "event": "check.updated",
            "eventId": "e7a1c3b5-2d4f-4a6b-8c9d-0e1f2a3b4c5d",
            "id": "chk_9c2e4f6a1b3d4e5f8a7b6c5d",
            "externalIdentifier": "vol-8841",
            "clientId": "cl_5b0e6f2a8c1d4e7b9a3f2d6c",
            "status": "CLEAR",
            "stage": "complete",
            "level": 2,
            "expirationDate": "2028-10-18T18:22:41Z",
            "completedAt": "2026-10-18T18:22:41Z",
            "timestamp": "2026-10-18T18:22:42Z"
          }
        ],
        "type": "object",
        "properties": {
          "event": {
            "enum": [
              "check.updated"
            ],
            "type": "string",
            "description": "Event type. Currently always `check.updated`."
          },
          "eventId": {
            "type": "string",
            "description": "Unique id of this event, the same on every retry of its delivery. Use it to drop duplicate deliveries.",
            "format": "uuid"
          },
          "id": {
            "type": "string",
            "description": "Identifier of the check (`chk_…`, same as `id` in API responses)."
          },
          "externalIdentifier": {
            "type": [
              "null",
              "string"
            ],
            "description": "Your identifier for the check, as sent when ordering. The easiest way to match the webhook to your records."
          },
          "clientId": {
            "type": "string",
            "description": "Client the check belongs to (its `clientId`)."
          },
          "status": {
            "enum": [
              "QUEUED",
              "PENDING",
              "CREATED",
              "CLEAR",
              "REVIEW",
              "ERROR",
              "CANCELLED"
            ],
            "type": "string",
            "description": "`QUEUED`: in a batch, not yet submitted. `PENDING`: accepted, being submitted. `CREATED`: submitted; the applicant has been invited to complete their information. `CLEAR`: completed, no search found records. `REVIEW`: completed and flagged (records found, or the result needs a person to look). `ERROR`: could not be completed. `CANCELLED`: cancelled. `CLEAR`, `REVIEW`, `ERROR` and `CANCELLED` are final."
          },
          "stage": {
            "enum": [
              "queued",
              "submitting",
              "awaiting_applicant",
              "applicant_ready",
              "in_progress",
              "complete",
              "closed"
            ],
            "type": "string",
            "description": "Where the check is, finer than `status`: `queued` (in a batch, not yet sent), `submitting` (being sent), `applicant_ready` (held: someone must review and release the order in the Datasource portal, e.g. a possible duplicate or a jurisdiction question), `in_progress` (searches are running), `complete` (final result ready: `CLEAR` or `REVIEW`), `closed` (will not complete: `ERROR` or `CANCELLED`). `applicant_ready` and `in_progress` are both `CREATED`; each move between them sends `check.updated`."
          },
          "level": {
            "maximum": 6,
            "minimum": 1,
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Product level the check was ordered with (1 to 6), or null for a check imported from the account's history.",
            "format": "int32"
          },
          "expirationDate": {
            "type": [
              "null",
              "string"
            ],
            "description": "When a completed check expires (UTC).",
            "format": "date-time"
          },
          "completedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "When the check reached a final status (UTC).",
            "format": "date-time"
          },
          "reportUrl": {
            "type": [
              "null",
              "string"
            ],
            "description": "Only for `CLEAR` and `REVIEW`: the report in the Datasource portal (needs a portal sign-in). Null otherwise."
          },
          "charges": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Only for a final status: what the screening provider charged, in US dollars. Null otherwise.",
            "format": "double"
          },
          "errorCode": {
            "type": [
              "null",
              "string"
            ],
            "description": "Only for `ERROR`: why, as a stable code (see the check's `errorCode`). Null otherwise."
          },
          "errorMessage": {
            "type": [
              "null",
              "string"
            ],
            "description": "Only for `ERROR`: one sentence for your staff saying what went wrong and what to do. Null otherwise."
          },
          "timestamp": {
            "type": "string",
            "description": "When this webhook was generated (UTC). Deliveries can arrive out of order; use the latest `timestamp` per check.",
            "format": "date-time"
          }
        },
        "description": "Body of the `check.updated` webhook, POSTed to your endpoint whenever a check changes status."
      },
      "WebhookTestResponse": {
        "examples": [
          {
            "status": "QUEUED"
          }
        ],
        "type": "object",
        "properties": {
          "status": {
            "enum": [
              "QUEUED"
            ],
            "type": "string",
            "description": "Always `QUEUED`: the `ping` event is delivered in the background, with retries."
          }
        },
        "description": "Acknowledgement that a test webhook was queued."
      }
    },
    "securitySchemes": {
      "ApiKey": {
        "type": "apiKey",
        "description": "Your API key (`pk_live_...` in production, `pk_test_...` in test) in the `X-Api-Key` header.",
        "name": "X-Api-Key",
        "in": "header"
      },
      "Bearer": {
        "type": "http",
        "description": "Alternatively, the same API key as a bearer token: `Authorization: Bearer <key>`.",
        "scheme": "bearer",
        "bearerFormat": "API key"
      }
    }
  },
  "security": [
    {
      "ApiKey": [ ]
    },
    {
      "Bearer": [ ]
    }
  ],
  "tags": [
    {
      "name": "Account",
      "description": "Check that your API key works."
    },
    {
      "name": "Settings",
      "description": "Your webhook URL, your webhook signing secret, and your default check validity."
    },
    {
      "name": "Clients",
      "description": "Your own account (`account`) and any sub-accounts you create to keep your customers' checks apart. Every check is billed to your account."
    },
    {
      "name": "Products",
      "description": "The product levels (1 to 6) you can order, at your wholesale prices."
    },
    {
      "name": "Checks",
      "description": "Order checks with the applicant's full details, then track, cancel and reconcile them."
    }
  ],
  "webhooks": {
    "check.updated": {
      "post": {
        "summary": "Check status changed",
        "description": "Sent to your webhook URL whenever a check changes status (including each step of a batch and automatic\nresolution of a `PENDING` check), and when you call **Re-send a check's webhook**. The payload carries both\n`status` and the finer `stage`.\n\n**Verify every delivery** before trusting it: compute HMAC-SHA256 over the raw request body (the exact bytes you\nreceived, before parsing), keyed with the UTF-8 bytes of your whole webhook secret (`whsec_` prefix included),\nhex-encode it in lowercase, and compare it to the `X-Partner-Signature` header in constant time.\n\n```js\n// Node.js 20+ (rawBody is a Buffer of the exact request body)\nimport crypto from \"node:crypto\";\nconst expected = crypto.createHmac(\"sha256\", process.env.DATASOURCE_WEBHOOK_SECRET).update(rawBody).digest(\"hex\");\nconst given = Buffer.from(req.get(\"X-Partner-Signature\") ?? \"\", \"utf8\");\nconst valid = given.length === expected.length && crypto.timingSafeEqual(given, Buffer.from(expected, \"utf8\"));\n```\n\n```python\n# Python 3\nimport hashlib, hmac, os\nexpected = hmac.new(os.environ[\"DATASOURCE_WEBHOOK_SECRET\"].encode(\"utf-8\"), raw_body, hashlib.sha256).hexdigest()\nvalid = hmac.compare_digest(expected, request.headers.get(\"X-Partner-Signature\", \"\"))\n```\n\n```csharp\n// C#\nvar expected = Convert.ToHexString(HMACSHA256.HashData(Encoding.UTF8.GetBytes(secret), rawBody)).ToLowerInvariant();\nvar valid = CryptographicOperations.FixedTimeEquals(Encoding.UTF8.GetBytes(expected), Encoding.UTF8.GetBytes(signatureHeader ?? \"\"));\n```\n\n**Delivery.** Respond with any `2xx` within 15 seconds; do slow work asynchronously. Anything else is retried up to\n5 more times with increasing delays. Delivery is at least once and not ordered: drop repeats by `eventId` (the same\non every retry of one event), and keep the state with the latest `timestamp` for each check (key checks by `id`).",
        "operationId": "CheckUpdatedWebhook",
        "parameters": [
          {
            "name": "X-Partner-Signature",
            "in": "header",
            "description": "Lowercase hex HMAC-SHA256 of the raw request body, keyed with the UTF-8 bytes of your whole webhook secret (`whsec_` prefix included).",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookPayload"
              },
              "example": {
                "event": "check.updated",
                "eventId": "e7a1c3b5-2d4f-4a6b-8c9d-0e1f2a3b4c5d",
                "id": "chk_9c2e4f6a1b3d4e5f8a7b6c5d",
                "externalIdentifier": "vol-8841",
                "clientId": "cl_5b0e6f2a8c1d4e7b9a3f2d6c",
                "status": "CLEAR",
                "stage": "complete",
                "level": 2,
                "expirationDate": "2028-10-18T18:22:41Z",
                "completedAt": "2026-10-18T18:22:41Z",
                "timestamp": "2026-10-18T18:22:42Z"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges receipt."
          },
          "default": {
            "description": "Anything else, a timeout (15 seconds) or a connection error is retried, up to 5 more times with increasing delays. Redirects are not followed."
          }
        }
      }
    },
    "check.expiring": {
      "post": {
        "summary": "Check expiring soon",
        "description": "Sent 30 days and again 7 days before a `CLEAR` or `REVIEW` check's `expirationDate` (each once; a check found later than 30 days out gets only the 7-day one). Use it to re-screen before the clearance lapses. Same signature, retry and `eventId` rules as `check.updated`.",
        "operationId": "CheckExpiringWebhook",
        "parameters": [
          {
            "name": "X-Partner-Signature",
            "in": "header",
            "description": "Lowercase hex HMAC-SHA256 of the raw request body, keyed with the UTF-8 bytes of your whole webhook secret (`whsec_` prefix included).",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckExpiringWebhook"
              },
              "example": {
                "event": "check.expiring",
                "eventId": "a4c6e8f0-2b4d-4f6a-8c0e-1a3c5e7f9b2d",
                "timestamp": "2028-09-18T14:00:03Z",
                "id": "chk_9c2e4f6a1b3d4e5f8a7b6c5d",
                "externalIdentifier": "vol-8841",
                "clientId": "cl_5b0e6f2a8c1d4e7b9a3f2d6c",
                "status": "CLEAR",
                "expirationDate": "2028-10-18T18:22:41Z",
                "daysLeft": 30
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges receipt."
          },
          "default": {
            "description": "Anything else, a timeout (15 seconds) or a connection error is retried, up to 5 more times with increasing delays. Redirects are not followed."
          }
        }
      }
    },
    "ping": {
      "post": {
        "summary": "Test ping",
        "description": "Sent by `POST /settings/webhook-test` so you can verify your endpoint and your signature check. Same signature, retry and `eventId` rules as `check.updated`.",
        "operationId": "PingWebhook",
        "parameters": [
          {
            "name": "X-Partner-Signature",
            "in": "header",
            "description": "Lowercase hex HMAC-SHA256 of the raw request body, keyed with the UTF-8 bytes of your whole webhook secret (`whsec_` prefix included).",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PingWebhook"
              },
              "example": {
                "event": "ping",
                "eventId": "f1d3b5a7-9c2e-4d6f-8a0b-3c5e7f9a1b2d",
                "timestamp": "2026-10-16T15:00:00Z"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges receipt."
          },
          "default": {
            "description": "Anything else, a timeout (15 seconds) or a connection error is retried, up to 5 more times with increasing delays. Redirects are not followed."
          }
        }
      }
    }
  }
}