Invites
Invite users into your ThunderPhone organization by email, choose the role each invite carries, revoke pending invites, and accept or decline the ones you receive.
Invites are the mechanism for bringing new members into an organization. The admin-side endpoints create/list/revoke invites scoped to your org. The token-side endpoints let an invitee look up, accept, or decline an invite by its secret token — those endpoints don't require you to be a member of the target org (the token itself identifies it).
Endpoints
| Method | Path | Required role | Description |
|---|---|---|---|
GET | /v1/invites | admin+ | List pending invites |
POST | /v1/invites | admin+ | Send an invite |
DELETE | /v1/invites/{invite_id} | admin+ | Revoke a pending invite |
GET | /v1/invites/{token} | authenticated | Look up an invite by token |
POST | /v1/invites/{token}/accept | authenticated | Accept an invite |
POST | /v1/invites/{token}/decline | authenticated | Decline an invite |
POST | /v1/invites/{token}/request-access | authenticated | Ask the inviter to re-issue the invite to your email |
Invite object (admin list/create)
The list / create endpoints use a trimmed view that omits the raw token. For the by-token lookup see the token lookup response.
{
"id": 18,
"email": "new-teammate@example.com",
"role": "member",
"status": "pending",
"invited_by_email": "owner@example.com",
"created_at": "2026-04-20T18:24:10.113Z",
"expires_at": "2026-04-27T18:24:10.113Z"
}| Field | Type | Description |
|---|---|---|
id | integer | Internal invite id (used by the revoke endpoint) |
email | string | Invitee email |
role | string | Role granted on acceptance: admin or member |
status | string | pending, accepted, or declined |
invited_by_email | string | Email of the admin/owner who sent the invite |
created_at | timestamp | ISO 8601 UTC |
expires_at | timestamp | 7 days after created_at by default |
List pending invites
curl https://api.thunderphone.com/v1/invites \
-H "Authorization: Bearer sk_live_YOUR_API_KEY"invites = requests.get(
"https://api.thunderphone.com/v1/invites",
headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
).json()Returns a JSON array of Invite objects
in pending state, sorted by created_at descending.
Send an invite
curl -X POST https://api.thunderphone.com/v1/invites \
-H "Authorization: Bearer sk_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "new-teammate@example.com",
"role": "member"
}'invite = requests.post(
"https://api.thunderphone.com/v1/invites",
headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
json={"email": "new-teammate@example.com", "role": "member"},
).json()| Field | Type | Required | Description |
|---|---|---|---|
email | string | yes | Invitee email |
role | string | yes | admin or member |
Returns 201 Created with the Invite object.
The invitee receives an email containing a link of the form
https://app.thunderphone.com/invite/{token}.
| Status | Condition |
|---|---|
400 | Email already has a pending invite for this org, or is already a member |
403 | Caller is not an admin/owner |
Revoke an invite
curl -X DELETE https://api.thunderphone.com/v1/invites/18 \
-H "Authorization: Bearer sk_live_YOUR_API_KEY"requests.delete(
f"https://api.thunderphone.com/v1/invites/{invite_id}",
headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
)Returns 204 No Content. Only invites with status pending can be
revoked.
Look up by token
Public lookup used by the dashboard's invite-landing page. This endpoint is unauthenticated — the token itself is the credential. Used to render the "You've been invited to join Acme Ops" UI.
curl https://api.thunderphone.com/v1/invites/a1b2c3d4-...invite = requests.get(
f"https://api.thunderphone.com/v1/invites/{token}",
).json()Response:
{
"id": 18,
"org_name": "Acme Ops",
"email": "new-teammate@example.com",
"role": "member",
"status": "pending",
"invited_by_email": "owner@example.com",
"created_at": "2026-04-20T18:24:10.113Z",
"expires_at": "2026-04-27T18:24:10.113Z"
}| Status | Condition |
|---|---|
200 | Pending, not expired — response includes org_name for UI display |
404 | Token not found |
410 | Token exists but is already accepted / declined, or has expired |
Accept an invite
The caller must be authenticated; their user is added to the target org with the role specified on the invite.
curl -X POST https://api.thunderphone.com/v1/invites/a1b2c3d4-.../accept \
-H "Authorization: Bearer sk_live_YOUR_API_KEY"result = requests.post(
f"https://api.thunderphone.com/v1/invites/{token}/accept",
headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
).json()Returns 200 OK:
{
"detail": "Invite accepted.",
"org_id": 42
}| Status | Condition |
|---|---|
200 | Invite accepted; caller is now a member |
403 | Caller is signed in as a user whose email does not match the invite |
404 | Token not found |
410 | Token exists but is already accepted / declined, or has expired |
Decline an invite
curl -X POST https://api.thunderphone.com/v1/invites/a1b2c3d4-.../decline \
-H "Authorization: Bearer sk_live_YOUR_API_KEY"requests.post(
f"https://api.thunderphone.com/v1/invites/{token}/decline",
headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
)Returns 204 No Content.
Request access to an invite
For a signed-in user who received an invite link addressed to a different email (e.g. a forwarded invite): emails the original inviter asking them to grant access to the caller's account instead. No membership is created — the inviter decides.
curl -X POST https://api.thunderphone.com/v1/invites/a1b2c3d4-.../request-access \
-H "Authorization: Bearer sk_live_YOUR_API_KEY"No request body. Returns 204 No Content when the request email was
sent.
| Status | Condition |
|---|---|
204 | Access request sent to the inviter |
400 | The invite is already addressed to your email (just accept it), or it has no sender to approve access |
404 | Token not found |
410 | Invite already accepted / declined, or expired |
429 | Rate limited — max 3 access requests per hour per user |
503 | The request email could not be sent |