> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.withpersona.com/2021-05-14/integration-guide-understanding-a-persona-api-payload/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.withpersona.com/_mcp/server. # Integration Guide: Understanding a Persona API payload > Learn how resources, relationships, and included objects are structured in Persona API responses. Persona's API responses are designed to be comprehensive and consistent. They are inspired by the JSON:API specification, following a normalized structure that separates primary data from related objects. This guide walks you through the anatomy of a typical Persona API payload. The exact payload schema for any object can be found in its API reference. ## Top-Level Structure Every Persona API payload has the same outermost shape: **`json`** ```json json { "data": { ... }, "included": [ ... ] } ``` * `data`: Contains the **primary resource** requested (e.g., an Inquiry, Case, Transaction, etc.) * `included`: Contains a list of fully-expanded **related resources** (e.g an Inquiry’s related Verifications, Account, and/or Case) --- ## Data The `data` object is the focal point of the payload. It represents the main resource returned by the API call and follows the following schema: **`json`** ```json json { "type": "inquiry | case | transaction | account | verification/{verification-type} | report/{report-type}", "id": "inq_aaa | case_bbb | txn_ccc | acct_ddd | ver_eee | rep_fff ", "attributes": { ... }, "relationships": { ... } } ``` **`type`:** A string defining the type of resource. Verification and Report types also specify the sub-type: for example: `verification/government-id` and `report/watchlist` **`id`:** Persona’s globally unique identifier for the resource. ### Attributes All resource-specific information lives in the `attributes` object. This section contains the primary data that describes the object—things like timestamps, status, names, and other core metadata that are **not** relationships or system-generated identifiers. While the exact set of attributes varies by resource type (e.g., `inquiry` vs. `transaction`), many resources share a **common base set** of properties for consistency. #### Shared attributes, common among most resources * `created-at`: ISO 8601 timestamp when the resource was created. * `updated-at`, `completed-at`, or `submitted-at`: Depending on the object type, these indicate state transitions. * `tags`: An array of custom string labels applied to the object. * `reference-id`: A custom identifier provided by your system to map the resource to your internal records (supported on `inquiries`, `transactions`, and `accounts`). #### Examples of resource-specific attributes * `status` indicates state specific to that resource (e.g., `"approved"`, `"ready"`, `"needs-review"`). Each resource uses its own set of statuses. * `files` and `photo-urls` arrays will contain download links to the files processed for `verifications` or `documents` resources * `checks` on verifications will detail exactly why the verification passed or failed * `result` and `run-history` are attributes specific to a report run on an individual or business * `behaviors` contain analytics about how the user interacted with the inquiry flow ### Fields Inquiries, Transactions, Cases, and Accounts all allow for a custom field schema to be configured on each object. Fields are strongly typed and the exact schema will vary depending on the implementation. **`json`** ```json json "attributes": { "status": "approved", "created-at": "2025-05-09T16:51:28.000Z", "fields": { "name-first": { "type": "string", "value": "Alexander" }, "name-last": { "type": "string", "value": "Sample" }, "is-primary-account-holder": { "type": "boolean", "value": true }, "birthdate": { "type": "date", "value": "1990-01-01" }, "jurisdiction": { "type": "choices", "value": "EU" }, "preferred-methods-of-contact": { "type": "multi_choices", "value": [ "text", "email" ] } } } ``` --- ### Relationships The `relationships` object defines foreign-key-style links to other Persona resources. Each object includes the object type as well as its ID. The `data` object within each relationship will be an array if there's a 1:N association between the primary resource and the relation (e.g an inquiry can have multiple verifications). It will be a single object if there’s a 1:1 mapping (e.g an inquiry can only be associated with one account) **`json`** ```json json "relationships": { "account": { "data": { "type": "account", "id": "act_123" } }, "verifications": { "data": [ { "type": "verification/selfie", "id": "ver_abc"}, {"type": "verification/government-id", "id": "ver_def"} ] }, "inquiry-template": { "data": { "type": "inquiry-template", "id": "itmpl_NZXSmP3CCkSX7EK9ub9d6hoXMQ1H" } } } ``` These references are expanded in the `included` array, allowing you to hydrate the full resource tree without additional requests. --- ## Included The `included` array contains full resource objects that correspond to the references in `relationships`. Each entry mirrors the structure of `data`. By default, starting from API version 2025-10-27, the `included` array will be empty unless you explicitly request related resources using the `include` query parameter (e.g., `?include=account,verifications`). For older API versions, some related resources may be included by default. See [Response Body](/response-body#specify-related-resources) for more details. **`json`** ```json json { "type": "account", "id": "act_123", "attributes": { "account-status": "Onboarded", "fields": { "email-address": { "type": "string", "value": "[email protected]" } ... } }, "relationships": { "account-type": { "data": { "type": "account-type", "id": "acttp_456" } } } } ``` --- ### Verifications #### Attributes Verification attributes contain all of the information that was extracted and processed within the verification, along with a `status` attribute of `passed`, `failed`, or `canceled`. Most implementations involving an inquiry template will copy the fields from the last passing verification object to its inquiry fields for ease of access. #### Files The files submitted will be contained in the `photo-urls` array of each verification. You can download the file by making a GET request to the URL provided. For payloads containing multiple verification attempts, make sure you’re fetching the files from a verification with a `passed` status. **`json`** ```json json { "data": {...}, "included": [ { "type": "verification/government-id", "attributes": { "status": "passed", "id-class": "pp", "name-first": "Alexander", "name-last": "Sample", "expiration-date": "2031-01-01", "identification-number": "12345", "checks": [...], "photo-urls": [ { "page": "front", // front of ID "url": "https://files.withpersona.com/dl-front.jpg?access-token=abc", "normalized-url": "https://files.withpersona.com/dl-front.jpg?access-token=def", "original-urls": [ "https://files.withpersona.com/dl-front.heic?access-token=..." ], "byte-size": 196256 }, { "page": "back", // back of ID, if collected ... } ], "selfie-photo": { // The portrait on the ID "url": "https://files.withpersona.com/selfie_photo.jpg?access-token=fhi", ... } } } ] } ``` #### Checks All verification resources will have a `checks` array, detailing the results of each individual verification check. **`json`** ```json json "checks": [ { "name": "document_expired_detection", "status": "passed | failed | not_applicable", "requirement": "required | not_required", "reasons": [], "metadata": {} } ] ``` ### Reports Look at the top level `has-match` attribute to get the current match status of the report. Any current matched results will show up in the `results` array. > **Note** > > As of API version 2025-12-08, report responses no longer include the `run-history` attribute. To retrieve the run history of a report, use the [List Report history](/api-reference/reports/list-report-history) endpoint. **`json`** ```json json "attributes": { "status": "ready", "created-at": "2025-06-10T03:30:13.000Z", "completed-at": "2025-06-10T03:30:13.000Z", "redacted-at": null, "report-template-version-name": "v3", "has-match": true, "is-continuous": false, "is-recurring": false, "tags": [], "query": { "name-first": "Alexander", "name-middle": null, "name-last": "Sample", "term": "Alexander Sample", "birthdate": null, "country-code": null }, "result": [ // All matching results for the search term ], "ignore-list": [] } ``` ## Webhook event payloads A webhook payload will contain the Persona resource with the same schema as defined above within its `payload` object. **`json`** ```json json { "data": { "type": "event", "id": "evt_PrXRyZ6sgM8nmhXiYgxRwAzRQh7n", "attributes": { "name": "inquiry.approved", "payload": { // The inquiry response is contained within this attribute "data": { "type": "inquiry", "id": "inq_xRC9NTj4FkVxgKDmHATNqxGAYXwH", "attributes": {...} }, "included": [ ... ] } } } } ``` ## KYC vs KYB: What top-level resource should I ingest? For KYC, you’ll likely only need to ingest **Inquiry** or **Transaction** payloads and events. All related information like verifications and reports will be contained in the response. For KYB, if you are using multiple inquiry templates (e.g: asking each UBO to verify themselves), you will want to ingest the **Case** payload, which will contain all account, inquiry, report, and verification information from the business *and* the UBOs. ## Appendix ### Statuses for each resource | Object | Possible status values | | ------------------ | ------------------------------------------------------------------------------------------------------------ | | Inquiry | created \| started \| pending \| completed \| failed \| approved \| declined \| expired | | Verification | passed \| failed \| canceled | | Verification check | passed \| failed \| not\_applicable | | Report | pending \| ready \| errored | | Case | Case statuses are customizable and will vary depending on the use case | | Transaction | Transaction statuses are customizable and will vary depending on the use case | | Account | Account statuses are stored in the `account-status` attribute, and will vary depending on the implementation | > Learn how resources, relationships, and included objects are structured in Persona API responses.