API surface. Platforms create and update merchant accounts over REST (/v1/accounts, GET /v1/account). Identity providers, memberships, invitations, roles, API keys and account suspension are administered over GraphQL Interface.
Platforms that run shipping for many businesses need to create those businesses, let their people sign in with the identity provider they already use, and decide what each person may do. The spec keeps three concerns apart, so that any of them can change without touching the others: An identity can hold memberships in many accounts. An account can trust several identity providers. Swapping a merchant from Google to Okta changes one identity_provider, and no membership, role or shipment changes.

1. Account

Endpoints

Closing an account revokes its keys and tokens, deletes its connections and webhook endpoints, and keeps shipment records for the retention period (chapter 10 §9).

2. Identity providers (SSO)

type may also be saml where the implementer offers it (capability accounts.saml). Everything downstream is the same, because a SAML assertion is mapped to the same identity shape. GraphQL: identityProviders, identityProvider, createIdentityProvider, updateIdentityProvider, deleteIdentityProvider, verifyDomainIdentityProvider (GraphQL Interface mutation), and testIdentityProvider (GraphQL Interface mutation), which returns a sign-in URL for testing the configuration.

3. Memberships and roles

  • identity is the (issuer, subject) pair. It is never an email alone, because emails change and get reused. email is informational.
  • source is invitation, jit, scim, idp_group, or api.
  • status is invited, active, suspended, or removed.
Roles bundle the same scopes OAuth uses (chapter 00 §3.2), so a person and an API key are authorized by one vocabulary: Custom roles: createRole (GraphQL Interface mutation) with { name, scopes[] }. Endpoints:
An invitation is accepted by signing in through any provider the account trusts, or the implementer’s own sign-in for accounts without SSO. The resulting identity is bound to the membership, and the email only routes the invitation.

4. API keys

createApiKey (GraphQL Interface mutation) returns secret once. Other endpoints: apiKeys (GraphQL Interface query), apiKey, updateApiKey (name, scopes, allowed_ips), rollApiKey (GraphQL Interface mutation) ({ expire_previous_in }), and deleteApiKey (GraphQL Interface mutation). system_metadata.created_by on every object references the key or membership that created it.

5. Seamless platform SSO (token exchange)

A platform whose users are already signed in, through the platform’s own IdP, should not make them sign in again to ship. The platform exchanges the user’s ID token for a scoped access token to one merchant account, using OAuth 2.0 Token Exchange (RFC 8693):
Rules:
  • The platform’s IdP must be registered as an identity_provider on the platform account. Child accounts inherit trust from their parent unless they configure their own.
  • The issued token’s scopes are the intersection of the requested scopes, the membership’s role, and the client app’s allowed scopes. It is never wider than any of them.
  • Tokens last at most 1 hour and are not refreshable. The platform repeats the exchange.
  • Each action is attributed to the person’s membership, not to the platform’s app. Audit trails name real people.

6. Events

account.created, account.updated, account.requirements_updated, account.suspended, account.closed, identity_provider.created, identity_provider.updated, identity_provider.domain_verified, membership.created, membership.updated, membership.removed, invitation.accepted, api_key.created, api_key.rolled, api_key.deleted. Platforms receive their children’s account events on their own endpoints.