@orangecheck/me-client v0.5.0
Every export from the consumer SDK, with type signatures and code samples. The SDK is the canonical integration path; the underlying API endpoints are documented at /developer/docs.
Two npm packages. me-client is the consumer SDK; auth-client is the React provider + hook (re-exported by me-client for convenience).
# yarn (recommended)
yarn add @orangecheck/me-client @orangecheck/auth-client
# or npm
npm i @orangecheck/me-client @orangecheck/auth-clientMount OcSessionProvider once at the root. Every component below it can call useOcSession() to read the live cross-subdomain session.
- OcSessionProvider <OcSessionProvider config?={OcAuthConfig}>Default authOrigin is https://ochk.io. Override only in dev/staging.
// _app.tsx (Next.js Pages router) — wrap your app once.
import { OcSessionProvider } from '@orangecheck/me-client';
export default function App({ Component, pageProps }) {
return (
<OcSessionProvider>
<Component {...pageProps} />
</OcSessionProvider>
);
}Returns { status, account, signInUrl, signOut, refresh, error }. Status is loading | authenticated | anonymous | error. Account is null when not authenticated.
- useOcSession() () => OcSessionStateThrows if called outside an OcSessionProvider.
- useOptionalOcSession() () => OcSessionState | nullReturns null instead of throwing.
// any component
import { useOcSession } from '@orangecheck/me-client';
function Header() {
const { status, account, signInUrl, signOut } = useOcSession();
if (status === 'loading') return <Skeleton />;
if (status !== 'authenticated') return <a href={signInUrl}>sign in</a>;
return (
<div>
signed in as {account.address.slice(0, 8)}…
<button onClick={() => signOut()}>sign out</button>
</div>
);
}Class C billable atom — sites pay per session, not per click. create() opens a new session; refresh() and invalidate() are free, telemetry-only.
- oc.session.create(opts) (SignInOptions) => Promise<Session>Class C billable.
- oc.session.refresh(id) (string) => Promise<Session>Free.
- oc.session.invalidate(id) (string) => Promise<void>Free.
import { oc } from '@orangecheck/me-client';
const session = await oc.session.create({
scope: ['identity', 'payment'],
sessionPolicy: { duration_seconds: 7 * 86400, refresh: 'sliding' },
});
// refresh inside the window — free, telemetry only
await oc.session.refresh(session.id);
// invalidate when the user signs out — free
await oc.session.invalidate(session.id);Class B billable atom — sites pay a configured percentage of the underlying payment amount. The user is prompted by me.ochk.io to consent before this resolves.
- oc.payment.authorize(opts) (PaymentAuthorizeOptions) => Promise<PaymentResult>Class B billable; cashback streams to the user.
import { oc } from '@orangecheck/me-client';
const result = await oc.payment.authorize({
identity: 'bc1q...',
amount_sats: 240_000,
description: 'breez · march invoice',
});
// result.id, result.user_envelope_id, result.verify_url
// Class B billable event for your site; cashback streams to the user.Get and update your IntegratorPriceConfig. validate() runs the same validator the server uses, locally — useful for live form feedback without a round-trip.
- oc.config.get() () => Promise<IntegratorPriceConfig>
- oc.config.update(cfg) (IntegratorPriceConfig) => Promise<IntegratorPriceConfig>Throws on local invalidity; 422 on server rejection.
- oc.config.validate(cfg) (IntegratorPriceConfig) => ValidationResultNo network call.
import { oc, validateIntegratorConfig } from '@orangecheck/me-client';
// Read your live config
const cfg = await oc.config.get();
// Mutate it
await oc.config.update({
...cfg,
events: {
...cfg.events,
payment_authorization: {
enabled: true,
site_pays: { kind: 'percent_of_amount', pct: 0.0085 },
user_share_pct: 0.65,
},
},
});
// Validate without a round-trip
const result = validateIntegratorConfig(cfg);
if (!result.ok) console.error(result.errors);Verify OC webhook signatures against the published JWKS. ALWAYS pass the raw body bytes (not the parsed JSON) — frameworks that re-serialize before your handler will produce a different byte sequence and the signature will not validate.
- oc.webhook.verify(rawBody, sigHex, kid, jwk?) (string|Uint8Array, string, string, OcPublicJwk?) => Promise<VerifyResult>Auto-fetches and caches ochk.io/.well-known/jwks.json for 1h when jwk is omitted.
- oc.webhook.fetchJwks() () => Promise<OcPublicJwk[]>
// node · express raw-body verification
import { oc } from '@orangecheck/me-client';
app.use(express.text({ type: 'application/json' }));
app.post('/api/oc/webhook', async (req, res) => {
const sig = req.header('OC-Signature');
const kid = req.header('OC-Key-Id');
const result = await oc.webhook.verify(req.body, sig, kid);
if (!result.ok) return res.status(401).end(result.reason);
const envelope = JSON.parse(req.body);
await onOcEvent(envelope);
res.status(200).end();
});Class A billable atom — sites pay once per delegation. Issue scope-limited authority to an agent. Revoke instantly. Production republishes a Nostr kind-30085 revocation envelope so any verifier drops subsequent envelopes signed under the delegation.
- oc.delegation.issue(opts) (IssueDelegationOptions) => Promise<DelegationEnvelope>Max TTL 30 days. Class A billable.
- oc.delegation.revoke(id) (string) => Promise<{ ok: true }>Free.
import { oc } from '@orangecheck/me-client';
const env = await oc.delegation.issue({
agent_id: 'agent-pubkey-or-did',
scope: ['inbox.read', 'attest.verify'],
expires_at: new Date(Date.now() + 7 * 86400_000).toISOString(),
reason: 'inbox triage agent',
});
// env.id, env.scope, env.expires_at, env.verify_url
// later — revoke. verifier rejects any envelope signed after this point.
await oc.delegation.revoke(env.id);Fire any billable subtype your IntegratorPriceConfig enables — stamp_signing, attest_verification_at_gate, scoped_action_authorization, kyc_tier_upgrade, etc. session.create and payment.authorize are higher-level helpers; this is the escape hatch when you want one of the rarer subtypes. Class is determined by SUBTYPE_CLASS; cashback computed via computeFees(); recorded under your project_key.
- oc.event.fire(opts) (FireEventOptions) => Promise<BillableEvent>Returns the canonical BillableEvent the server recorded.
import { oc } from '@orangecheck/me-client';
// fire any billable subtype your IntegratorPriceConfig enables.
const stamp = await oc.event.fire({
project_key: 'pk_live_yourcompany',
subtype: 'stamp_signing',
action_label: 'review · march invoice',
});
// stamp.id, stamp.gross_fee_sats, stamp.user_earned_sats, stamp.verify_url
// for percent_of_amount-priced events, include the underlying amount:
const verify = await oc.event.fire({
project_key: 'pk_live_yourcompany',
subtype: 'attest_verification_at_gate',
payment_amount_sats: 50_000,
});Every type the SDK exports. Source of truth lives in oc-packages/me-client/src/types.ts and mirrors oc-me-web/src/lib/events/types.ts.
- EventClass
- EventSubtype
- AttestTier
- SiteFeeShape
- IntegratorEventConfig
- IntegratorPriceConfig
- ComputedFees
- ValidationResult
- BillableEvent
- Session
- SessionPolicy
- SignInOptions
- PaymentAuthorizeOptions
- PaymentResult
- TelemetryEvent
- OcAccount
- OcSessionState
- OcSessionStatus
- OcAuthConfig
- OcPublicJwk
- VerifyResult
- DelegationScope
- DelegationEnvelope
- IssueDelegationOptions
- PLATFORM_FEE_POLICY { pct: 0.2; min_floor_sats: 1; ratified: string }
- MIN_INTEGRATOR_PRICE_SATS number = 5
- computeFees(cfg, payment_amount_sats?) (IntegratorEventConfig, number?) => ComputedFees
- validateIntegratorConfig(cfg) (IntegratorPriceConfig) => ValidationResult