For the complete documentation index, see llms.txt. This page is also available as Markdown.

Integrate on chain KYC dev guide

You want your app to gate an action behind proof of a KYC credential, verified without your app ever seeing the underlying personal data.

Who this is for: developers adding a KYC-gated flow (an allowlist, a mint, a transfer) to a Lumia app. Prerequisites: Networks & Endpoints; KYC (concept) if you haven't already read what KYC means in Lumia's compliance model.

How it works

The verifier flow is a two-call REST handshake, documented in full at /reference/rest-apis/kyc-verifier-api. This page walks through using it; that page is the endpoint table.

  1. Your backend calls POST /sign-in on the verifier, scoped to the network you're checking against.

  2. The response includes a qrCode and a sessionID. Your frontend renders the QR code; the user scans it with their credential wallet.

  3. Your backend polls GET /status?sessionID=... until it returns a terminal status (success/approved, or failed).

  4. Only once status is successful does your app grant the gated action.

Steps

1

Pick the network you're scoping the check to

Use its confirmed chain ID from /reference/networks.

2

Start a session

const res = await fetch("https://verifier-backend.privado.id/sign-in", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    chainID: "2030232745", // Beam, see /reference/networks; do not use 1952959480
    scope: [
      {
        circuitId: "<your circuit ID>", // from your verifier/circuit configuration
        id: 1,
        query: {
          allowedIssuers: ["*"], // restrict this for a production check
          context: "<your query context>",
          type: "<your credential type>",
          credentialSubject: {},
        },
      },
    ],
    skipClaimRevocationCheck: false,
  }),
});
const { qrCode, sessionID } = await res.json();
3

Render the QR code

Render qrCode for the user to scan with their credential wallet.

4

Poll for status

async function pollStatus(sessionID) {
  const res = await fetch(`https://verifier-backend.privado.id/status?sessionID=${sessionID}`);
  const { status } = await res.json();
  return status; // "success" / "approved" / "failed" / a pending state; see /reference/rest-apis/kyc-verifier-api
}
5

Grant the gated action

On a successful status, grant the gated action in your app/contract logic.

Verify it worked

Run the flow end to end with a test credential wallet: confirm /sign-in returns a scannable QR and a sessionID, that scanning it changes /status from pending to success/approved, and that your app's gated action becomes available only after that.

Troubleshooting

/status never leaves pending

Confirm the chainID you sent matches the network your credential wallet is actually scoped to; a mismatch here is easy to introduce if you copy an old example using 1952959480.

circuitId/query fields rejected

Get the exact expected values from your own verifier/circuit configuration rather than guessing from another chain's Privado ID integration.

No error codes to branch on

See /reference/rest-apis/kyc-verifier-api for the endpoint's response shape; handle non-200 responses generically if it doesn't cover what you're seeing.

Last updated

Was this helpful?