Developer integration
Ask before you use data.
Integrating ConsentOS takes four calls: announce your service, request permission, enforce the grant before doing the work, and verify receipts when you need proof. The @consentos/sdk package wraps them with no dependencies.
1. Create a client — on your server
Your API key identifies your service and never leaves your backend. In this build Pixly is seeded as a verified service; a full deployment would issue keys from a developer console.
consent.ts import { ConsentOS } from "@consentos/sdk" export const consent = new ConsentOS({ serviceId: "pixly", apiUrl: "https://consentos.vercel.app", apiKey: process.env.CONSENTOS_API_KEY, // server-side only })2. Request permission
Say exactly what you want: the data, the purpose, how long you keep it, whether it leaves your company. The user's rules decide deterministically. You get a decision, a machine-readable reason and — for ALLOW and DENY — a signed receipt. An ALLOW receipt is your grant.
enable-recommendations.ts const result = await consent.request({ userId, dataType: "uploaded_images", purpose: "personalization", retentionDays: 30, thirdPartySharing: false, }) switch (result.decision) { case "ALLOW": await saveGrant(userId, "personalization", result.receiptId) break case "DENY": showBlocked(result.reason) // e.g. RETENTION_EXCEEDS_LIMIT break case "REQUIRE_USER": // the user's rules want to be asked; they answer in ConsentOS const answer = await consent.waitForDecision(result.requestId) break }POST /api/v1/consent/evaluate → 200 { "requestId": "0f6c1d0e-…", "decision": "DENY", "reasonCode": "PURPOSE_DENIED", "reason": "Foundation-model training is blocked by the user's privacy policy.", "details": { "rule": "policy.foundationModelTraining" }, "evaluatedAt": "2026-09-26T14:32:08.114Z", "policyVersion": 3, "receiptId": "a1d4…", "receiptUrl": "https://consentos.vercel.app/receipts/a1d4…", "engineVersion": "1.0.0" }3. Enforce before you do the work
This is the part that makes consent real. Your protected endpoint asks ConsentOS whether the grant exists, belongs to this user and service, covers this purpose and data, is not revoked, and still verifies. If not, refuse. Do not trust a decision your own frontend reports.
app/api/train-model/route.ts export async function POST(req: Request) { const { grantId } = await req.json() const check = await consent.checkGrant({ userId, purpose: "foundation_model_training", dataType: "uploaded_images", receiptId: grantId, }) if (!check.authorized) { return Response.json( { error: check.code, message: check.message }, // CONSENT_VIOLATION | CONSENT_REVOKED { status: 403 }, ) } return startTraining() }4. Announce your service to the extension
One line in the browser lets the ConsentOS extension recognise your site, show the user what you are allowed to do, and refresh the moment a decision lands. The extension checks your page's origin against your registered domain, so another site cannot claim to be you.
app/layout.tsx (client) import { announceService, notifyDecision } from "@consentos/sdk/browser" announceService({ serviceId: "pixly", name: "Pixly" }) // after your backend receives a decision: notifyDecision({ requestId })5. Verify receipts
Receipts are SHA-256 over canonical JSON (sorted keys, no whitespace), signed with Ed25519. Anyone can check them against the public keys; no ConsentOS account needed.
audit.ts const result = await consent.verifyReceipt(receiptId) // { valid: true, payloadIntact: true, signatureValid: true, // requestHashValid: true, policyHashValid: true, revoked: false, … }
Endpoints
| Endpoint | Auth | Purpose |
|---|---|---|
| POST/api/v1/consent/evaluate | Service key | Ask to use data for a purpose. Returns ALLOW, DENY or REQUIRE_USER. |
| POST/api/v1/grants/check | Service key | Runtime enforcement: is this use permitted right now? |
| GET/api/v1/consent/requests/:id | Service key | Poll a REQUIRE_USER request until the user answers. |
| GET/api/v1/receipts/:id | Service key or user | The full signed receipt document. |
| GET/api/v1/receipts/:id/verify | Public | Recompute hashes and check the signature. |
| POST/api/v1/receipts/verify | Public | Verify a receipt document you hold. |
| GET/api/v1/keys | Public | Ed25519 signing keys as a JWK set. |
| GET/api/v1/services/:id | Public | Directory entry for an integrated service. |
Purposes
essential
Storing what a service needs to work at all — your account, your uploads, your settings.
analytics
Measuring how a product is used so it can be improved.
personalization
Using your activity to tailor what you see inside the service.
advertising
Using your data to choose which ads you are shown.
foundation_model_training
Using your content to train general-purpose AI models.
third_party_sharing
Passing your data to other companies.
precise_location
Using your exact location rather than a city or region.
Data types
- uploaded_images
- profile
- account
- email_address
- usage_events
- device_info
- contacts
- messages
- coarse_location
- precise_location
Anything outside these lists is valid to send, and is escalated to the user rather than guessed at.
Reason codes
Checks run in a fixed order and combine deny-overrides: any deny wins, then any ask, otherwise allow.