Team
Invite somebody
Send an invitation, take a seat, and what the owner-only rule means for API keys.
curl --request POST \
--url 'https://truestat.io/api/v1/team/invites' \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"role": "admin",
"email": "<string>"
}'{
"data": {
"role": "member",
"email": "dana@example.com",
"pending": true,
"email_sent": true
},
"meta": {}
}Sends an invitation e-mail and takes a seat immediately.
Owner only — and that is not the scope
This is the one place in the API where carrying the right scope is not the whole answer.
team:write says the key was issued for team management. It does not say the
person behind the key is allowed to manage the team. An organisation admin
can create an API key, and admin is not owner — so a key minted by an admin
gets 403 owner_only here, exactly as that admin would find no team controls
in the dashboard.
The role is read from whoever created the key, and it is read fresh on every call. A key whose creator is later demoted stops being able to manage the team from that moment — the same way the screen disappears for them.
Everywhere else in the API the scope is sufficient, because creating a key at all requires an admin, and admin already outranks what those endpoints need. Team management is the exception because the bar above it is higher.
The seat is taken before they accept
The membership row is written first, then the mail goes out. So the seat counts against your plan from this call, not from the moment somebody clicks.
If the plan has no seats left you get 402 with a sentence naming the tier
that has more and what it costs. If the account has no active plan at all you
get 402 subscription_required — that check happens before anything is
created, so a failed invitation leaves nothing behind.
email_sent: false is not a failure
{
"data": {
"email": "dana@example.com",
"role": "member",
"pending": true,
"email_sent": false
}
}The membership exists and holds its seat. Only delivery did not happen.
Do not retry this call — it would answer 409 already_member, which is
correct and unhelpful. Re-send the invitation from the team screen instead.
Which roles can be invited
admin and member. Nothing else is accepted.
owner is not a value you can hand out through a request body; transferring
an account is deliberate and happens in the dashboard. viewer is left out
because nothing in the permission rules distinguishes it from member today —
offering it would sell a restriction that is not enforced.
Already on the team
A 409 covers both cases, with a message that says which:
the address has already accepted — they are a member
the address has an invitation outstanding — it was already sent
Authorizations
AuthorizationstringheaderrequiredAn API key from Settings → API keys. Scopes available: analytics:read, sites:read, sites:write, settings:read, settings:write, goals:read, goals:write, funnels:read, funnels:write, notes:read, notes:write, alerts:read, alerts:write, team:read, team:write, revenue:read, revenue:write.
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Request bodyapplication/json
roleenum<string>bodyrequiredadminmemberemailstring (email)bodyrequiredResponse
The answer.
dataobjectmetaobjecterrorobjecterrorobjecterrorobjecterrorobject