Conformance
Conformance checks test whether a provider keeps the contract it advertises. If it promises to connect purchases to users, for example, a verification-only credential must not be able to change an owner.
Use this when reviewing your implementation or comparing providers. Ask for a passing report tied to the source and configuration you will run. An API response with the right field names is only part of that evidence.
- Choose the responsibilities and REST or GraphQL format the provider supports.
- Run the checks against an isolated instance with disposable users.
- Fix failures, rerun, and keep the result with the implementation.
Read the checks alongside the implementation
openiap-commerce-protocol-example
verify.mjs replays the purchase flow, expiry boundaries, signatures, retries, and receiver recovery. These checks explain what this small backend demonstrates; it makes no full-profile claim.
Read code: verifyLabThe published conformance runner calls IAPKit’s real REST and GraphQL routes against fixture store/database I/O. Separate worker and mutation tests cover persistence responsibilities.
Read code: IAPKit dual-binding conformanceHow to check this behavior
Example. Install dependencies, then run npm test in the example repository. Bun runs its HTTP server and SQLite. Inspect reference
IAPKit. Run bun run test -- server/api/commerce/conformance.test.ts convex/commerce/spec.conformance.test.ts from packages/kit. These are local contract checks, not live store tests. Inspect reference
Run and read the checks#
Runner setup and implementation requirements
First run the runnable local example to explore the purchase flow. It does not claim full profile conformance. To test your own implementation, use an isolated test instance with disposable identities: the operation vectors call binding and erasure as well as reads. Supply credentials from that instance.
Install openiap-commerce-protocol and ajvwith your package manager. Save this as check-conformance.mjsand run it with Node.js or Bun. The built-in adapters add the Bearer prefix: supply token values without that prefix. Set COMMERCE_GRAPHQL_URL only when testing that binding.
import Ajv from "ajv/dist/2020.js";
import {
createRestAdapter,
createGraphqlAdapter,
runConformance,
} from "openiap-commerce-protocol/conformance";
const baseUrl = process.env.COMMERCE_BASE_URL;
const credentials = {
verification: process.env.COMMERCE_VERIFICATION_TOKEN,
server: process.env.COMMERCE_SERVER_TOKEN,
};
if (!baseUrl || !credentials.verification || !credentials.server) {
throw new Error("Set the test provider URL and both role tokens.");
}
const adapters = [createRestAdapter({ baseUrl, fetch, credentials })];
if (process.env.COMMERCE_GRAPHQL_URL) {
adapters.push(createGraphqlAdapter({
url: process.env.COMMERCE_GRAPHQL_URL, fetch, credentials,
}));
}
const report = await runConformance({
adapters,
Ajv,
credentials,
// Add your eventsAdapter here if the provider declares the events profile.
});
console.log(JSON.stringify(report, null, 2));
process.exitCode = report.ok ? 0 : 1;The runner talks only through the fetch you give it; the URL may point to a local test provider. A provider whose capability descriptor declares the events profile also supplies an eventsAdapter — the runner drives §9 signing, verification, the delivery envelope, response semantics, the entitlement gate, and the emission rules through it, and a signing-only adapter fails.
Implement the EventsAdapter interface in the installed conformance/index.d.ts against your own emitter. An advertised events profile without this adapter fails the run. Read report.results and report.parityFailuresfor failures; the script exits nonzero when report.ok is false.