OC Me · Quickstart
Seven steps from cold to shipped. Each one is its own surface in the integrator console. None of them hides behind a sales call. You can stop at any point; nothing is destructive.
01 · create your project
Sign in at me.ochk.io (email-OTP or BIP-322). Your OC
identity is your integrator account — no separate developer signup. Run the
three-step wizard at /me/projects/new:
name, domain, mode. You get a project_key and a public JWK URL pattern.
display_name: YourCompany
domain: yourcompany.com
mode: test # first 1,000 sessions free
→ project_key: pk_test_a4f9k2x...
02 · verify your domain
Until verified, your project_key cannot fire live envelopes against your
domain. Add either record below, then click "verify now" on /me/projects/[id].
Backend tries DNS first, falls back to fetching your homepage. Test mode is
unrestricted; this gate applies to live mode only.
# DNS TXT at yourcompany.com (apex)
oc-verify=<token>
# OR meta tag in <head> at https://yourcompany.com/
<meta name="oc-domain-verify" content="<token>" />
03 · install the SDK
One npm package, three subpath entry points.
yarn add @orangecheck/me-client @orangecheck/auth-client
| Entry point | What it has |
|---|---|
@orangecheck/me-client | the oc.* calls, setBearerToken, sign-in button |
@orangecheck/me-client/server | server-side verification (zero JWK handling) |
@orangecheck/me-client/popup | browser-only signin orchestrator |
The React provider and hook (OcSessionProvider, useOcSession) come from
@orangecheck/auth-client; me-client does not re-export them.
04 · drop the popup signin
Add a button. Inside the click handler, call signInWithOc(). A 480x720
me.ochk.io popup opens, user signs in, popup postMessages a token bound to
your origin back to your page, closes itself. Same shape Google and GitHub use.
OC's session cookie lives on ochk.io, so a site outside the family never sees
it. Carry the token yourself: send it as a Bearer to your backend, which
verifies it (step 05). A Next.js site can instead trade it once for its own
cookie, which is what the per-stack snippets on /me/projects/[id] do. 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';
document.querySelector('#signin')!.addEventListener('click', async () => {
const result = await signInWithOc();
if (!result) return; // user cancelled or popup blocked
setBearerToken(result.token); // me-client calls ride it
const me = await fetch('/api/auth/me', {
headers: { Authorization: `Bearer ${result.token}` },
});
if (me.ok) location.assign('/dashboard');
});
05 · verify the session server-side
Wrap your protected routes with the framework adapter for your stack. The
wrapper handles JWKS retrieval + caching internally. You never touch a JWK env
var or /.well-known/jwks.json.
// Next.js Pages — 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,
display_name: req.ocSession.name ?? null,
nostr_npub: req.ocSession.npub ?? null,
},
});
},
{ audience: 'https://your-site.example' }
);
Express:
import { ocAuthExpress } from '@orangecheck/me-client/server';
app.use(ocAuthExpress({ audience: 'https://your-site.example' }));
Hono / Workers / Bun / Deno:
import { ocAuthHono } from '@orangecheck/me-client/server';
app.use('*', ocAuthHono({ audience: 'https://your-site.example' }));
audience is your own origin: the sign-in popup issues your site a token bound
to it, and a token issued to any other site is refused. A *.ochk.io site that
reads the family cookie leaves it out. The per-stack snippet generator on
/me/projects/[id] has the copy-paste blocks pre-filled with your project_key
and your origin.
06 · smoke-test the loop
On /me/projects/[id], the smoke-test panel fires a real envelope under your
project_key (same pipeline as production: signed, co-signed, OTS-anchored,
fanned out to webhooks). See it land in the live event stream within seconds.
[ fire test envelope → ]
subtype: session_creation
↓
envelope id: oc-me-tx7m4f9k
webhooks_fired: 0 (none registered yet)
→ live in /verify/[id]
Register a webhook URL on the same page, click "test fire" on the webhook row to confirm delivery + signature verification before you wire it into your backend.
07 · flip to live
Set per-event prices in the config editor on /me/projects/[id]. Choose how
much of each fee streams to your user vs your rebate. Once the project is in
live mode AND domain-verified, envelopes ship.
mode: live
session_creation: 60 sats · user_share 65%
payment_authorization: 0.75% of amount · user_share 65%
OC keeps a fixed 20% platform fee; the remaining 80% splits between the user (your call) and your rebate (whatever's left).
reference: see it working
me-demo.ochk.io is a live OC integration we built
ourselves — a fictional newsletter site (Lumen Notes) styled deliberately
not-orangecheck. The signin button there uses the exact signInWithOc() popup
shipped in step 04; the loop works end-to-end. Source at
github.com/orangecheck/oc-me-demo-web.
next, deeper
- SDK reference — every export with type signatures
- Integrations guide — OAuth-peer pattern, sample configs, error handling
- Webhooks — full reception sample, delivery semantics
- API reference — every
/api/*endpoint