Nine steps. About five minutes to first envelope; ten more to harden for production.
From new project to first billable envelope, then a production-hardening HMAC step on top — every step has the actual code sample. Mark steps done as you go; progress persists locally, no account needed to read this page.
- [01]
create your project
sign in at me.ochk.io, then run the three-step wizard at /me/projects/new. your OC identity IS your integrator account — no separate developer signup. you get a project_key + a public JWK URL. ~60 seconds.
open /me/projects/new →# /me/projects/new display_name: YourCompany domain: yourcompany.com mode: test → project_key: pk_test_a4f9k2x... - [02]
verify your domain
until verified, your project_key cannot fire live envelopes against your domain. add a DNS TXT record (or a meta tag on your homepage) and click "verify now" — backend tries DNS first, falls back to the meta tag fetch. test mode is unrestricted; this gate applies to live mode only.
see the verify card →# DNS TXT at yourcompany.com oc-verify=<token shown on /me/projects/[id]> # OR meta tag in <head> <meta name="oc-domain-verify" content="<token>" /> - [03]
install the SDK
one npm package, three subpath entry points. /server has the framework adapters (no env vars, no JWK handling). /popup has the signin orchestrator. the main entry has the event, payment and session calls. the React provider (OcSessionProvider, useOcSession) comes from @orangecheck/auth-client.
yarn add @orangecheck/me-client @orangecheck/auth-client - [04]
drop the popup signin
add a button. inside the click handler, call signInWithOc(). a 480x720 me.ochk.io popup opens, user signs in (email-OTP or BIP-322), popup postMessages a token bound to your origin back, closes itself. OC's cookie lives on ochk.io, so a site outside the family carries the token itself: as a Bearer to your backend, or traded once for your own cookie (the Next.js stack snippets do that). a *.ochk.io site already has the family cookie and skips this.
import { setBearerToken } from '@orangecheck/me-client'; import { signInWithOc } from '@orangecheck/me-client/popup'; button.addEventListener('click', async () => { const result = await signInWithOc(); if (!result) return; // user cancelled setBearerToken(result.token); // me-client calls ride it const me = await fetch('/api/auth/me', { headers: { Authorization: `Bearer ${result.token}` }, }); }); - [05]
verify the session server-side
wrap your protected route with withOcAuth (Next.js Pages), ocAuthExpress (Express), or ocAuthHono (Hono). the wrapper handles JWKS retrieval + caching — no env vars. pass audience as your own origin: the popup issues your site a token bound to it, and a token issued to any other site is refused. a *.ochk.io site reads the family cookie and leaves audience out. answer /api/auth/me as { ok: true, account: { id, did_oc } } — the shape OcSessionProvider reads.
see all stack snippets →// pages/api/auth/me.ts import { withOcAuth } from '@orangecheck/me-client/server'; export default withOcAuth(async (req, res) => { if (!req.ocSession) return res.status(401).json({ ok: false }); res.status(200).json({ ok: true, account: { id: req.ocSession.sub, did_oc: req.ocSession.did_oc }, }); }, { audience: 'https://your-site.example' }); - [06]
fire a billable event from your backend
sign the request with your project secret and name who earns inside the signed body. no browser, no user cookie, and no reason for your backend to hold your users' session tokens — the signature is you asserting this identity did this on your site. store their did_oc next to your own user row once and you never need their session again.
reveal the signing secret →// server-side · the earner rides inside the bytes you sign import { oc } from '@orangecheck/me-client'; await oc.event.fire({ project_key: process.env.OC_PROJECT_KEY!, subtype: 'session_creation', // any subtype your project enabled signingSecret: process.env.OC_SIGNING_SECRET!, // never in a browser userAddress: user.did_oc, // who earns idempotencyKey: crypto.randomUUID(), }); - [07]
smoke-test the loop
fire a real envelope under your project_key from /me/projects/[id] (smoke test panel). see it land in the live event stream within seconds. test webhook delivery with one click before you wire your backend. exact same pipeline as production — signed, co-signed, OTS-anchored, fanned out.
see the user demo end-to-end →# /me/projects/[id] [ fire test envelope → ] subtype: session_creation ↓ envelope id: oc-me-tx7m4f9k webhooks_fired: 0 (none registered yet) → live in /verify/[id] - [08]
flip to live
set per-event prices in the config editor. choose how much of each fee streams to your user vs your rebate. domain verified + project in live mode = envelopes ship. paired comparisons against your actual stack come back in a business day if you want one.
request a paired comparison →# /me/projects/[id] · config mode: live session_creation: 60 sats · user_share 65% payment_authorization: 0.75% of amount · user_share 65% - [09]
the signature, by hand
the SDK does this for you — this is the wire format if you are not using it. signing is NOT optional: a user session proves a user, never the paying project, so an unsigned POST is refused in test mode as well as live. the one exception is a request from the project owner's own session, which is the CLI test-fire path and not a shape a backend should rely on. reveal or rotate the 256-bit secret in /me/projects/[id]/keys.
reveal/rotate the secret →// node · sign every /api/integrator/event POST import { createHmac } from 'node:crypto'; const ts = Math.floor(Date.now() / 1000); const sig = createHmac('sha256', process.env.OC_SIGNING_SECRET) .update(`${ts}.${rawBody}`) .digest('hex'); headers['X-OC-Signature'] = `t=${ts},v1=${sig}`;
next, deeper
The quickstart gets you to first envelope. After that: /why#integrators has the full pitch + comparison table, /integrate/sandbox runs your config against a representative one-month event mix, and docs.ochk.io/me/sdk documents every export, type signature, and code sample.
Just want your users to have an OrangeCheck identity — not the me.ochk.io billable-events product? That is a separate, simpler integration: docs.ochk.io/integration covers letting OrangeCheck be your sign-in, or adding a did:oc to the login you already run.