Gridex Staff API
Documentation 2026-10-12.1. Staff response schema 2026-10-09.1. Manage staff accounts and customer service from your own backend.
You do not need to match the latest documentation revision exactly to use a supported API version. Documentation updates do not change the business response schema or require an integration upgrade. Earlier supported Staff response profiles remain available. Independent staff onboarding has its own schema, 2026-10-05.2.
Integration readiness
The documented Staff API is available for integration development. Production use requires the deployed API and OPS database prerequisites plus the organization's active credential, explicit Staff scopes, identity provider, membership and any independent-login binding. Verify an authenticated read and write with the intended role and company, correct audit attribution and a retry of the same logical operation before go-live.
Configure staff login
Create an API credential with the specific staff scopes you need. In Settings → Customer login, add an OIDC provider or your backend public signing key with purpose Staff. Copy its issuer and audience exactly. Existing website and customer scopes do not grant staff access.
Your backend authenticates the person and maps their account to a Gridex user UUID. Keep the API credential and signing private key on your server. Derive the acting user from the authenticated account, never from a browser supplied UUID.
Sign each request
Send Authorization: Bearer <GRIDEX_API_KEY> and x-gridex-staff-assertion: <SIGNED_JWT> on every call. Supported algorithms are RS256, PS256 and ES256. The JWT requires the configured iss and aud, sub equal to the staff Gridex user UUID, integer iat and exp with a lifetime of at most 900 seconds, and a unique jti. Optional nbf controls the earliest valid time.
Clients registered for an independent staff identity additionally send token_use "staff_access", company_id, local_auth_issuer, local_auth_subject, staff_binding_id and staff_binding_version from onboarding; sub stays the central Gridex user UUID. A removed or revoked registration is rejected and never falls back to the central flow. See the independent staff onboarding guide in docs/staff-api/independent-onboarding.md.
Each assertion is accepted once. Generate a new assertion and jti for every attempt, including reads and retries. Gridex checks the current central account, active organization membership, current identity binding where required, and the person's role permissions and overrides for every request.
Your backend verifies the local Auth session before signing. Gridex also calls the registered local Auth getUser during identity resolution and invitation acceptance. A normal Staff request validates the signed proof and current central authority; it does not call local Auth getUser again for an already signed proof.
import { createPrivateKey, randomUUID, sign } from 'node:crypto'
function staffAssertion(authenticatedStaffGridexUserId) {
const iat = Math.floor(Date.now() / 1000)
const encode = value => Buffer.from(JSON.stringify(value)).toString('base64url')
const header = encode({ alg: 'RS256', typ: 'JWT', kid: process.env.GRIDEX_STAFF_KEY_ID })
const payload = encode({
iss: process.env.GRIDEX_STAFF_ISSUER,
aud: process.env.GRIDEX_STAFF_AUDIENCE,
sub: authenticatedStaffGridexUserId,
iat, exp: iat + 300, jti: randomUUID(),
})
const input = header + '.' + payload
const signature = sign('RSA-SHA256', Buffer.from(input),
createPrivateKey(process.env.GRIDEX_STAFF_PRIVATE_KEY_PEM))
return input + '.' + signature.toString('base64url')
}Scopes and permissions
The credential scope and the person's permission are both required.
| Scope | Operation | Permission |
|---|---|---|
| staff_users.read | List staff and roles | users.read |
| staff_users.write | Invite, change roles, disable and reactivate | users.write |
| staff_customers.read | Search and retrieve customers | customers.read |
| staff_customers.write | Change contact details | masterdata.write |
| staff_customers.write | Request identity change | customers.write |
| staff_cases.read | Read cases, events and attachments | cases.read |
| staff_cases.write | Create, reply, note, phone, status, assign and upload | cases.write |
Staff cannot grant a role exceeding their own permissions or disable themselves. The final active administrator cannot be disabled or demoted. Assignees must be active staff in the same organization.
Writes and retries
Every POST and PATCH requires Idempotency-Key. Reuse that key and unchanged body for a retry, with a fresh assertion and jti. Use a new key for a new logical operation. Contact updates require expectedUpdatedAt from the latest customer updated_at and at least one editable field. A version conflict requires reloading and reconciling state. Identity changes preserve customer approval and contract acceptance.
Customer and case paths use opaque references; staff account operations use Gridex user UUIDs. Identity numbers are masked in customer responses. Internal notes and phone logs require staff access. Writes are audited with the acting staff identity, API credential and staff_api channel.
Upload a raw PDF, PNG or JPEG body up to 4 MiB with x-file-name and optional x-attachment-visibility: internal or customer (default internal). Only released attachments can be downloaded; the stored hash is verified on download.
Replay, request IDs and storage project
Every Staff write response, including staff-user invite, role change, disable and enable, carries Idempotency-Replayed: true when a stored result is returned and false for a new execution. Current authentication and permission are checked before any replay.
Gridex issues one server request ID per call and returns the same value in request_id, the X-Request-ID header and the request log, on success and on error. An inbound X-Request-ID is kept only as a separate client correlation value.
The optional x-gridex-expected-project-ref header pins the storage project; a mismatch returns 412 storage_project_mismatch before any authentication or write. Responses carry X-Gridex-Project-Ref.
Query parameters: existing parsing is kept by default. Send x-gridex-query-parsing: strict to require each parameter at most once and page, page_size and limit as plain decimal digits; violations return 422 invalid_field.
Endpoints
| Method | Path | Scope | Operation |
|---|---|---|---|
| GET | /api/v1/staff/users | staff_users.read | List staff accounts with their membership status. |
| POST | /api/v1/staff/users | staff_users.write | Invite staff to the organization within the acting staff role ceiling. Idempotency-Key is required. |
| PATCH | /api/v1/staff/users/[id] | staff_users.write | Change a staff role while preserving the final active administrator. Idempotency-Key is required. |
| POST | /api/v1/staff/users/[id]/disable | staff_users.write | Disable staff while preventing self disable and loss of the final administrator. Idempotency-Key is required. |
| POST | /api/v1/staff/users/[id]/enable | staff_users.write | Reactivate a disabled staff membership. Idempotency-Key is required. |
| GET | /api/v1/staff/roles | staff_users.read | List staff roles and whether the acting staff can assign each role. |
| GET | /api/v1/staff/customers | staff_customers.read | Search and page customers belonging to the authenticated organization. |
| GET | /api/v1/staff/customers/[ref] | staff_customers.read | Retrieve a customer with masked identity numbers and explicit public fields. |
| PATCH | /api/v1/staff/customers/[ref]/contact | staff_customers.write | Update customer contact fields using an expected version. Idempotency-Key is required. |
| POST | /api/v1/staff/customers/[ref]/identity-change | staff_customers.write | Request a customer identity change with customer approval when required. Idempotency-Key is required. |
| GET | /api/v1/staff/cases | staff_cases.read | List customer cases available to staff in the authenticated organization. |
| POST | /api/v1/staff/cases | staff_cases.write | Create a customer support case as the acting staff. Idempotency-Key is required. |
| GET | /api/v1/staff/cases/[reference] | staff_cases.read | Retrieve a customer case including staff visible events and attachments. |
| POST | /api/v1/staff/cases/[reference]/messages | staff_cases.write | Reply to a customer through the existing support conversation. Idempotency-Key is required. |
| POST | /api/v1/staff/cases/[reference]/notes | staff_cases.write | Add an internal staff note to a customer case. Idempotency-Key is required. |
| POST | /api/v1/staff/cases/[reference]/phone-interactions | staff_cases.write | Record a phone interaction and its customer verification evidence. Idempotency-Key is required. |
| PATCH | /api/v1/staff/cases/[reference]/status | staff_cases.write | Change the status of a customer case. Idempotency-Key is required. |
| PATCH | /api/v1/staff/cases/[reference]/assignee | staff_cases.write | Assign a customer case to active staff in the same organization. Idempotency-Key is required. |
| GET | /api/v1/staff/cases/[reference]/events | staff_cases.read | List staff visible case events with a case bound continuation cursor. |
| GET | /api/v1/staff/cases/[reference]/attachments | staff_cases.read | List staff visible attachments of a customer case. |
| POST | /api/v1/staff/cases/[reference]/attachments | staff_cases.write | Upload a staff attachment for content inspection before release. Idempotency-Key is required. |
| GET | /api/v1/staff/cases/[reference]/attachments/[attachmentReference]/file | staff_cases.read | Download a released staff visible attachment with its hash verified. |
Read complete case history
Case detail includes events_page and attachments_page. Follow next_cursor through GET /api/v1/staff/cases/{reference}/events or GET /api/v1/staff/cases/{reference}/attachments until has_more is false. Each list accepts limit from 1 to 100 (default 50) and cursor. Sign a fresh assertion for every page. Cursors are bound to the organization, customer and case.
Customer detail marks its initial contacts, addresses and sites with contacts_page, addresses_page and sites_page: limit is 100, returned is the included count, and has_more identifies additional records beyond the initial collection.
Errors
JSON errors contain error.code, error.message, error.retryable, error.field and error.blockers, plus request_id, correlation_id and contract_schema_version. Success and error responses carry X-Request-ID and X-Gridex-Contract-Version. X-Gridex-Documentation-Version identifies the associated documentation revision. When fetching OpenAPI itself, X-Gridex-Contract-Version identifies that document's revision.
| HTTP | Reason or code | Action |
|---|---|---|
| 400 / 422 | Invalid request or Idempotency-Key | Correct fields or headers. |
| 401 | staff_assertion_missing, staff_assertion_signature_invalid, staff_assertion_issuer_mismatch, staff_assertion_audience_mismatch, staff_assertion_expired, staff_assertion_replayed | Fix configuration or sign a fresh assertion. |
| 403 | api_scope_missing, staff_provider_missing, staff_provider_invalid, staff_membership_inactive, staff_permission_denied, staff_role_ceiling_exceeded | Check configured scopes, provider, active membership and permissions. |
| 404 | Resource unavailable in this organization | Use a current reference from the same organization. |
| 409 | version_conflict, staff_self_disable_forbidden, staff_last_admin_required, staff_invalid_user_state, staff_self_role_change_forbidden, idempotency conflict | Reload and reconcile the operation without bypassing safeguards. |
| 410 / 423 | organization_closed, organization_inactive, organization_paused | Resolve the organization lifecycle restriction before retrying. |
| 413 / 415 | payload_too_large or attachment size/type rejected | Reduce the JSON body or use PDF, PNG or JPEG within 4 MiB. |
| 429 | Rate limit exceeded | Observe Retry-After and sign a fresh assertion for the retry. |
| 412 | storage_project_mismatch | Use the deployment serving the expected project; nothing was executed. |
| 500 / 503 | Processing or service unavailable | Keep the request ID; retry only when safe and retryable. |