Nazeel API

The contract is openapi.yaml. Base path /api/v1.

Authentication

Things a client has to get right

CSRF. A cookie-authenticated request that changes anything must carry an Origin or Referer the API recognises. Bearer-token clients are unaffected.

Side-effecting GETs refuse the cookie entirely (terminal, audit export, logs, recordings). A browser will issue those cross-origin, so a cookie there would be exploitable from any page. Use a bearer token, or mint a single-use 60-second ticket with POST /auth/ticket and pass it as a query parameter.

Sessions are revocable. Every token carries a jti that is checked against the sessions table on each request, so revocation takes effect immediately rather than at expiry. GET /me/sessions, DELETE /me/sessions/{jti}, POST /me/sessions/revoke-all (which spares the calling session).

Empty lists are [], never null. If you find one that is not, it is a bug.

Errors

{"code": "nazeel.env.quota.perUser", "params": {"owner": "amr", "current": "3", "max": "3"}}

Admission failures carry causes[], one per rule, each with field, code, params. Render texts from api/pkg/i18n (Render(lang, code, params)), English and Arabic.

Licence

PUT /licence {"key": "NZL2...."}, and NZL1. keys are still accepted. States: valid, grace, expired, invalid, missing. Issue keys with nazeel-licence issue (vendor only).

Expired or missing refuses creating, extending and syncing environments, and nothing else: waking, previews, sign-in and the audit log all keep working. A licensed feature that is absent answers 402 with the feature name in params, which a client should render as "not in your plan" rather than as an error. GET /licence/usage-report returns a signed report of monthly active seats.

Audit

GET /audit (admin), GET /audit/verify, GET /audit/export (signed evidence package), PUT /settings/siem for syslog or HTTP forwarding. Entries are hash-chained and can never be altered or deleted.