How scope checking works
Every /public/v1/* route can declare one or more required scopes via requireScope("scope-string", ...). At request time, the middleware checks that all required scopes are present in req.marketplaceAuth.scopes (the array stored on the AppInstall row).
A missing scope returns:
HTTP/1.1 403 Forbidden{
"error": "insufficient_scope",
"message": "Missing scope: invoices:read",
"required": ["invoices:read"]
}Scopes are granted by the user during the OAuth install consent screen. To gain a new scope, the user must re-install (or re-authorize) your app — you cannot self-elevate.
Scope catalog
The scopes below are wired into routes today. Some routes return 501 not_implemented while their handlers are being built — the scope check still applies.
| Scope | Authorizes |
|---|---|
invoices:read | GET /public/v1/orgs/:o/entities/:e/invoices, GET .../invoices/:id *(handler stubbed — 501 today)* |
bills:read | GET /public/v1/orgs/:o/entities/:e/bills *(handler stubbed — 501 today)* |
customers:read | GET /public/v1/orgs/:o/entities/:e/customers *(handler stubbed — 501 today)* |
Webhook subscription endpoints (POST/GET/DELETE /public/v1/orgs/:o/entities/:e/webhooks) do not currently require an additional scope beyond a valid install — auth + tenant guard are sufficient.
Manufacturing scopes (planned)
Once manufacturing is wired into the public gateway (see Manufacturing API roadmap), the scopes will follow the same <resource>:<action> pattern that the internal surface uses today:
bom:read,bom:create,bom:update,bom:deleteworkOrder:read,workOrder:create,workOrder:update,workOrder:deleterecipe:read,recipe:create,recipe:update,recipe:deletequalityInspection:read,qualityInspection:create,qualityInspection:update,qualityInspection:deletesubcontractOrder:read,subcontractOrder:create,subcontractOrder:update,subcontractOrder:deletemanufacturingReport:read
These scope names are stable on the internal surface today. Public-API exposure is roadmap.