Accept Notlogin agent credentials
Agents present a Notlogin-signed Verifiable Credential. Your backend verifies it offline against our public keys — no API key on your side, no round-trip in the hot path. A valid cert means a pre-authorized, verified-human tier; an invalid one just falls back to your anonymous tier.
Two ways in: the SDK (agents POST a credential to your endpoint) or "Sign in with Notlogin" (standard OIDC redirect). Pick whichever fits your product — you can offer both.
1 · Install the SDK
npm i notlogin-sdk viem
2 · Verify credentials in your backend
Five lines anywhere a request from an agent arrives. Tune requiredProofs to your bar (you can change it any time in the portal).
import { verifyCredential, recordRedemption } from 'notlogin-sdk'
const result = await verifyCredential(req.body.vcJson, {
vendorSlug: 'your-slug', // your registered slug
requiredProofs: ['email'], // your verified-human bar
// brokerUrl defaults to https://notlogin.com; mode defaults to 'online'
})
if (!result.valid) {
// Fall back to your anonymous-agent tier, or refuse the upgrade.
return res.status(403).json({ reason: result.reason })
}
// You can now trust: result.issuer, result.scope, result.verifiedProofs,
// result.budgetUsdcCents, result.remainingCents, result.expiresAt, result.credentialId
const apiKey = mintYourApiKey({ tier: 'verified-human' })
// Keep the broker budget ledger in sync (optional but recommended):
await recordRedemption({ credentialId: result.credentialId!, vendorSlug: 'your-slug', vendorApiKey: apiKey })
return res.json({ apiKey, tier: 'verified-human' })3 · Or drop in a framework middleware
Same verification, one line. Express / Hono / Next.js App Router:
import { notloginMiddleware } from 'notlogin-sdk/express'
app.post('/agent-action',
notloginMiddleware({ vendorSlug: 'your-slug', requiredProofs: ['email'] }),
(req, res) => {
if (!req.notlogin?.valid) return
res.json(req.notlogin.result)
})import { notloginMiddleware } from 'notlogin-sdk/hono'
app.post('/agent-action',
notloginMiddleware({ vendorSlug: 'your-slug', requiredProofs: ['email'] }),
(c) => {
const notlogin = c.get('notlogin')
if (!notlogin.valid) return c.json({ error: 'unauthorized' }, 403)
return c.json(notlogin.result)
})import { NextResponse } from 'next/server'
import { withNotlogin } from 'notlogin-sdk/next'
export const POST = withNotlogin(async (req) => {
if (!req.notlogin?.valid) return NextResponse.json({ error: 'unauthorized' }, { status: 403 })
return NextResponse.json(req.notlogin.result)
}, { vendorSlug: 'your-slug', requiredProofs: ['email'] })Verification modes
online (default) also checks the broker for revocation + remaining budget and returns credentialId. offline does local signature/expiry/proof checks only — sub-millisecond, no round-trip. Use offline only right after an online check of the same cert.
verifyCredential(vc, { vendorSlug: 'your-slug', mode: 'offline' }) // local-only, no revocation
verifyCredential(vc, { vendorSlug: 'your-slug', mode: 'online' }) // default, + revoke + budget"Sign in with Notlogin" (OIDC)
Prefer a redirect flow? It's standard OIDC + PKCE. Add the button (see brand kit), then exchange the code server-side. Discovery lives at /.well-known/openid-configuration.
// On your callback (user returns with ?code=...), exchange it server-side:
const r = await fetch('https://notlogin.com/api/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
// redirect_uri must match the one you sent to /authorize. code_verifier is
// required unless you authenticate with a registered client_secret.
body: JSON.stringify({
code: req.query.code,
code_verifier: pkceVerifier,
redirect_uri: 'https://your-app.com/auth/notlogin/callback',
}),
})
const { sub, verifiedProofs, id_token, access_token, refresh_token } = await r.json()
// sub = stable user id · id_token = EdDSA JWT (verify against /.well-known/jwks.json)Get paid (x402, USDC)
Agents pay from their human's managed wallet, inside the credential's budget. Answer HTTP 402 with your price; the agent settles through POST /api/x402/pay (or presents a gasless X-PAYMENT header) and retries with the tx hash. Register a payout address in the portal and every agent payment for your vendor is pinned to it. Settled payments carry a signed receipt you can verify offline against the same issuer keys as credentials:
{ "receipt": { "schema": "notlogin/receipt/v1", "paymentId": "...", "vendorSlug": "your-slug",
"payTo": "0x...", "amountCents": 150, "network": "base", "txHash": "0x...", "settledAt": "..." },
"signature": "<base64url Ed25519 over the canonical receipt JSON>",
"kid": "<key id in /.well-known/notlogin-issuer.json>" }Need to charge without the agent in the loop? Ask for a charge grant at OIDC consent and call POST /api/x402/charge with your client secret (amounts above the user's threshold wait for their approval). Running a marketplace? The escrow gateway (/api/x402/gateway/*) adds refunds, releases to sellers and a hosted checkout. Trading apps can request a capped trade mandate over the user's wallet. Full contracts, bodies and error codes: llms-full.txt.
Test it
The vendor portal has a one-click test: it mints a real credential for your account, checks it against your required proofs and — for SDK vendors — submits it live to your endpoint. Or from your terminal:
npx tsx agent-demo/integration-test.ts --vendor https://your-site.com --vendor-slug your-slug
Register your service and verify your domain — no review queue.