Skip to content

Permissions

Each business-scoped endpoint requires a resource:action permission. Sessions use the person’s role. API keys and OAuth connections use their granted permissions, limited by what their creator was allowed to grant.

Scope What it allows
tenant:read See the business and who is in it.
customers:read Read customers, and export them as CSV.
customers:write Add and change customers, and record or remove their marketing consent.
products:read Read what the business sells and its prices.
products:write Change products and agreed customer rates.
orders:read Read orders.
orders:write Take orders and change them.
rounds:read Read rounds, vehicles, and the bases they start from.
rounds:write Plan rounds and change them.
drivers:read See which vehicle each driver usually takes.
drivers:write Change which vehicle a driver usually takes.
rota:read See shifts, time off and cover. A driver sees only their own.
rota:write Run the rota: shift patterns, time off, cover and approvals.
timeoff:write Ask for time off. A driver asks only for their own.
deliveries:write Record delivery outcomes, proof and round departure.
members:read See who works there.
members:write Change what people can do, and remove them.
invitations:read See open invitations.
invitations:write Invite people and cancel invitations.
keys:read, keys:write Manage API keys. Never granted to a key or a connection.
connections:read, connections:write Manage connected apps. Requires a signed-in person.
shops:read, shops:write Connect a shop, pull its catalogue and copy its website into the shop. Never granted to a key or a connection.
storefront:read See the business’s own shop: its settings, the draft, what is live and its addresses.
storefront:write Edit, publish or take down the business’s own shop, upload its pictures and manage its domains. Owners and admins only.
billing:read Read the plan and the invoices Bottle has raised, and what is in the business’s own Stripe account.
billing:write Change the plan. Never granted to a key or a connection.
privacy:read See the retention rules, what is due and what has been erased.
privacy:write Change retention rules and erase customer records. Not available to API keys.

Monetary amounts use integer pence: 5400 means £54.00. Product prices exclude VAT; check the endpoint’s field descriptions for totals and tax breakdowns.

Bottle currently supports sterling. Shop imports in other currencies are rejected.

billing:read is granted like any other scope, and is what an accounting integration or an assistant answering “what do we pay for Bottle” needs. It covers the plan, the trial, the renewal date and every invoice, each with a link to the invoice itself.

Only a signed-in owner can change the subscription. billing:write cannot be granted to API keys or OAuth connections.

Owners have every scope. Admins have every scope except billing:write.

Drivers can read their assigned rounds and products, record deliveries, manage their own connections and record round departure and return. They cannot browse the full customer list, team records or business finances. For van sales, GET /rounds/{id}/customers provides a limited customer search.

Round access is also restricted by role. Drivers can read and record outcomes only for their assigned rounds. Requests for another driver’s round return 404.

Role still matters after the scope check. An admin holds members:write but cannot change an owner, and the last owner cannot be demoted.

{ "error": "missing_scope", "message": "This needs the members:write permission, ..." }

missing_scope means the caller lacks the required permission. forbidden means the permission exists but does not allow this specific action or record.

Some areas start on a bigger plan: rounds and planning, vehicles, the rota and drivers, cash taken by drivers, regular orders, several yards and delivery partners. Each endpoint in one of them carries x-plan-area in the OpenAPI document, naming the area: rounds, vehicles, rota, cash, standingOrders, yards or deliveryPartners.

When the business’s plan does not open the area, the request is refused after the scope check, reading included:

{
"error": "plan_locked",
"area": "rounds",
"message": "Rounds is not on your plan. It starts on Yard. An owner can move up under Billing."
}

The refusal is the same for a session, an API key and a connected assistant. Assistants are not offered tools for a closed area at all. GET /billing returns features, one true or false for each area, so an integration can check first. A second base (POST /locations) counts as several yards.

Nothing is deleted when a business moves to a smaller plan. The records come back when it moves up again.