Okouro docs

Every request carries a role, decided when you log in. The role controls two things: which endpoints you may call, and which sensitive fields you are allowed to see. Okouro also has a team-leader capability that is a relationship, not a role.

The four roles

A user has exactly one role, returned as the role field on the user object:

Rolerole valueTypical scope
AdminadminFull control of the account: users, settings, validation, settlement.
OperationsoperationsDay-to-day operations: clients, invoicing, expense settlement.
ExecutiveexecutiveRead-oriented oversight: KPIs, margins, forecasts.
ConsultantconsultantSelf-service: own timesheet, time off, assignments, expenses.

When you sign up you become the account’s admin. A user named as somebody’s manager gains team-leader powers on top of their role (below).

What each role can do

Rather than memorise a matrix, use the status codes as your guide:

  • 403 Forbidden means your role is not allowed to call that endpoint at all, or is not allowed for that specific record.
  • 404 Not Found means the record exists outside your scope, or not at all; Okouro does not distinguish the two.

Some concrete rules that recur across the guides:

  • Validate or reject a timesheet: admin only.
  • Approve or reject time off: admin only.
  • Approve or reject an expense: admin or the requester’s team leader.
  • Pay an expense: admin or operations.
  • Update a mission budget: admin only.
  • Read staffing KPIs: admin or executive.
  • Read mission-budget KPIs: admin, operations, or executive.

Team leaders

A user who is named as the manager_id of one or more consultants becomes a team leader for those consultants. This is orthogonal to role: an operations user can be a team leader, and so can another consultant.

Team leaders gain scoped powers over the consultants they manage: they can validate subordinates’ timesheets, approve or reject subordinates’ time off and expenses, and act on their behalf. They never gain these powers over their own records, and their reach is limited to the consultants they manage plus their own.

You can tell whether the current user manages anyone from GET /auth/me: is_manager is true when the user manages at least one consultant.

Field-level visibility

Two money fields are sensitive and are hidden from the consultant role:

FieldAppears onVisible toHidden from
daily_costconsultant profiles, mission budgetsadmin, operations, executiveconsultant
billing_rateassignments, timesheet linesadmin, operations, executiveconsultant

A hidden field is returned as null, never removed from the response. So the JSON shape is stable across roles; only the value changes. For example, the same assignment looks different depending on who asks:

{ "id": "...", "consultant_id": "...", "billing_rate": "900.00", "status": "active" }
{ "id": "...", "consultant_id": "...", "billing_rate": null, "status": "active" }

The second response is what a consultant receives. Margin figures on mission budgets and quote profitability follow the same rule (masked from consultant).

Account isolation

Every record belongs to an account (your tenant). A token only ever reaches records in its own account; there is no way to address another account’s data, and cross-account reads return 404. You never pass an account id on requests; it is derived from your token.

Designing around roles

  • Treat 403 as “wrong role”, not “transient error”; do not retry.
  • Expect sensitive numeric fields to be null for consultant-role tokens, and branch your UI or logic on that rather than assuming a number is always present.
  • If you need to act on a subordinate’s record, the acting user must be that record’s manager (or an admin); a matching role alone is not enough.

See Track time, Request time off, and Manage expenses for the role split in each flow.