verified. On the Trusset ID Register, that holds only when one of your instance’s registered wallets did the verifying. Confirming Verify Identity creates or updates the record for the wallet it verified.
Beyond that the two do not follow each other. A record’s status is what was last recorded, not a live registry read, and archiving a record leaves the identity on the registry. Read the registry’s own answer with Identity Status.
Base Path
X-API-Key header. See Authentication.
Customer records need the
customers service. Everything under /identity, /id-links, /verification-profiles, /eligibility and /disclosure-requests needs identity.
Which register you write to
An instance writes to the Trusset ID Register by default, or to its own register when it is bound to one. Its own register is either a Trusset identity register or an ERC-3643 identity registry (Tokeny T-REX with ONCHAINID). Every identity call resolves the register automatically, and no endpoint takes a registry address. Calldata responses name the kind inregisterKind: TRUSSET or TREX.
The request is the same on both kinds, but the work behind it is not. On a Trusset register, each write is one transaction from a wallet holding KYC_PROVIDER_ROLE, or REGISTER_OPERATOR_ROLE to revoke an identity. On an ERC-3643 registry, registering a wallet can take three rounds: deploying its ONCHAINID, signing each claim as a message, then adding the claims and registering the identity. Verify Identity sets out which key signs each step.
When none of your instance’s wallets holds the role a write needs, the write is refused before any calldata is handed out. A Trusset register answers 403 KYC_PROVIDER_ROLE_MISSING, 403 REGISTER_OPERATOR_ROLE_MISSING for a revocation or 403 COMPLIANCE_ROLE_MISSING for a freeze, and an ERC-3643 registry 403 REGISTRY_AGENT_MISSING. The check is skipped when the instance has no registered wallet or the role cannot be read, and a write without the role then reverts on chain.
On the Trusset ID Register, Trusset grants all three roles to a registered, verified wallet of your instance: open the wallet page of the issuer app and press Grant on-chain roles on the wallet card, which lists the roles the wallet is missing. The grant is part of the issuer app (POST /issuer-wallets/wallets/:instanceId/:walletId/grant-roles with the issuer app login), not of the API key. A refusal can outlast a new grant by up to a minute. On your instance’s own register, the register owner grants the roles.
The Trusset ID Register is shared by every instance without a register of its own, so it holds one identity per wallet. Your instance revokes and freezes only identities one of its own wallets registered, and is refused with 403 IDENTITY_HELD_BY_ANOTHER_ISSUER for an identity another issuer’s wallet wrote. An identity the copy into the current register carried over counts for the wallet that first registered it, and one the Trusset platform wrote before issuer wallets signed counts as yours when the wallet belongs to one of your customers.
The Trusset ID Register
On Sepolia the Trusset ID Register is0xEf244c4Bd4d71Bd9A30EDF6Edef7CCC72642291a. The previous address, 0xE9114c40934f6fB6BB317935156b731f7A86D006, was retired on 10 October 2026 and takes no new identities.
The 25 identities verified on the previous register were copied to the current one with their kycHash, investor type, expiries and claims. An identity past its hard expiry was not copied. A soft expiry that had already passed was moved to one hour after the copy. On the current register each copy names the migration key as kycProvider and the copy time, 10 October 2026, as timestamp. Identity Status returns the original verifier and date in onChain.migration.
Lending markets and vaults whose gate still reads the previous register admit only wallets verified before the move. A market’s admin moves the gate with Set Identity Gates. A vault keeps its register for life and cannot be moved, so a customer verified since deposits through a vault gated on the current register.
Binding either Trusset register as your instance’s own register in the Issuer Portal is refused with 400 REGISTRY_IS_PLATFORM. Select Trusset there to write to the current register.
Writes return calldata
Every write that changes the registry returns unsigned calldata for a wallet you control to sign and broadcast. Nothing is submitted on your behalf. Call the endpoint once withouttxHash to get the transaction, then again with the hash to have the receipt verified and the result recorded.
Some writes vary that shape. Add Claims from Proof and Attest Proofs confirm several receipts in one call with txResults. The pending queue and ONCHAINID deployments confirm on their own endpoints. On an ERC-3643 registry, a write can first answer with messages to sign, which the next call sends back as claimSignatures. When a plan holds several transactions, confirmStepIndex names the one to confirm.
Pending approvals
When a customer passes KYC through an ID link or a hosted verification service, the approval does not reach the register on its own. It waits in a queue with thekycHash, investor type, expiries and residency claim Trusset computed, until your wallet signs it.
Work the queue with List Pending Verifications, Build Pending Registration and Confirm Pending Registration. Dismiss Pending Verification closes a row for good.
On an ERC-3643 registry a wallet needs an ONCHAINID before it can be registered. Build Pending Registration asks for one in its first phase when the wallet has none. Deploy ONCHAINID and Confirm ONCHAINID deploy one ahead of time.
Eligibility registers
A verification profile can carry an eligibility register: an on-chain identity register that holds exactly the wallets admitted under that profile. Lending markets and vaults read it as a gate, so a market can lend only to the customers of one profile and a vault can take deposits only from them. A register is deployed for a profile, or an existing one bound to it, in the Issuer Portal. A deployed register extends your instance’s own ERC-3643 identity register, so an instance that writes to the Trusset ID Register cannot deploy one (409 ELIGIBILITY_REQUIRES_OWN_REGISTER). It can still bind an existing ERC-3643 register to a profile that is not limited to professional clients (PUT /customers/verification-profiles/{id}/eligibility-register). That register is read only here, in the EXTERNAL mode below. Only a profile limited to professional clients needs your instance’s own ERC-3643 register first. A profile without a register named as a market or vault gate answers 409 ELIGIBILITY_REGISTER_NOT_SET, and its message gives the remedy that fits the profile. Both codes carry details.registryMode: TRUSSET on such an instance. This API manages who is on it.
One register stands for one profile of an instance. The Issuer Portal refuses to bind a register that another profile of the instance already uses (ELIGIBILITY_REGISTER_IN_USE), or one that keeps its identities in the same identity storage as another profile’s register (ELIGIBILITY_STORAGE_IN_USE). A profile limited to professional clients takes only a register in the REGISTER mode below, whose admissions your instance signs (PROFESSIONAL_REGISTER_REQUIRED), because lending markets rely on it to admit professional clients only. A bound profile’s professionalOnly setting cannot change until the register is unbound.
Admissions work like the pending queue. A wallet waits as an admission, your wallet signs the transaction that puts it on the register, and the confirm reads the outcome from the chain.
1
Queue
Request Admission queues a wallet of one of your customers. Trusset also queues admissions on its own, listed below.
2
Build
Build Admission returns one unsigned
registerIdentity or batchRegisterIdentity transaction for up to 50 waiting wallets.3
Sign
A wallet of your instance that is an agent of the register signs and broadcasts it. Trusset holds no key and sends nothing.
4
Confirm
Confirm Admission takes the transaction hash alone and records every wallet the register’s
IdentityRegistered logs in the receipt name.deleteIdentity transaction per wallet, and Confirm Removal, which reads IdentityRemoved logs. List Admissions shows the queue in every state, Get Wallet Eligibility shows one wallet across every register, and List Eligibility Profiles lists the profiles that have one.
Trusset queues these on its own:
A removal that reaches an admission still waiting to be signed cancels it instead. Nothing is written to a register until your wallet signs.
A removal waiting to be signed can be withdrawn. A
LAPSED, REVOKED, REJECTED or REQUIREMENTS_CHANGED removal is withdrawn by a fresh verification of the customer, or by Request Admission with reverifiedOutsideTrusset: true. A MANUAL, COUNTRY_BLOCKED, ARCHIVED or WALLET_CHANGED removal is withdrawn only by a request from you, never by a verification. Archiving a customer, changing its wallet or its country into a blocked one, and a KYC rejection queue removals on every profile register the wallet is admitted to.
Which registers can be signed here
What this API can do on a register depends on the register. The mode is recorded when the register is bound. The Issuer Portal shows it, and List Eligibility Profiles reports it asadmissionMode. Request Admission follows the recorded mode. The builds inspect the register again, so a register that no wallet of your instance is an agent of any more is refused there.
A register deployed from the Issuer Portal uses the claim topics and trusted issuers of your instance register, and a wallet is admitted with the ONCHAINID your instance register holds for it. It therefore reads as verified there on the same claims, which is why Build Admission skips a wallet your instance register does not verify yet.
Eligibility registers are available on Ethereum instances only. A customer webhook set up in the Issuer Portal reports the queue as
eligibility.admission_pending, eligibility.admitted, eligibility.removal_pending and eligibility.removed.
Claims
The registry holds eight claim slots per identity. Four of them mean something fixed and four are yours to assign.
The four canonical slots are reserved on this API. Add Claim refuses them with
PROOF_REQUIRED, because a residency attestation that anyone could write by hand would not be worth reading. Add Claims from Proof can file all four from a verified bundle, and Attest Proofs any of them except KYC. A Trusset register does not enforce the reservation itself: any wallet holding KYC_PROVIDER_ROLE can write any slot directly.
The four assignable slots take a hash you supply. What they mean is your convention, and a proof for a field with no canonical meaning can be filed in one of them.
On an ERC-3643 registry the claims live on the wallet’s ONCHAINID instead. Each slot except KYC becomes the topic uint256(keccak256(name)), where name is the slot name such as RESIDENCY. A KYC claim takes the register’s first required claim topic that one of your wallets can sign for. A CLAIM key of the registry’s trusted issuer signs each claim.
KYC proofs
Claims backed by proofs come from the Trusset KYC zk-Proof Tool, which runs entirely on your own machines. It takes your KYC records and produces three things per subject: a Merkle root to publish on chain, one zk-STARK per proved field, and a manifest signed with your operator key. The manifest says what was asserted, under which rule, on what evidence, and for how long. Trusset never sees the underlying data. What reaches this API is the manifest, the signature, and the proof bytes. The date of birth, the nationality and the documents stay with you.1
Register your operator key
Set Operator Key records the ed25519 public key the tool prints. Bundles are verified against it.
2
Verify the identity
Verify Identity puts the subject on the registry with their
kycHash, which is the bundle’s Merkle root.3
Read the bundle
Inspect Manifest reports what the bundle contains and which leaves can be attested, without writing anything.
4
File the claims
Add Claims from Proof verifies the bundle and returns the calldata for each claim it backs.
A leaf can be a hiding commitment with no zk proof behind it, which the tool uses for fields like a surname where there is no predicate worth proving. Those leaves are marked
commitmentOnly and are not attestable while proof verification is enforced.Disclosure requests
A disclosure request asks the holder of a wallet to disclose one verified fact to your instance. The fact is age over 18 (AGE), country of residence (COUNTRY), or the complete on-chain verification (FULL_KYC).
The holder answers on verify.trusset.org with a consent the wallet signs and, for some facts, a zk-STARK proof from their bundle. Creating a request sends the holder nothing, and no webhook reports the answer, so read it back with Get Disclosure Request.
Response envelope
/identity and /eligibility always send both data and error, with the unused one null. So do Get ID Link, Issue Sumsub Token, Bind Link Wallet and Recheck Link Review. The other paths send only the one that applies, so a success has no error key and a failure has no data key. On failure, error carries code and message. Always branch on success rather than on the HTTP status alone.
The lists under /manage and /id-links put total in metadata. List Disclosure Requests returns data.items and data.pagination instead.
Errors every route can return
These refusals come before a route runs, so they carry nodata. The rate limit and the key-material check run before authentication, and those two answers carry no requestId.
Rate limits
Every request made with an API key counts against 200 requests per minute for that key, across every product. The minute is a fixed window on the clock, not a rolling one. Exceeding it returns429 RATE_LIMIT_EXCEEDED with a Retry-After header in seconds. Every response reports the budget in X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. See Rate Limits.
Add Claims from Proof, Inspect Manifest and Attest Proofs also share a budget of 30 requests per minute per instance. It answers 429 with code RATE_LIMITED, not RATE_LIMIT_EXCEEDED, and a Retry-After header.
Two more budgets of 120 requests per minute per instance apply. The admission and removal writes under /eligibility share one with Get Wallet Eligibility. Get ID Link, Issue Sumsub Token, Bind Link Wallet and Recheck Link Review share the other. Both answer 429 RATE_LIMIT_EXCEEDED with a Retry-After header. No other Customers route has a tighter limit.
Credits
Requests made with an API key also draw on your instance’s monthly credit allowance, one credit each, reads included. Every Customers path is billed against theidentity service, /manage included. Writes made in the Issuer Portal draw on the same allowance.
Every metered response carries X-Credits-Limit, X-Credits-Remaining and X-Credits-Reset, plus an X-Request-Id you can quote in support requests. When the allowance is exhausted the request is refused with 402 CREDIT_LIMIT_EXCEEDED, and metadata carries creditsLimit, creditsRemaining and resetsAt. Only a 5xx answer refunds its credit, so a refusal such as SERVICE_NOT_ENABLED still costs one.