PurrOSDocs

Authentication & scopes

The three ways to call the API, how people's permissions and reach are checked, and every integration scope.

Authentication

There are three ways to call the API:

CallerHowAccess
Integration keyAuthorization: Bearer pk_live_… from registering an integrationThe scopes in its manifest, company-wide
Personal keyAuthorization: Bearer pk_live_… created at POST /auth/api-keys by a user whose role has api_keys.personalThat user's own role permissions and reach, never more
SessionThe purros_session cookie set by POST /auth/sign-in (the web app)The signed-in person's role permissions and reach
GET /api/v1/employees HTTP/1.1
Host: erp.example.com
Authorization: Bearer pk_live_3c9f…

Keys are shown once, can have an expiry, and can be revoked. Use GET /api/v1/me to check what a key is, or GET /api/v1/auth/session to see a person's role, permissions and assignments.

Keep keys secret

Only a hash of each key is stored, so a lost key can't be shown again: revoke it and create a new one. Put keys in environment variables, never in code. See API keys.

People: permissions and reach

Requests from people (sessions and personal keys) are checked against their role instead of scopes. The endpoint reference lists the permission each endpoint needs. When the role holds the permission with a reach narrower than Everyone (own team, assigned locations or assigned departments):

  • list endpoints must be narrowed with locationId or employeeId inside that reach
  • single records, and actions on them, are checked against the record's location or employee
  • anything else returns 403 out_of_reach

Data feeds (batch ingestion, tenders, settlements, sensor readings…) are for integration keys only. Sessions also:

  • must send state-changing requests from the PurrOS origin (the Origin header is checked), which protects against cross-site request forgery
  • may need a second step (POST /auth/sign-in/mfa) before anything else works; see Authentication

Scopes

Integration keys are limited to the scopes they declared:

ScopeCovers
organization:readOrg units, locations, departments, roles, users (read-only)
organization:writeCreate, update and archive org units, locations and departments
attachments:read, attachments:writeUpload, download and delete files (Attachments)
people:read, people:writeEmployees, documents, skills, onboarding
payroll:read, payroll:writePay rates, pay period exports, payslips
time:read, time:writePunches, timesheets, time off
scheduling:read, scheduling:writeDemand drivers, forecasts, schedules, shifts, availability
cash:read, cash:writeTenders, settlements, bank transactions, counts, deposits
inventory:read, inventory:writeItems, stock, movements, counts, waste, transfers, usage recipes
purchasing:read, purchasing:writeSuppliers, catalogs, suggested orders, purchase orders, receipts, supplier invoices
sales:read, sales:writeSales transactions and summaries, customers, sales orders, invoices
operations:read, operations:writeForms, submissions, corrective actions, audits, sensor readings
equipment:read, equipment:writeAssets, meter readings, work orders
communication:read, communication:writeAnnouncements, calendar events, recognitions
reports:read, reports:writeReports, KPIs, recommendations. write is for pushing custom display metrics.
people:sensitiveSensitive employee fields (national ID, bank details). Needs Owner approval at registration.
notifications:deliverReceive notification.requested events to deliver SMS or chat messages

Sensitive employee fields are never returned to integration keys without the people:sensitive scope.

Scopes also decide which webhook events an integration may subscribe to. Managing integrations and webhook endpoints (/integrations, /webhook-endpoints) is for people only (integrations.manage, webhooks.manage); an integration uses /integrations/self instead.

Ask for the minimum

Declare only the scopes your integration needs. A scope of a switched-off feature can't be requested, and existing keys lose it while the feature is off.

  • GET/auth/api-keys

    Your personal API keys

    Keynot allowed
    Peopleself (session)
  • POST/auth/api-keys

    Create a personal API key

    Keynot allowed
    Peopleapi_keys.personal (session)
  • DELETE/auth/api-keys/{id}

    Revoke one of your personal API keys

    Keynot allowed
    Peopleself (session)
  • POST/auth/invitations:accept

    Accept an invitation and set a password

    Keypublic
    Peoplepublic
  • POST/auth/magic-link

    Email a single-use sign-in link

    Keypublic
    Peoplepublic
  • POST/auth/magic-link:redeem

    Sign in with a magic link

    Keypublic
    Peoplepublic
  • POST/auth/mfa/recovery-codes:regenerate

    Replace your recovery codes

    Keynot allowed
    Peopleself (session)
  • POST/auth/mfa/totp:confirm

    Turn on two-factor authentication with a first code

    Keynot allowed
    Peopleself (session)
  • POST/auth/mfa/totp:disable

    Turn off two-factor authentication

    Keynot allowed
    Peopleself (session)
  • POST/auth/mfa/totp:setup

    Start setting up an authenticator app

    Keynot allowed
    Peopleself (session)
  • POST/auth/password

    Change your password

    Keynot allowed
    Peopleself (session)
  • POST/auth/password-reset

    Email a password reset link

    Keypublic
    Peoplepublic
  • POST/auth/password-reset:complete

    Choose a new password with a reset link

    Keypublic
    Peoplepublic
  • GET/auth/session

    The signed-in person: role, permissions, assignments and enabled features

    Keynot allowed
    Peopleself
  • GET/auth/sessions

    Your active sessions and devices

    Keynot allowed
    Peopleself (session)
  • DELETE/auth/sessions/{id}

    Sign out one of your sessions

    Keynot allowed
    Peopleself (session)
  • POST/auth/sign-in

    Sign in with email and password

    Keypublic
    Peoplepublic
  • POST/auth/sign-in/mfa

    Finish signing in with an authenticator or recovery code

    Keynot allowed
    Peopleself (session)
  • POST/auth/sign-out

    Sign out this session

    Keynot allowed
    Peopleself (session)

On this page