Operations
An operation is one request your software makes to the commerce provider. For a purchase, the important order is verify → connect the owner → read access.
These calls keep separate questions separate: a valid receipt, its owner, and today’s access can have different answers. Follow Alice through those steps →
Find the call you need#
Check what a provider supports#
Before connecting, ask which services, stores, and API formats this backend supports. This public answer contains no customer purchase data.
Use it to choose a compatible provider before sending purchases.
Compare the example and IAPKit
Different scope, declared explicitly
Run the flow locallyopeniap-commerce-protocol-example
The descriptor names a fictional fixture store and makes no complete-profile claim. All six REST operations let you study the flow, including account deletion; they do not establish support for real stores or the full protocol.
Read code: capabilities See the service implementationIAPKit
IAPKit declares profiles, both API bindings, and support per store. Apple and Google have subscription events; Meta and Amazon do not. Read the descriptor before choosing a store integration.
Read code: PROVIDER_CAPABILITIES How to check this behavior
Example. Local checks validate the teaching flow and published vectors. They are not a full provider conformance report. Inspect reference
IAPKit. Capability tests compare the served descriptor, store mappings, and implementation declarations. Inspect reference
API details · providerCapabilities
- Operation
providerCapabilities- REST request
GET /commerce/v1/capabilities- Responsibility
- Core: every provider supports discovery.
- Credential
- None: public discovery
Check the purchase evidence#
Send the store’s evidence and receive isValid. A valid purchase is not yet connected to an app user and does not by itself grant access.
Alice’s receipt is valid. Next, authorize and record who owns it.
Compare the example and IAPKit
Same question: is the evidence valid?
See the service implementationIAPKit
The handler sends evidence to the Apple, Google, Meta, or Amazon verifier and returns the same isValid answer. Store-specific work stays behind this call.
Read code: verifyPurchaseVerdict How to check this behavior
Example. The Verify step checks isValid and confirms that Alice still has no access. Run npm test. Inspect reference
IAPKit. The route suite checks unreachable verification and retry behavior using mocked store I/O. Inspect reference
API details · verifyPurchase
- Operation
verifyPurchase- REST request
POST /commerce/v1/purchases/verify- Responsibility
verification profile- Credential
- verification role
Connect the purchase to its owner#
Your authenticated backend selects Alice and asks the provider to associate the verified purchase with her. Repeating this request keeps the same owner.
Continue on bound: true. A false result covers both unknown evidence and an ownership conflict; it never tells Bob whose purchase exists.
Compare the example and IAPKit
Same owner after a retry
See the service implementationIAPKit
The protocol handler calls bindUserAsServer. Convex checks the project’s server credential and records ownership without moving a purchase already owned by another user.
Read code: bindUserAsServer How to check this behavior
Example. The Bind step repeats Alice’s request and rejects Bob’s claim. Run npm test. Inspect reference
IAPKit. Binding tests cover repeated and conflicting claims against the subscription mutation handlers. Inspect reference
API details · bindPurchase
- Operation
bindPurchase- REST request
POST /commerce/v1/purchases/bind- Responsibility
accountLifecycle profile- Credential
- server role
Read which products the user can access#
Ask for Alice’s current productIds. Your backend unlocks a feature only when its product is in that list. The answer includes supporting subscription records, without purchase tokens.
Premium in the list: allow Premium. Empty list: no current access. A request failure is not an empty list or a new grant.
Compare the example and IAPKit
Same access rule, different storage
See the service implementationIAPKit
isEntitledAt applies the same rule to Convex records. entitlementsV2 reads the current time and returns allowed products without exposing store purchase tokens.
Read code: isEntitledAt How to check this behavior
Example. The state checks test before, at, and after expiry with a controlled clock. Run npm test. Inspect reference
IAPKit. Account-read tests check token omission, server authorization, and time advancing past expiry. Inspect reference
API details · entitlements
- Operation
entitlements- REST request
GET /commerce/v1/entitlements- Responsibility
entitlements profile- Credential
- server role
Read the subscription’s current status#
Use this for a subscription status screen or an “any active subscription?” check. It returns active and, when available, a supporting subscription record.
Canceling renewal can leave active: true until expiry. For product-specific access, use entitlements.
Compare the example and IAPKit
Explain why access continues
See the service implementationIAPKit
subscriptionStatusV2 selects a subscription and applies the same access deadline. The protocol handler turns that record into the shared response shape.
Read code: subscriptionStatusV2 How to check this behavior
Example. Cancel and Expire compare the status response with current entitlements. Run npm test. Inspect reference
IAPKit. The contract vectors compare status and access over REST and GraphQL with an in-memory database substitute. Inspect reference
API details · subscriptionStatus
- Operation
subscriptionStatus- REST request
GET /commerce/v1/subscriptions/status- Responsibility
entitlements profile- Credential
- server role
Remove the user’s identity#
When Alice deletes her account, ask the provider to remove her identity from its subscription records and protocol event store. Repeating the request is safe.
accepted acknowledges the request. A provider may report an erasure job. Your backend and other event recipients must erase their own copies separately.
Compare the example and IAPKit
Delete the account in both implementations
See the service implementationIAPKit
eraseUser starts a project-scoped job. The worker removes identity from purchases, subscriptions, and events in batches, waiting for claimed deliveries before cleaning those events.
Read code: drainSubscriptionUserErasurePage How to check this behavior
Example. Run bun verify-erasure.mjs. It checks active-account erasure, in-flight delivery, repeated jobs, late events, and restart. Inspect reference
IAPKit. Erasure request tests cover server authorization and repeated requests, including already completed jobs. Inspect reference
API details · eraseUser
- Operation
eraseUser- REST request
POST /commerce/v1/users/erase- Responsibility
accountLifecycle profile- Credential
- server role
The same operation meanings apply over REST and GraphQL. Repeated requests are idempotent: they do not repeat the business effect. Providers must report an error when they cannot produce a complete answer.
Exact inputs, outputs, and behavior: SPEC.md §4.