A valid request URL is required to generate request examples{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"email": "jsmith@example.com",
"role": "owner",
"role_name": "Owner",
"invited_by_contact_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"created_at": "2023-11-07T05:31:56Z",
"expires_at": "2023-11-07T05:31:56Z"
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}Invite someone onto the team
Owner only. Creates the invitation and emails the link, in the organization’s name. Valid for 7 days, one pending invite per address per customer.
The answer says nothing about whether that address already has an account here. The one conflict it does report — already_member — is membership of the caller’s own team, which they can already read off GET /v1/contact/customer/members. Every other case takes the identical path.
The team’s plan may cap seats. When the plan of the team’s subscription names a seat feature, the invitation is checked against that limit — counting members and pending unexpired invitations, so three invitations sent in a row cannot each pass a cap of three. Past it the answer is 402 seat_limit_reached, and the way out is upgrading the team’s plan (or freeing a seat). A team on no plan, or on a plan naming no seat feature, has no limit.
Each request mails somebody else’s inbox, so this route is limited strictly: per contact session and per client IP.
A valid request URL is required to generate request examples{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"email": "jsmith@example.com",
"role": "owner",
"role_name": "Owner",
"invited_by_contact_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"created_at": "2023-11-07T05:31:56Z",
"expires_at": "2023-11-07T05:31:56Z"
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}Authorizations
A contact session token, uk_ct_…. Belongs to one of the developer's own users, and reads only that user's data.
Headers
The customer this call is acting inside — the same arrangement as X-Organization-Id, one plane down. Switching customers is navigation, not a mutation: nothing is stored, you send a different header, and the membership JOIN behind it decides what you may do there. An id you are not a member of matches no row and answers 404. Absent, the contact's oldest membership answers.
Body
Response
Invited.
A seat offered to an address. It is a credential, so only its id and address are ever readable — the token exists once, in the email.
The role's key. owner and member always exist; a tenant may define their own beside them.
"owner"
The role's display name, for a screen that should not show a key.
"Owner"