# Individual Identity

Run an end-to-end identity verification on a Brazilian individual. Each Individual Identity wraps the proofs (document and/or facial biometrics) that the holder must submit; Stark Infra orchestrates the collection, validates each proof against the bureau provider and delivers the final result through a webhook.

Use Individual Identity to onboard new customers, re-verify existing ones (reboarding) or gate any high-risk operation that requires a fresh proof of life.

The flow is asynchronous: the API returns immediately with the identity in `created` status, and private workers walk it through `processing`, `pending` and finally `success` or `failed`. Every transition produces an `IndividualIdentityLog` that is delivered through the `individual-identity` webhook subscription.

NOTE: Read [Core Concepts](https://docs.starkinfra.com/get-started/core-concepts.md) before continuing this guide.

**RESOURCE SUMMARY**

**Individual Identity**The verification request itself. Holds the holder's data, the proofs requested and the link the holder will use to submit them.**Individual Identity Proof**Each proof required by the identity (one per `proofType`). Generated automatically; submitted via PATCH with the holder's content.

## Available Languages

Code samples on this page are in Python. The same content is available with samples in:

- [Python](https://docs.starkinfra.com/get-started/individual-identity-python.md)
- [Node.js](https://docs.starkinfra.com/get-started/individual-identity-node.md)
- [PHP](https://docs.starkinfra.com/get-started/individual-identity-php.md)
- [Java](https://docs.starkinfra.com/get-started/individual-identity-java.md)
- [Ruby](https://docs.starkinfra.com/get-started/individual-identity-ruby.md)
- [Elixir](https://docs.starkinfra.com/get-started/individual-identity-elixir.md)
- [.NET](https://docs.starkinfra.com/get-started/individual-identity-dotnet.md)
- [Go](https://docs.starkinfra.com/get-started/individual-identity-go.md)
- [Clojure](https://docs.starkinfra.com/get-started/individual-identity-clojure.md)
- [cURL](https://docs.starkinfra.com/get-started/individual-identity-curl.md)

## Setup

For each environment (Sandbox and Production):

1. Create an account at Stark Bank.

2. Get in touch with your account manager to enable Individual Identity on your workspace and to choose which proof types your workspace will require — `identity` (document), `biometric` (facial selfie) or both.

3. Create a [Webhook resource](https://docs.starkinfra.com/api.md#webhook) subscribed to `individual-identity` events to be notified on every state transition (`created` → `processing` → `pending` → `success` / `failed`).

4. Generate your ECDSA credentials by following [How to Create ECDSA Keys](https://docs.starkinfra.com/how-to-create-ecdsa-keys.md) and authenticate every request with the `Access-Id`, `Access-Time` and `Access-Signature` headers.

## Typical flow

**1.** Create an Individual Identity with the holder's `name`, `email`, the list of `proofs` to be collected and the `deliveryMethod`. Stark Infra returns the identity in `created` status, already carrying a `validatorLink` — an URL with the encoded `identityId` that the holder can open to submit each proof.

**2.** If `deliveryMethod = automatic`, Stark Infra sends the `validatorLink` to the holder by e-mail. If `deliveryMethod = manual`, the link is returned in the response and your application is responsible for delivering it (in-app screen, SMS, push, etc.).

**3.** While the holder fills in each proof, Stark Infra creates one `IndividualIdentityProof` per `proofType`. The proofs start in `pending` and move to `processing` once their content is submitted via `PATCH /v2/individual-identity-proof/:id`. The provider validates each proof and the proof transitions to `success` or `failed`.

**4.** When all proofs reach `success`, the identity transitions to `success`. If any proof ends in `failed` or `expired`, the identity transitions to `failed` and the remaining proofs are canceled.

**5.** Every transition produces an `IndividualIdentityLog` entry, delivered in order to your webhook endpoint. React to `success` / `failed` to release the gated operation in your product.

## Use cases

**Onboarding:** validate a new customer's identity (document + biometrics) before opening their account.

**Reboarding:** periodically refresh the identity proofs of long-standing customers to comply with internal KYC policies.

**Step-up authentication:** require a fresh facial biometric before high-value or sensitive operations (large transfers, password reset, device change).

**Embedded validation:** combine `deliveryMethod = manual` with your own in-app UI to walk the holder through proof submission without leaving your product.

## Individual Identity Overview

An Individual Identity represents a single identity verification request for a Brazilian individual. Creating one triggers the asynchronous pipeline that generates the proofs, delivers the `validatorLink` to the holder and ends in `success` or `failed` through the `individual-identity` webhook subscription.

### The Individual Identity Object

**Parameters**

| Name | Type | Description |
| --- | --- | --- |
| `id` | STRING | Unique id for the Individual Identity. |
| `name` | STRING | Full name of the holder being verified. |
| `taxId` | STRING | CPF of the holder, with or without punctuation. Optional at creation; can be patched later. Example: "012.345.678-90". |
| `email` | STRING | E-mail used to deliver the `validatorLink` when `deliveryMethod = automatic`. |
| `phone` | STRING | Holder's phone in international format. Optional. Example: "+5511987654321". |
| `tags` | LIST OF STRINGS | Free-form tags to label the identity for future queries. |
| `proofs` | LIST OF STRINGS | List of proof types required by this identity. Options: `identity` (document), `biometric` (facial selfie). Each item must be enabled on your workspace's Identity Profile. |
| `deliveryMethod` | STRING | How the `validatorLink` reaches the holder. Options: `automatic` (Stark Infra sends an e-mail with the link) and `manual` (the link is returned in the response and your application is responsible for delivering it). |
| `validatorLink` | STRING | URL the holder opens to submit each proof. Carries the `identityId` encoded in the `info` query parameter. Base URL depends on the environment: `starkbank.com` in Production, `sandbox.starkbank.com` in Sandbox. |
| `sourceId` | STRING | Identifier of the entity that triggered this verification. For external callers it is filled automatically with the workspace id and cannot be sent at creation. |
| `sourceType` | STRING | Origin of the verification. Options: `onboarding`, `reboarding` (both reserved for internal callers) and `external` — the value assigned automatically for verifications triggered by your workspace. |
| `workspaceId` | STRING | Id of the workspace that owns this identity. |
| `status` | STRING | Current lifecycle status of the identity. Options: `created`, `processing`, `pending`, `success`, `failed`. |
| `created` | STRING | Creation datetime. Example: "2026-06-23T12:00:00.000000+00:00". |
| `updated` | STRING | Last update datetime. Example: "2026-06-23T12:05:30.000000+00:00". |

### Create Individual Identities

`POST /v2/individual-identity`

Create one or more Individual Identities in batch. Each entry must include at least the holder's `name`, `email`, the `deliveryMethod` and the list of `proofs` to be collected.

Each identity is returned in `created` status, already carrying its `validatorLink`. Save the returned `id` — you'll use it as the path parameter on every subsequent call related to this verification.

**Validations:** the workspace must have an active Identity Profile; every value in `proofs` must be enabled on that profile; `taxId` and `phone`, when sent, must be valid.

**Parameters**

| Name | Required | Description |
| --- | --- | --- |
| `name` | REQUIRED | Full name of the holder being verified. |
| `email` | REQUIRED | E-mail used to deliver the `validatorLink` when `deliveryMethod = automatic`. |
| `deliveryMethod` | REQUIRED | How the `validatorLink` reaches the holder. Options: `automatic`, `manual`. |
| `proofs` | REQUIRED | List of proof types to collect. Each item must be one of `identity`, `biometric` and must be enabled on your workspace's Identity Profile. |
| `taxId` | OPTIONAL | CPF of the holder, with or without punctuation. Validated when sent. Example: "012.345.678-90". |
| `phone` | OPTIONAL | Holder's phone in international format. Example: "+5511987654321". |
| `tags` | OPTIONAL | List of free-form tags to label the identity for future queries. |

**Request**

```python
import starkinfra

identities = starkinfra.individualidentity.create([
    starkinfra.IndividualIdentity(
        name="Daenerys Targaryen Stormborn",
        email="daenerys@example.com",
        delivery_method="automatic",
        proofs=["identity", "biometric"],
        tax_id="012.345.678-90",
        phone="+5511987654321",
        tags=["onboarding-123"]
    )
])

for identity in identities:
    print(identity)
```

**Response**

```python
[
    IndividualIdentity(
        id="5740977003561984",
        name="Daenerys Targaryen Stormborn",
        tax_id="012.345.678-90",
        email="daenerys@example.com",
        phone="+5511987654321",
        tags=["onboarding-123"],
        proofs=["identity", "biometric"],
        delivery_method="automatic",
        validator_link="https://starkbank.com/validator-link?info=eyJpZGVudGl0eUlkIjoiNTc0MDk3NzAwMzU2MTk4NCJ9",
        source_id="6480539068923904",
        source_type="external",
        workspace_id="6480539068923904",
        status="created",
        created="2026-06-23T12:00:00.000000+00:00",
        updated="2026-06-23T12:00:00.000000+00:00"
    )
]
```

### List Individual Identities

`GET /v2/individual-identity`

List and filter the Individual Identities in your workspace. Results are returned paged via cursor; combine filters to narrow the search.

**Parameters**

| Name | Required | Description |
| --- | --- | --- |
| `after` | OPTIONAL | Filter entities created after this date. Format: ISO 8601 or YYYY-MM-DD. |
| `before` | OPTIONAL | Filter entities created before this date. Format: ISO 8601 or YYYY-MM-DD. |
| `cursor` | OPTIONAL | String used to get the next batch of results. Our SDKs handle this for you. |
| `limit` | OPTIONAL | Number of results per cursor. Max = 100. |
| `status` | OPTIONAL | Filter identities by status. Accepts a single value or a comma-separated list. Options: `created`, `processing`, `pending`, `success`, `failed`. |
| `ids` | OPTIONAL | List of strings to get specific identities by ids. When sent, paging is bypassed. |
| `taxIds` | OPTIONAL | List of CPFs to filter the response by. |
| `email` | OPTIONAL | Filter identities by holder e-mail. |
| `tags` | OPTIONAL | Filter entities that contain the specified tags. |

**Request**

```python
import starkinfra

identities = starkinfra.individualidentity.query(
    status=["pending", "success"],
    tags=["onboarding-123"],
    limit=10
)

for identity in identities:
    print(identity)
```

**Response**

```python
[
    IndividualIdentity(
        id="5740977003561984",
        name="Daenerys Targaryen Stormborn",
        tax_id="012.345.678-90",
        status="pending",
        proofs=["identity", "biometric"],
        delivery_method="automatic",
        created="2026-06-23T12:00:00.000000+00:00",
        updated="2026-06-23T12:00:10.000000+00:00"
    )
]
```

### Get an Individual Identity

`GET /v2/individual-identity/:id`

Retrieve a single Individual Identity by its `id`. Use this to inspect the current `status` of the verification.

**Parameters**

| Name | Required | Description |
| --- | --- | --- |
| `id` | REQUIRED | Id returned by `POST /v2/individual-identity`. Sent as the path parameter. |
| `fields` | OPTIONAL | List of strings to filter response JSON keys. Not available in the SDKs. |

**Request**

```python
import starkinfra

identity = starkinfra.individualidentity.get("5740977003561984")
print(identity)
```

**Response**

```python
IndividualIdentity(
    id="5740977003561984",
    name="Daenerys Targaryen Stormborn",
    tax_id="012.345.678-90",
    email="daenerys@example.com",
    phone="+5511987654321",
    tags=["onboarding-123"],
    proofs=["identity", "biometric"],
    delivery_method="automatic",
    validator_link="https://starkbank.com/validator-link?info=eyJpZGVudGl0eUlkIjoiNTc0MDk3NzAwMzU2MTk4NCJ9",
    source_id="6480539068923904",
    source_type="external",
    workspace_id="6480539068923904",
    status="success",
    created="2026-06-23T12:00:00.000000+00:00",
    updated="2026-06-23T12:05:30.000000+00:00"
)
```

### Update an Individual Identity

`PATCH /v2/individual-identity/:id`

Update the `taxId` of an Individual Identity after it has been created. Useful when the CPF is unknown at creation time and is only collected during the proof submission flow.

Other fields of the identity are immutable through this endpoint.

**Parameters**

| Name | Required | Description |
| --- | --- | --- |
| `id` | REQUIRED | Id returned by `POST /v2/individual-identity`. Sent as the path parameter. |
| `taxId` | OPTIONAL | CPF to assign to the identity, with or without punctuation. Validated. |

**Request**

```python
import starkinfra

identity = starkinfra.individualidentity.update(
    id="5740977003561984",
    tax_id="012.345.678-90"
)

print(identity)
```

**Response**

```python
IndividualIdentity(
    id="5740977003561984",
    name="Daenerys Targaryen Stormborn",
    tax_id="012.345.678-90",
    status="pending",
    proofs=["identity", "biometric"],
    delivery_method="automatic",
    created="2026-06-23T12:00:00.000000+00:00",
    updated="2026-06-23T12:02:00.000000+00:00"
)
```

### Cancel an Individual Identity

`DELETE /v2/individual-identity/:id`

Cancel an Individual Identity (soft delete). The identity transitions to `failed`, every pending proof is canceled and a `canceled` log is delivered through the webhook.

**Validations:** the identity must exist, must belong to your workspace and must currently be in `created` or `pending` status. Identities already in `processing`, `success` or `failed` cannot be canceled.

**Parameters**

| Name | Required | Description |
| --- | --- | --- |
| `id` | REQUIRED | Id returned by `POST /v2/individual-identity`. Sent as the path parameter. |

**Request**

```python
import starkinfra

identity = starkinfra.individualidentity.cancel("5740977003561984")
print(identity)
```

**Response**

```python
IndividualIdentity(
    id="5740977003561984",
    name="Daenerys Targaryen Stormborn",
    status="failed",
    proofs=["identity", "biometric"],
    delivery_method="automatic",
    created="2026-06-23T12:00:00.000000+00:00",
    updated="2026-06-23T12:03:00.000000+00:00"
)
```

### List Individual Identity Logs

`GET /v2/individual-identity/log`

Get a paged list of all Individual Identity logs. A log tracks a change in the identity's lifecycle and is the exact payload delivered through the webhook subscription.

**Parameters**

| Name | Required | Description |
| --- | --- | --- |
| `after` | OPTIONAL | Filter entities created after this date. |
| `before` | OPTIONAL | Filter entities created before this date. |
| `cursor` | OPTIONAL | String used to get the next batch of results. Our SDKs handle this for you. |
| `limit` | OPTIONAL | Number of results per cursor. Max = 100. |
| `identityIds` | OPTIONAL | List of Individual Identity ids linked to the desired logs. Max = 100. |
| `types` | OPTIONAL | Filter logs by type. Options: `created`, `processing`, `pending`, `updated`, `success`, `failed`, `canceled`, `expired`. |

**Request**

```python
import starkinfra

logs = starkinfra.individualidentity.log.query(
    types=["success", "failed"],
    identity_ids=["5740977003561984"],
    limit=10
)

for log in logs:
    print(log)
```

**Response**

```python
[
    IndividualIdentityLog(
        id="6661702144623308",
        type="success",
        identity=IndividualIdentity(id="5740977003561984", status="success"),
        errors=[],
        created="2026-06-23T12:05:30.000000+00:00"
    )
]
```

### Get an Individual Identity Log

`GET /v2/individual-identity/log/:id`

Retrieve a single Individual Identity log by its `id`.

**Parameters**

| Name | Required | Description |
| --- | --- | --- |
| `id` | REQUIRED | Id of the Individual Identity log entity. |

**Request**

```python
import starkinfra

log = starkinfra.individualidentity.log.get("6661702144623308")
print(log)
```

**Response**

```python
IndividualIdentityLog(
    id="6661702144623308",
    type="success",
    identity=IndividualIdentity(id="5740977003561984", status="success"),
    errors=[],
    created="2026-06-23T12:05:30.000000+00:00"
)
```

## Individual Identity Proof Overview

Each Individual Identity Proof represents one piece of evidence required by the parent Individual Identity. One proof is generated per `proofType` requested at creation; the holder then submits the content of each proof via `PATCH /v2/individual-identity-proof/:id`.

Proofs go through their own lifecycle (`pending` → `processing` → `success` / `failed` / `canceled` / `expired`). The parent identity transitions to `success` when every proof reaches `success`; it transitions to `failed` as soon as any proof fails or expires.

### The Individual Identity Proof Object

**Parameters**

| Name | Type | Description |
| --- | --- | --- |
| `id` | STRING | Unique id for the Individual Identity Proof. |
| `proofType` | STRING | Type of evidence required by this proof. Options: `identity` (document such as RG or CNH), `biometric` (facial selfie). |
| `metadata` | DICTIONARY | Raw payload returned by the provider after the proof is validated. Empty (`{}`) until the proof reaches `processing`. |
| `status` | STRING | Current lifecycle status of the proof. Options: `pending`, `processing`, `success`, `failed`, `canceled`, `expired`. |
| `individualIdentityId` | STRING | Id of the parent Individual Identity this proof belongs to. |
| `created` | STRING | Creation datetime. Example: "2026-06-23T12:00:10.000000+00:00". |
| `updated` | STRING | Last update datetime. Example: "2026-06-23T12:03:00.000000+00:00". |

### List Individual Identity Proofs

`GET /v2/individual-identity-proof`

List the proofs tied to an Individual Identity. The `identityId` query parameter is required — proofs are always scoped to a parent identity.

**Parameters**

| Name | Required | Description |
| --- | --- | --- |
| `identityId` | REQUIRED | Id of the parent Individual Identity whose proofs you want to list. |
| `status` | OPTIONAL | Filter proofs by status. Accepts a single value or a comma-separated list. |
| `proofType` | OPTIONAL | Filter proofs by `proofType`. Options: `identity`, `biometric`. |
| `ids` | OPTIONAL | List of strings to get specific proofs by ids. |
| `after` | OPTIONAL | Filter proofs created after this date. |
| `before` | OPTIONAL | Filter proofs created before this date. |
| `cursor` | OPTIONAL | String used to get the next batch of results. |
| `limit` | OPTIONAL | Number of results per cursor. Max = 100. |

**Request**

```python
import starkinfra

proofs = starkinfra.request.get(
    path="/individual-identity-proof",
    query={
        "identityId": "5740977003561984",
        "status": ["pending", "processing"],
        "limit": 10
    }
).json()

print(proofs)
```

**Response**

```python
{
    'cursor': None,
    'proofs': [
        {
            'id': '4512334302912512',
            'proofType': 'biometric',
            'metadata': {},
            'status': 'pending',
            'individualIdentityId': '5740977003561984',
            'created': '2026-06-23T12:00:10.000000+00:00',
            'updated': '2026-06-23T12:00:10.000000+00:00'
        }
    ]
}
```

### Get an Individual Identity Proof

`GET /v2/individual-identity-proof/:id`

Retrieve a single Individual Identity Proof by its `id`. Inspect the `status` and, once validation completes, the `metadata` dictionary returned by the provider.

**Parameters**

| Name | Required | Description |
| --- | --- | --- |
| `id` | REQUIRED | Id of the Individual Identity Proof. Sent as the path parameter. |
| `fields` | OPTIONAL | List of strings to filter response JSON keys. Not available in the SDKs. |

**Request**

```python
import starkinfra

proof = starkinfra.request.get(
    path="/individual-identity-proof/4512334302912512"
).json()

print(proof)
```

**Response**

```python
{
    'proof': {
        'id': '4512334302912512',
        'proofType': 'identity',
        'metadata': {'documentId': 'doc-abc-123', 'documentType': 'RG'},
        'status': 'success',
        'individualIdentityId': '5740977003561984',
        'created': '2026-06-23T12:00:10.000000+00:00',
        'updated': '2026-06-23T12:03:00.000000+00:00'
    }
}
```

### Submit an Individual Identity Proof

`PATCH /v2/individual-identity-proof/:id`

Submit the content of a proof. This is the step in which the holder's document or biometric is uploaded for validation.

The shape of the `content` field depends on the `proofType`:

**biometric** — `content` is a base64 image string with the facial selfie. Example: `"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ..."`.

**identity** — `content` is a JSON-serialised string carrying the `documentId` (the provider's document identifier) and/or the document `file` (base64 image). Example: `"{\"documentId\":\"abc-123\",\"file\":\"data:image/jpeg;base64,/9j/...\"}"`.

After a successful PATCH the proof transitions from `pending` to `processing`; the provider validates it asynchronously and the proof eventually reaches `success` or `failed`.

**Parameters**

| Name | Required | Description |
| --- | --- | --- |
| `id` | REQUIRED | Id of the Individual Identity Proof being submitted. Sent as the path parameter. |
| `content` | REQUIRED | Content of the proof, encoded according to the `proofType` as described above. |

**Request**

```python
import starkinfra

proof = starkinfra.request.patch(
    path="/individual-identity-proof/4512334302912512",
    body={
        "content": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ..."
    }
).json()

print(proof)
```

**Response**

```python
{
    'proof': {
        'id': '4512334302912512',
        'proofType': 'biometric',
        'metadata': {},
        'status': 'processing',
        'individualIdentityId': '5740977003561984',
        'created': '2026-06-23T12:00:10.000000+00:00',
        'updated': '2026-06-23T12:02:00.000000+00:00'
    }
}
```
