Permissions
Each API key has a set of permissions (also called scopes). A permission decides two things: which endpoints the key can call, and which fields it can see.
The permissions
| Permission | Name in TRUED | What it opens |
|---|---|---|
invoices:read |
Invoices and charges | /v1/invoices, /v1/charges, with client billing fields |
time_entries:read |
Time entries | /v1/time-entries, with client billing fields |
clients:read |
Clients and contacts | /v1/clients |
credits:read |
Client credit | /v1/clients/{id}/credit: balance, packages, history |
contractors:read |
Contractors | /v1/contractors |
payments:read |
Confirmed payments | /v1/payments (client payments) |
events:read |
Events | /v1/events |
pay:read |
Contractor pay rates and payouts | Adds contractor pay to the endpoints above |
margin:read |
Margins | Adds margin amount and percent to invoices |
/v1/me and /v1/openapi.json need no permission beyond a valid key.
Contractor pay and margins
pay:read and margin:read do not open an endpoint on their own. They add fields to endpoints
the key can already call. A key with margin:read must also have pay:read: a margin is the
amount billed minus what the contractor is paid, so it shows contractor pay.
- With
pay:read: pay rates and payout amounts on time entries and charges, contractor pay status and payout amount on invoices, contractor payouts on/v1/payments, and thepayout.paidevent. - With
margin:read:margin_amount,margin_percentandmargin_noteon invoices.
A dashboard that only shows client billing should not have either. Give them only to tools that genuinely need pay or profit figures, such as a payroll system.
A field your key may not see is left out
TRUED does not send null or a blank value for a field your key may not see. The field is left
out of the response completely. For example, an invoice read with invoices:read alone:
{
"id": "inv_7Qa2",
"number": "INV-2026-09-0047",
"net_due": "950.00",
"currency": "USD"
}
The same invoice read by a key that also has pay:read and margin:read also carries
payout_amount, contractor_pay_status, margin_amount and margin_percent.
Write your code so a missing field means "not available to this key", not zero.
Missing a permission
Calling an endpoint the key has no permission for returns 403, and the message names the
permission needed:
curl https://api.trued.io/v1/contractors -H "Authorization: Bearer $TRUED_API_KEY"
{
"type": "https://docs.trued.io/errors/403",
"title": "Not allowed",
"status": 403,
"detail": "This key does not have the \"contractors:read\" permission. Create or rotate a key with that permission in TRUED under Settings, Integrations, API Keys.",
"request_id": "req_9k2LmQ"
}
To change a key's permissions, create a new key with the right permissions and revoke the old one. Permissions are fixed for the life of a key (a rotated key keeps the same permissions), so a key can never quietly gain access.