> For the complete documentation index, see [llms.txt](https://docs.t-rex.network/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.t-rex.network/guides/claim-issuer/05.-issue-a-claim-to-an-investor.md).

# 05. Issue a claim to an investor

Issuing a claim records, on an investor's identity, that a Claim Issuer vouches for a fact about it: identity verified, accredited, resident of a jurisdiction. The Claim Issuer verifies the investor off-chain, signs the claim, and the claim is added to the investor's ONCHAINID. From then on, every asset that trusts that issuer for that topic counts the claim. This is what makes an investor eligible.

## At a glance

|                   |                                                                                                                                                                                                                                                                                                                                                                                                |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Triggered by**  | Claim Issuer                                                                                                                                                                                                                                                                                                                                                                                   |
| **Actors**        | Claim Issuer, Investor, Identity Owner, Platform                                                                                                                                                                                                                                                                                                                                               |
| **Contracts**     | The ONCHAINID of the Investor, the ONCHAINID of the Claim Issuer, `ERC734Validator`, `IdentityFactory` and `ReputationRegistry` (read only, during the check of the issuer)                                                                                                                                                                                                                    |
| **Preconditions** | The Investor has an ONCHAINID (see [02](/guides/identity/02.-deploy-an-onchainid.md)); the Claim Issuer has an ONCHAINID of type `CLAIM_ISSUER` with a `CLAIM_SIGNER` key; the Claim Issuer has verified the Investor under its own process; either the Claim Issuer has standing in the network, or the Investor's identity has granted it a claim key, or the Investor adds the claim itself |
| **Result**        | The Investor's identity holds a valid claim from the Claim Issuer for the topic                                                                                                                                                                                                                                                                                                                |

## Actors and roles

| Actor          | Role in this flow                                                                                         | What they hold                                                                                  |
| -------------- | --------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| Claim Issuer   | Verifies the Investor, signs the claim and, in the usual path, adds it to the Investor's identity.        | An ONCHAINID of type `CLAIM_ISSUER`. A `CLAIM_SIGNER` key to sign. A `MANAGEMENT` key to submit |
| Investor       | Is the subject of the claim. Provides its documents off-chain.                                            | An ONCHAINID                                                                                    |
| Identity Owner | The Investor in its capacity as controller of the identity. Transacts only when it adds the claim itself. | A `CLAIM_SIGNER` or `CLAIM_ADDER` key on its identity                                           |
| Platform       | Carries the verification session, builds the claim and relays the calls.                                  | Whatever keys the Claim Issuer or the Investor has authorized                                   |

## Sequence

```mermaid
sequenceDiagram
    participant Investor
    participant CI as Claim Issuer
    participant CIID as Claim Issuer ONCHAINID
    participant Identity as Investor ONCHAINID
    participant Rep as ReputationRegistry

    Investor->>CI: documents, off-chain
    CI->>CI: verify under its own process
    CI->>CIID: getClaimHash(identity, topic, data) (read)
    CI->>CI: sign the claim with a CLAIM_SIGNER key
    alt the Claim Issuer adds the claim
        CI->>CIID: addClaimTo(topic, scheme, signature, data, uri, identity)
        CIID->>CIID: caller holds MANAGEMENT, claim valid
        CIID->>Identity: addClaim(topic, scheme, issuer, signature, data, uri)
        Identity->>Rep: issuer has a claim key here, or standing in the network
        Identity->>CIID: isClaimValid(identity, topic, signature, data)
        Identity-->>Investor: ClaimAdded
    else the Investor adds the claim
        CI-->>Investor: signed claim
        Investor->>Identity: addClaim(topic, scheme, issuer, signature, data, uri)
        Identity->>CIID: isClaimValid(identity, topic, signature, data)
        Identity-->>Investor: ClaimAdded
    end
```

## Step by step

### Step 1. Verify the Investor

**Who:** Claim Issuer

**Call:** Off-chain

**Before the call:** The Investor has given the address of its ONCHAINID and the documents the verification requires. When the Investor comes with a wallet that has no identity yet, the Claim Issuer creates one for that wallet first, with the wallet as its only manager ([02](/guides/identity/02.-deploy-an-onchainid.md)).

**What happens:** The Claim Issuer verifies the Investor under its own process and regulation. It confirms that the person it verified controls the identity it will attest. The result of the verification, and the documents, stay with the Claim Issuer.

**What changes:** Nothing on-chain.

### Step 2. Build and sign the claim

**Who:** Claim Issuer (`CLAIM_SIGNER` key)

**Call:** Off-chain, using read calls

**Before the call:** Step 1 concluded that the fact can be attested.

**What happens:** The Claim Issuer builds the claim.

| Field               | Value                                                                                                                                                                          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `topic`             | The claim topic agreed with the Issuers that rely on it, for example `<KYC topic>`. Not zero.                                                                                  |
| `scheme`, `uri`     | How the claim is to be read, and where supporting material is.                                                                                                                 |
| `data.issuedAt`     | The time of signing. Not zero.                                                                                                                                                 |
| `data.validUntil`   | The time after which the claim expires. Zero for no expiry.                                                                                                                    |
| `data.metadataHash` | `getMetadataHash(scheme, uri)`, read on the `ERC734Validator`, the module whose address `Identity.registryModule()` returns. It binds the scheme and the URI to the signature. |
| `data.payload`      | The content for the topic: a hash or an encoded value, not raw personal data.                                                                                                  |

It reads `getClaimHash(identity, topic, data)` on its own ONCHAINID, which returns the ERC-712 digest of the claim in the issuer's signing domain, and signs that digest with a key that holds `CLAIM_SIGNER` on its identity. The `signature` field of the claim carries the signer and its signature together.

**What changes:** Nothing on-chain.

### Step 3. Add the claim to the identity

There are two ways. The first is the usual one.

**Who:** Claim Issuer (`MANAGEMENT` key of its identity)

**Call:** `addClaimTo(topic, scheme, signature, data, uri, identity)`, called on the Claim Issuer's ONCHAINID

**Before the call:** Step 2 is done. The call is made directly on the issuer's identity by the key holder.

**What the contract checks:**

1. The caller holds `MANAGEMENT` on the Claim Issuer's identity. Otherwise the call reverts with `SenderDoesNotHaveManagementKey`.
2. The claim is valid for this issuer: inside its validity window, not revoked, signed by a `CLAIM_SIGNER` key of the issuer, with a signature that verifies. Otherwise `InvalidClaim`.
3. On the Investor's identity: the Claim Issuer's identity holds a `CLAIM_SIGNER` or `CLAIM_ADDER` key there. If it does not: its identity is of type `CLAIM_ISSUER` in the `IdentityFactory`, and its reputation is at least the claim-add threshold. Otherwise `IdentityNotClaimIssuerType` or `ReputationBelowClaimAddThreshold`.
4. The topic is not zero. Otherwise `InvalidClaimTopic`.
5. The signature, the payload and the URI are within their size limits. Otherwise `ClaimSignatureTooLong`, `ClaimPayloadTooLong` or `ClaimUriTooLong`.
6. `data.metadataHash` matches the scheme and the URI. Otherwise `ClaimMetadataMismatch`.
7. The issuer confirms the claim: `isClaimValid(identity, topic, signature, data)` returns true. Otherwise `InvalidClaim`.

**What changes:** The Investor's identity stores the claim under `claimId = keccak256(abi.encode(issuer, topic))`. If the identity already held a claim from this issuer for this topic, it is replaced. The `ERC734Validator` emits `ClaimAdded`, or `ClaimChanged` for a replacement, with the identity, the claim and the caller, and `ClaimAddedTo` for the write made by the issuer.

**Alternative: the Investor adds the claim.**

**Who:** Identity Owner (`CLAIM_SIGNER` or `CLAIM_ADDER` key of the Investor's identity)

**Call:** `addClaim(topic, scheme, issuer, signature, data, uri)`, called on the Investor's ONCHAINID

**Before the call:** The Claim Issuer has sent the signed claim to the Investor.

**What the contract checks:** The caller holds `CLAIM_SIGNER` or `CLAIM_ADDER` on the identity. Otherwise `SenderDoesNotHaveClaimSignerKey`. Then checks 4 to 7 above.

**What changes:** The same.

### Step 4. Confirm the effect

**Who:** Platform

**Call:** Off-chain, using read calls

**Before the call:** Step 3 is confirmed.

**What happens:** The Platform reads `getClaim(claimId)` on the Investor's identity, and `isClaimValid(identity, topic, signature, data)` on the Claim Issuer's identity, which must return true. For an asset the Investor wants to hold, it reads `TREXRegistry.isVerified(address)` for one of the Investor's addresses.

**What changes:** Nothing on-chain.

## State after the flow

* The Investor's identity holds one claim from this issuer for this topic, readable with `getClaim(claimId)` and listed by `getClaimIdsByTopic(topic)`.
* The Claim Issuer answers `isClaimValid` with true for that claim, until it expires, is revoked, or its signing key is withdrawn.
* Every asset that requires the topic and trusts this issuer for it counts the claim, for every address of the identity, on every chain.
* No asset was touched. No registry of any asset changed.
* No personal data is on-chain.

## Failure modes

| Symptom                                                             | Cause                                                                                                                                                            | Fix                                                                                                                                    |
| ------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| Reverts with `SenderDoesNotHaveManagementKey`                       | `addClaimTo` was called by a key that does not hold `MANAGEMENT` on the issuer's identity (step 3, check 1)                                                      | Submit with a `MANAGEMENT` key. The signing key signs, it does not submit                                                              |
| Reverts with `InvalidClaim`                                         | The claim does not validate: wrong digest, signer without `CLAIM_SIGNER`, `issuedAt` zero or in the future, expired, or already revoked (step 3, checks 2 and 7) | Read `getClaimStatus` on the `ERC734Validator`, with the issuer's identity as the caller of the read, to see which. Sign a fresh claim |
| Reverts with `IdentityNotClaimIssuerType`                           | The issuer has no claim key on the Investor's identity and is not a `CLAIM_ISSUER` identity of the factory (step 3, check 3)                                     | Have the Investor add the claim itself, or grant the issuer a claim key                                                                |
| Reverts with `ReputationBelowClaimAddThreshold`                     | The issuer's reputation is below the network threshold (step 3, check 3)                                                                                         | Same. Or have the `REPUTATION_MANAGER` review the issuer                                                                               |
| Reverts with `ClaimMetadataMismatch`                                | `metadataHash` was not computed from the scheme and the URI submitted (step 3, check 6)                                                                          | Compute it with `ERC734Validator.getMetadataHash(scheme, uri)`                                                                         |
| Reverts with `InvalidClaimTopic`                                    | The topic is zero (step 3, check 4)                                                                                                                              | Use the agreed topic                                                                                                                   |
| Reverts with a size error                                           | The signature, the payload or the URI exceeds 2,048 bytes (step 3, check 5)                                                                                      | Put a hash in the payload, not the data                                                                                                |
| Reverts with `SenderDoesNotHaveClaimSignerKey`                      | In the alternative path, the caller holds neither `CLAIM_SIGNER` nor `CLAIM_ADDER` on the Investor's identity                                                    | Use a key that does, or a `MANAGEMENT` key                                                                                             |
| The call is refused when sent as a user operation                   | `addClaim` and `addClaimTo` require a direct call from the key holder                                                                                            | Call the identity directly                                                                                                             |
| The claim is on the identity and the Investor is still not eligible | The asset does not trust this issuer for this topic, or another required topic is missing                                                                        | See [04](/guides/issuer/04.-add-a-trusted-claim-issuer.md) and [03](/guides/issuer/03.-configure-required-claim-topics.md)             |

## Common misunderstandings

> **Wrong:** "The protocol issues the KYC." Or: "The Issuer issues the claim."
>
> **Right:** A Claim Issuer signs claims. The protocol stores them and checks them. The Issuer of an asset decides which Claim Issuers it trusts and for which topics. It can run its own Claim Issuer, which is then a separate role with its own identity.

> **Wrong:** "A claim is issued for a token."
>
> **Right:** A claim is about an identity, not about an asset. One claim serves every asset that trusts its issuer for its topic. An investor verified once is not verified again per asset.

> **Wrong:** "A claim is issued to a wallet."
>
> **Right:** A claim is added to the ONCHAINID. Every address of the identity shares it: the identity's own address and every linked wallet, on every chain.

> **Wrong:** "The claim contains the investor's data."
>
> **Right:** The claim contains a topic, the issuer, a validity window, a signature and a payload that is a hash or an encoded value. The documents stay off-chain with the Claim Issuer.

## Integration notes

* Read `getClaimHash(identity, topic, data)` from the issuer's identity to obtain the digest to sign. Do not rebuild the typed data by hand.
* Set `validUntil` to the date after which the verification has to be renewed. Expiry needs no transaction, and the investor stops being eligible at that moment.
* Re-issuing for the same topic replaces the previous claim from the same issuer. Renewal is this same flow.
* Keep the signing key and the submitting key apart. A signing service holds `CLAIM_SIGNER`. Submission and revocation take `MANAGEMENT`.
* Store, off-chain, the digest of each claim issued with the verification record. It is what `revokeClaimByDigest` takes.
* Index `ClaimAdded`, `ClaimChanged` and `ClaimRemoved` on the `ERC734Validator`, filtered by identity or by issuer.
* An Investor without a gas token receives its claims through the first path. The Claim Issuer pays.
* A Claim Issuer with standing needs no approval from the Investor to add a claim. This is by design: asking for an acceptance on every claim would add a step to every onboarding. The gate is upstream, on who can be a Claim Issuer at all. The Investor can remove a claim from its identity afterward.

## Related flows

* [19 Revoke a claim](/guides/claim-issuer/19.-revoke-a-claim.md) : withdrawing the attestation
* [02 Deploy an ONCHAINID](/guides/identity/02.-deploy-an-onchainid.md) : the Investor's identity, and the Claim Issuer's
* [04 Add a trusted Claim Issuer](/guides/issuer/04.-add-a-trusted-claim-issuer.md) : what makes the claim count for an asset
* [03 Configure required claim topics](/guides/issuer/03.-configure-required-claim-topics.md) : which topics an asset requires
* [08 Mint a position to an investor](/guides/positions/08.-mint-a-position-to-an-investor.md) : where eligibility is first checked


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.t-rex.network/guides/claim-issuer/05.-issue-a-claim-to-an-investor.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
