Skip to main content
An Orru statement is a record on Creditcoin. Anyone can read it. You do not need an account, an API key, or our cooperation, and that is deliberate. A verification service you have to trust is the thing Orru exists to remove.

Two ways, same answer

Open the page

https://orru.xyz/verify/<credentialId>Server-rendered, no wallet, no login. Works in a fresh incognito window. Hand this link to anyone.

Call the API

GET /api/verify/<credentialId>The same data as JSON. Public and unauthenticated.
Or skip us entirely and read the contract yourself. The page and the API are conveniences; the credential lives on-chain and answers to nobody.

What a statement proves

Four checks compose into one statement.
1

The Ethereum evidence is authentic

Attestcoin authenticated the source transaction against attested Ethereum history through Creditcoin’s native query verifier. For Demo Payroll that receipt contains the ERC-20 transfer. For Semuni it contains the payer’s commitment, not proof of an off-chain bank transfer.
2

The payer is recognised

The event came from the exact expected source contract, and its indexed payer is approved. The payer comes from topics[1], not the transaction’s gas-paying from address. A stranger emitting a lookalike event does not count.
3

The proof uses the same commitments

The zero-knowledge proof recomputes each commitment from the private amount, period and salt. Creditcoin requires those byte-identical commitments to be the ones Attestcoin accepted, then checks the common band and consecutive periods.
4

The subject controls the wallet

The holder signed an EIP-712 authorization at issuance. A proof shows payments exist; it does not show that whoever submitted it owns the address they named. Both are required.
For an off-chain payer, the cryptographic claim begins at the approved payer’s anchor. Orru removes trust in its own indexing and database, but it cannot prove that an external bank transfer occurred from an Ethereum commitment alone.

What it does not prove

This does not prove future income, affordability, legal credit eligibility, or guaranteed repayment.
It is a dated record of past payments, not a forecast. Treat it as one input to your own decision.

What you get, and what you do not

A statement carries an income band, never an amount. The band is enforced by a zero-knowledge circuit: the holder proves every payment fell inside one band without revealing what any of them were. That is the whole point, and it means a narrower band is more useful to you and less private to them.

Statements do not expire

There is no expiry field, and that is a design decision rather than an omission. A statement attests a dated past window, and that stays true forever. Whether a window is recent enough to lend against is your policy, not ours. A payday lender and a mortgage underwriter will not agree, and neither should be forced into the other’s answer. Every statement carries evidenceEndDate: the date of the most recent payment it proves. Apply your own maximum age to it.
If you want this enforced on-chain rather than in your code, DemoCreditPool shows the pattern: a minimumEvidenceHeight floor that rejects anything older, and can only ever be raised.

Three states, and only three

Issued and not revoked. Read the band, the period count, and evidenceEndDate, then apply your own freshness policy.
The holder or the issuer withdrew it. revokedAt says when. Do not lend against a revoked statement, regardless of how good the band looks.
No statement with that id was ever issued. Usually a mistyped id. A credential id is 0x followed by 64 hex characters; anything else is not one.
Render on status, never on whether you got data back. The contract returns a fully populated record for a revoked statement: same subject, same band, everything. Code that checks “did I receive a response?” will show a revoked statement as valid.