Invite Member
POST /roles/invite
Invite one person into the organisation, at a role below administrator.
status in the response is the app’s own: invited when an invitation
email went out to someone with no graph8 account, added when the person
already had one and now holds the role immediately. Re-inviting the same
address is safe - the pending invitation is UPDATED to the new role rather
than duplicated - so a reconciliation loop may call this once per row.
ADMINISTRATOR ROLES ARE REFUSED HERE, AND THAT IS WHY THIS ROUTE CAN EXIST
AT ALL. The module docstring withholds every route that can end with a
person holding PropelAuth Owner or Admin. The reason is specific:
build_api_principal can answer AS an org administrator, and the app’s
_assert_can_grant_permissions bypasses its non-escalation check for a
privileged org role - so a bare proxy of the app handler would let a
credential mint an administrator. Capping the role here removes exactly
that, and leaves the capability that was actually asked for: admitting
members and project roles in bulk from a script, a workflow or an agent.
Granting administration stays a decision for a person, in the product.
422 when neither or both of role_id/role are given; 404 when the role is
not this organisation’s; 403 when the role is administrator-equivalent, or
when the app refuses the grant because the key’s own permissions do not
cover the role’s.
Authorizations
Parameters
Header Parameters
Request Body required
Invite one person into the organisation. Mirrors roles.InviteUserRequest
with ONE addition: the role may be named instead of identified by UUID.
The app model takes role_id: UUID only, because its caller is a role
picker that already holds the id. An API caller holds a NAME - “Engineer”,
“Member” - and making it fetch GET /roles first to translate is a round
trip this contract can absorb. So exactly one of role_id or role is
required; role is resolved against this organisation’s own roles by slug
first, then by case-insensitive display name.
role is deliberately NOT defaulted to “Member”. An absent role on an
invitation is a caller mistake, and silently picking the fallback is how
someone ends up in an organisation at a permission level nobody chose.
Responses
201
Successful Response
object
An open envelope for a single role, team, member or account record.
Open on purpose. The app’s own response models on this surface grow with
the product - RoleResponse gained rep_limits and manages_role_slugs,
TeamResponse gained channel counts and a campaign count - and a pinned
mirror would SILENTLY DROP whatever it had not caught up on. A dropped
permission in a role read is the worst possible kind of stale: it reads as
“they do not have it”.
object
object
Whether there are more pages
Items per page
Current page number (1-indexed)
Total number of items
422
Validation Error