This recipe sells a Team plan with 1,000 report exports a month, shared by everyone on the customer's team. When you are done:
- the person who buys becomes the owner of the customer's organization and invites colleagues by email;
- a colleague who joins works in the same organization, so their exports count against the same 1,000;
- only the owner and admins can change billing or invite; members just use the product.
There is nothing team-specific in your backend. A buyer organization is the unit that subscribes, and the session token of every member names it, so ruling and reporting by organization_id already shares the allowance.
How it works
| Object | In this recipe |
|---|---|
| Buyer organization | The customer's team, for example Acme Analytics. It holds the subscription and the allowance |
| Member | An end-user account in that organization, with the role OWNER, ADMIN, MEMBER or VIEWER |
| Session token | Issued to one end user, for one organization at a time; organization_id in its claims is that organization |
Buyer organizations describes roles, invitations and switching in full.
1. Define the Team plan
Create a plan with the allowance shared by the team, as in the other recipes:
PUT /mgt/v1/projects/{projectId}/plans/{planId}/versions/1/rules
Authorization: Bearer <operator session token>
Content-Type: application/json
{ "rules": [{ "capability_id": "<report_exports>", "allowance": 1000, "reset_interval": "MONTHLY" }] }Then publish it. The allowance belongs to the organization, not to each member: five members share 1,000, they do not get 1,000 each.
2. The buyer signs up and subscribes
The person who signs up without an invitation gets an organization of their own, with the name they give and them as owner. They subscribe it to Team through PricingTable and checkout; as an owner or admin, they are allowed to change billing. This needs Allow self sign-up turned on, under Settings, Project, Customer sign-in. It is off by default, and until it is on no end user can create an account, not even an invited one; see Who may create an account.
3. The owner invites the team
Owners and admins invite by email, with the Public API and their own session:
POST /public/v1/organizations/{orgId}/invitations
Authorization: Bearer <access token of an owner or admin>
Content-Type: application/json
{ "email": "<invited email address>", "role": "MEMBER" }{orgId} must be the organization of the session. ShipRev mails the invitation; the token travels only in that email, with a link to the hosted invitation page on your brand domain, or to your own sign-in page with an invitation_token query parameter if you set a custom sign-in address.
Give owners and admins a place to do this in your product, for example a members page that calls this endpoint through your forwarding path.
4. The colleague joins
What the invited person does depends on whether they already have an account on your gate:
| They | What they do | Result |
|---|---|---|
| Have no account | Sign up from the invitation: POST /public/v1/auth/register with email, password and invitation_token, or the hosted page | Their account joins the inviting organization and gets no organization of its own. The email is verified by the invitation, so the session is issued at once |
| Already have an account | Sign in, then POST /public/v1/invitations/accept with { "token": "<invitation token>" } | They become a member, and keep their other organizations |
GET /public/v1/invitations/info?token=<token> shows the organization's name, the email and the role before either, without a session.
Someone who belongs to more than one organization works in one at a time. GET /public/v1/organizations lists them and POST /public/v1/auth/switch with an organization_id returns an access token for the other one. Your backend sees whichever organization the token names.
5. Your backend: nothing changes
Rule and report with the organization from the verified token, as on any route:
const claims = await shiprev.verifyToken(token); // the member's own session
const ruling = await shiprev.adjudicateAsync({
organization_id: claims.organization_id, // the team's organization
capability_key: 'report_exports',
quantity: 1,
operation: 'write',
});
// ... run the export, then report it with the same claims.organization_idWhat one member uses, every member sees used. If a member exports 40 times and the owner 10 times, both of them are ruled with remaining 950 and limit 1,000, and UsageMeter shows 50 used to either of them.
Your backend receives the organization in the token, not the member's role. Decide what a member may do in your product with the organization's entitlements, and keep finer permissions of your own, such as who may delete a report, in your application.
6. What members can and cannot do in ShipRev
| Action | Owner, admin | Member, viewer |
|---|---|---|
| Use the product within the allowance | Yes | Yes |
| See the subscription, members and usage | Yes | Yes |
| Invite, change roles, remove members | Yes; only owners manage other owners | Refused with 403 FORBIDDEN |
| Change plan, cancel, pay | Yes | Refused with 403 INSUFFICIENT_ROLE |
Show billing and invitation actions only to owners and admins. The session that sign-in and sign-up return carries the role in account.current_role, for the organization the session is in; a refused request reaches the components' onError.
Try it
- Publish Team and sign up a test end user, the owner. Activate their organization on Team, through checkout in Stripe's test mode or by hand with
POST /mgt/v1/projects/{projectId}/subscriptions/activate. - Invite a second address as
MEMBER, open the mail and sign up from it. Verify the new member's token in your backend:organization_idis the owner's organization. - Export as the member, then as the owner. Both rulings show the same
remaining. - As the member, try
POST /public/v1/subscriptions/cancel. Expect403withINSUFFICIENT_ROLE. - Invite an address that already has an account of its own, accept as that account, switch to the team's organization and verify the new token: it names the team's organization.
Variations
- More allowance for larger teams. Publish a second plan, Business, with a larger allowance; the owner moves the organization to it like any plan change.
- Several teams per customer. Each team is its own organization with its own subscription; an end user can be a member of several and switch between them.