Consent
Installing your app is a decision a human makes. The consent screen is where they make it, and it is generated from two things you wrote: your access register, and the reason you gave for each entry in billing.json.
What the merchant sees
Not the JSON. The register rendered in plain language, one line per grant, with your reason under the ones you explained — and, for a paid app, the plan and the price. Roughly:
This app will be able to:
Read and write its own serial registry
Read your orders
→ Link a registered serial to the order that sold it.
Contact api.acme-service.example
→ Register warranties with the manufacturer.
So the register is not a configuration detail. It is the text of an agreement, and it is read by somebody who is deciding whether to trust you with a live commerce tenant.
Write for the person reading it
Two files do the work, and the second is the one most apps neglect.
manifest.permissions says what:
"permissions": [
{ "entity": "device_serials", "access": ["read", "create", "update"] },
{ "capability": "orders.get", "compatible": "^1.0" },
{ "outbound": "api.acme-service.example", "paths": ["/v2/warranties/*"] }
]
billing.json's listing.scopes says why:
"listing": {
"scopes": [
{ "scope": "orders.read", "reason": { "en": "Link a registered serial to the order that sold it." } }
]
}
A reason is a sentence about their business, not about your architecture:
| Write | Not |
|---|---|
| "Link a registered serial to the order that sold it." | "Requires read on orders." |
| "Register warranties with the manufacturer." | "Outbound HTTP to api.acme-service.example." |
| "Create a login for each contact so they can use the portal." | "Needs identity write scope." |
An unexplained grant is not neutral. A merchant reading "read your orders" with no reason has to decide what you might do with it, and the safe assumption is rarely the flattering one.
Claim the least you can
Everything on that screen has to be justified to somebody who is not you, so:
An entry you never exercise makes the decision harder for no benefit. It also widens your blast radius for nothing.
Grant per operation. ["read", "create"] on a ledger is a real safety property you can point at. ["read", "create", "update", "delete"] everywhere tells the merchant you did not think about it.
Narrow an outbound host and its paths. { "outbound": "*" } makes the screen unanswerable, and an unanswerable screen is an app nobody installs.
Do not declare an unproven grant speculatively. A merchant consenting to ai or mail for a feature that does not work yet will ask why.
What changes when you add a grant
A new grant is a new thing the merchant is consenting to. Adding one is not a patch-level change in spirit, whatever the version number says.
The habit that keeps this from going wrong:
Say it in the release notes. "This version also reads your orders, to link a serial to the order that sold it." A merchant who is asked to consent again deserves to know what changed before they are asked.
Add the reason in the same commit as the grant. A grant with no reason is the one that stalls an install.
Remove the grant when you remove the code. In the same version. A register describing an app that no longer exists is worse than no register: it teaches the merchant that your list is not to be trusted.
Read the whole array before a major. If you cannot say which route or handler needs an entry, delete it and see what breaks in staging.
That is the discipline against consent drift — a grant added for a feature that shipped, a host left behind after a vendor change, an identity grant surviving the code that needed it. Six versions later the screen describes something else entirely.
Consent is not permission for everything
Worth being clear about what the merchant has and has not agreed to, because two adjacent mechanisms are not covered by it:
Consent is app-to-resource. It says your app may reach a thing. It says nothing about whether a particular person in that tenant may do something — that is person permissions and the Cockpit view gates.
Consent is not tenant isolation. Scoping to the calling tenant is unconditional and not something a merchant grants or could waive. See Tenant isolation.
Next steps
- Permissions — the register itself.
- Billing — where the reasons live.
- Publish and install — what happens after they click install.
- Private or Marketplace — who ever sees this screen.