Built by devs, for devs

A full integration from scratch, in one afternoon

We'll build account opening with a liveness check: the person signs up in your product, completes the verification on their phone, and your server receives the signed decision. All of it in the test environment, without touching your included verifications, and at the end, the switch to production.

# 1 · your server opens the session
POST /v1/sessions        → sessionId + captureUrl

# 2 · the person completes the verification on their phone
captureUrl               → camera, gestures, upload

# 3 · the decision arrives at your server
webhook session.completed → APPROVED · score · threshold · receipt

Before you start

You need three things, and each takes minutes.

  1. An account

    The Free plan comes with an unlimited test key and 30 real verifications per month. Create account.

  2. A test key

    In the console, under API Keys, create one with the test environment. It runs on the simulated engine: it doesn't use your included verifications, isn't billed, and can't see production.

  3. A public URL for the webhook

    In development, a tunnel does the job. Without one, you can fetch the session by id — step 5 shows both paths.

Step 1 · Install the SDK

Optional, but it handles the fiddly parts: webhook signatures, receipt verification, safe retries, and the envelope types. Pick your language — the rest of the tutorial shows the code in all of them.

pip install catalisa-biometrics composer require catalisa/biometrics gem install catalisa-biometrics dotnet add package Catalisa.Biometrics go get github.com/catalisaio/catalisa-biometrics-sdk/packages/go io.github.catalisaio:catalisa-biometrics:0.1.0

Store the key in an environment variable. It lives on the server, never in the app or the browser: anyone holding the key can open sessions on your account.

Step 2 · Open the session on your server

When the person reaches the verification step of your sign-up, your backend opens a session. The response includes the captureUrl: it is valid for one person and one session, and it expires.

Loading the example…

The purpose is what you would show an auditor asking why this person's face was processed. The metadata field accepts up to ten free-form labels — and never a CPF (Brazilian taxpayer ID).

Step 3 · Get the person to capture

The simplest path is the link: over WhatsApp, email, a QR code, or a button in your app. We host the page, already in your brand, and it works on mobile and desktop.

Loading the example…

Want the camera inside your product? There's an iframe with progress events and uploading from your own app. The decision never goes through the browser — not even in the iframe.

Step 4 · Receive the decision on your server

When the verification finishes, we send a signed event to your endpoint. Verify the signature before trusting the payload: that is what proves it came from Catalisa and not from someone who found your URL.

Loading the example…

  • Verify the raw bodyParsing and re-serializing the JSON changes the bytes, and the signature won't match.
  • Use the event idA delivery can arrive more than once; the id is stable and works as an idempotency key.
  • Respond fastReturn 200 and do the work afterwards. Slow responses trigger redelivery.
  • No endpoint yet?Fetch the session by id — that's step 5.

Step 5 · Read the envelope and decide

The decision comes with the numbers that produced it: score, threshold, and the model that decided, check by check. That's what you show when someone disputes it.

Loading the example…

The final states are APPROVED, REJECTED, INCONCLUSIVE, EXPIRED, and CANCELLED. RETRY_ALLOWED is not final: the person can still try again, and the page reissues the link on its own.

Step 6 · Rehearse every outcome

In the test environment, the last digits of the CPF determine the result. That lets you cover approval, rejection, review, and errors without relying on luck — and without touching your included verifications.

CPF ending in …-25Approved
CPF ending in …-11Inconclusive · review
CPF ending in …-55Retry, then approved
CPF ending in …-66Engine error (retry)
CPF ending in …-00Failed face match
CPF ending in …-33Failed liveness

Also cover what goes wrong beyond the face: an exhausted quota and a suspended account come back as typed errors.

Loading the example…

Step 7 · Keep the receipt

Every decision comes with a signed evidence bundle. You verify the signature without calling us, today or three years from now — it's what backs your side of the story in a dispute or an audit.

# Ed25519 over exactly this string
sessionId | attempt | bundleHash | signedAt

# the public key comes from GET /v1/evidence-keys
# retired keys stay published — old receipts still verify

Every SDK runs this check offline, without calling Catalisa. Details in Decision receipt.

Step 8 · Go to production

The code doesn't change. What changes is the key — plus four checks before you go live.

  1. Swap the key

    Create a production key in the console and use it on your server. From then on the engine is the real one, every verification counts toward your included verifications, and test sessions disappear from your list.

  2. Register the production webhook

    In the console, under Webhooks, point it at your URL and save the public keys. Verify the signature with them.

  3. Review the policy

    Thresholds, number of attempts, link expiry, and what to do in the gray zone: send to human review or reject. All under Settings.

  4. Match the plan to your volume

    The console shows how much of the cycle you've used. Above your included verifications, overage is charged per verification; blocking only happens on the Free plan.

Want capture in your brand? Under Customization you can set the page's color, logo, and copy, and allow the domains that can embed the iframe.

Start with a dry run: the test key costs nothing.