Firm
27 operations. All areas
- POST /v1/firms
- GET /v1/firm
- POST /v1/firm/members
- GET /v1/firm/members
- POST /v1/firm/members/{id}/remove
- POST /v1/firm/keys
- GET /v1/firm/keys
- POST /v1/firm/keys/{id}/rotate
- POST /v1/firm/keys/{id}/revoke
- POST /v1/firm/agents
- GET /v1/firm/agents
- POST /v1/firm/agents/{id}/assign
- POST /v1/firm/agents/{id}/unassign
- POST /v1/firm/agents/{id}/revoke
- GET /v1/firm/clients
- POST /v1/firm/clients
- POST /v1/firm/clients/{id}/owner-invite
- POST /v1/firm/clients/lock-period
- POST /v1/firm/kill-switch
- POST /v1/firm/sessions
- GET /v1/firm/sessions
- POST /v1/firm/sessions/{id}/revoke
- GET /v1/firm/audit/verify
- GET /v1/firm/audit/events
- GET /v1/firm/proposals
- POST /v1/firm/proposals/decide
- GET /v1/firm/close
POST/v1/firms
Create an accounting firm with its first admin member and that member's key (returned once). Operator bootstrap token required.
- Operation
createFirm - Scope: operator token
- Write: needs Idempotency-Key (or dry_run)
- Request body
namestring, requiredadmin_namestring, required
- Responses
201Created (object)- Errors
400,401,403,409,422,429,500(Error:error.type,message)
GET/v1/firm
The caller's firm and who the caller is (firm key or firm session)
- Operation
getFirm - Scope: read
- Read
- Responses
200Firm (FirmMe)- Errors
400,401,403,429,500(Error:error.type,message)
POST/v1/firm/members
Add a firm member (firm admin). They appear in every client that granted the firm access. No seat fees.
- Operation
createFirmMember - Scope: admin
- Write: needs Idempotency-Key (or dry_run)
- Request body
namestring, requiredrole"admin" | "cpa" | "bookkeeper", required admin and cpa: all scopes in clients (admin also manages the firm); bookkeeper: read and propose.
- Responses
201Added (object)- Errors
400,401,403,409,422,429,500(Error:error.type,message)
GET/v1/firm/members
Firm members
- Operation
listFirmMembers - Scope: read
- Read
- Parameters
include_removedquery, boolean
- Responses
200Members (object)- Errors
400,401,403,429,500(Error:error.type,message)
POST/v1/firm/members/{id}/remove
Remove a member (firm admin): their keys and sessions end at once. Final.
- Operation
removeFirmMember - Scope: admin
- Write: needs Idempotency-Key (or dry_run)
- Parameters
idpath, string, required
- Request body
reasonstring, required
- Responses
200Removed (object)- Errors
400,401,403,404,409,422,429,500(Error:error.type,message)
POST/v1/firm/keys
Mint a firm key for a member or a firm agent (firm admin). The secret is returned once; only its hash is stored. Use it with X-Evenbead-Company on any company operation.
- Operation
createFirmKey - Scope: admin
- Write: needs Idempotency-Key (or dry_run)
- Request body
principal_type"member" | "agent", requiredmember_idstringfirm_agent_idstringscopesarray of "read" | "propose" | "approve" | "admin", requiredexpires_in_daysinteger Lifetime in days. Default: 365 for a member's key, 30 for a firm agent's (at most 90).rate_limit_rpminteger | null This key's own rate budget in requests per minute (null: the firm default).
- Responses
201Created (object)- Errors
400,401,403,409,422,429,500(Error:error.type,message)
GET/v1/firm/keys
Firm keys (prefixes only, never secrets)
- Operation
listFirmKeys - Scope: read
- Read
- Responses
200Keys (object)- Errors
400,401,403,429,500(Error:error.type,message)
POST/v1/firm/keys/{id}/rotate
Rotate a live firm key (firm admin, or the key's own holder): a successor with the same principal and scopes and a fresh lifetime; the old key keeps working for the overlap window (default 24 h, at most 7 days, 0 = at once). The new secret is returned once.
- Operation
rotateFirmKey - Scope: read
- Write: needs Idempotency-Key (or dry_run)
- Parameters
idpath, string, required
- Request body
overlap_secondsintegerexpires_in_daysinteger Lifetime in days. Default: 365 for a member's key, 30 for a firm agent's (at most 90).rate_limit_rpminteger | null This key's own rate budget in requests per minute (null: the firm default).reasonstring
- Responses
201Rotated (object)- Errors
400,401,403,404,409,422,429,500(Error:error.type,message)
POST/v1/firm/keys/{id}/revoke
Revoke a firm key (and its sessions), effective on the next request
- Operation
revokeFirmKey - Scope: admin
- Write: needs Idempotency-Key (or dry_run)
- Parameters
idpath, string, required
- Request body
reasonstring, required
- Responses
200Revoked (object)- Errors
400,401,403,404,409,422,429,500(Error:error.type,message)
POST/v1/firm/agents
Register a firm agent (firm admin). It acts only in clients it is assigned to, with each client's own threshold.
- Operation
createFirmAgent - Scope: admin
- Write: needs Idempotency-Key (or dry_run)
- Request body
namestring, requiredscopesarray of "read" | "propose" | "approve" | "admin", required
- Responses
201Created (object)- Errors
400,401,403,409,422,429,500(Error:error.type,message)
GET/v1/firm/agents
Firm agents with their client assignments and per-client thresholds
- Operation
listFirmAgents - Scope: read
- Read
- Responses
200Agents (object)- Errors
400,401,403,429,500(Error:error.type,message)
POST/v1/firm/agents/{id}/assign
Assign a firm agent to a client that granted the firm access, with that client's posting threshold (upsert; a threshold change is audited in the client's log)
- Operation
assignFirmAgent - Scope: admin
- Write: needs Idempotency-Key (or dry_run)
- Parameters
idpath, string, required
- Request body
company_idstring, requiredposting_threshold_centsinteger, required Integer cents.scopesarray of "read" | "propose" | "approve" | "admin"
- Responses
200Assigned (object)- Errors
400,401,403,404,409,422,429,500(Error:error.type,message)
POST/v1/firm/agents/{id}/unassign
Stop a firm agent from acting in one client
- Operation
unassignFirmAgent - Scope: admin
- Write: needs Idempotency-Key (or dry_run)
- Parameters
idpath, string, required
- Request body
company_idstring, requiredreasonstring, required
- Responses
200Unassigned (object)- Errors
400,401,403,404,409,422,429,500(Error:error.type,message)
POST/v1/firm/agents/{id}/revoke
Revoke a firm agent everywhere (and its keys). Final.
- Operation
revokeFirmAgent - Scope: admin
- Write: needs Idempotency-Key (or dry_run)
- Parameters
idpath, string, required
- Request body
reasonstring, required
- Responses
200Revoked (object)- Errors
400,401,403,404,409,422,429,500(Error:error.type,message)
GET/v1/firm/clients
The console: every client that granted the firm access, with status at a glance (bank, proposal queue, period locks, overdue AR, last activity, migration)
- Operation
listFirmClients - Scope: read
- Read
- Parameters
as_ofquery, string
- Responses
200Clients (object)- Errors
400,401,403,429,500(Error:error.type,message)
POST/v1/firm/clients
Create a new client company (firm admin): owner user, firm-billed grant to this firm with all scopes, and a single-use owner invitation (returned once, 14 days) for the firm to hand to the owner. The firm never receives a company key; the owner claims theirs (ADR-0023).
- Operation
createFirmClient - Scope: admin
- Write: needs Idempotency-Key (or dry_run)
- Request body
namestring, requiredowner_namestring, requiredstarter_chart"general" | "services" | "retail" | "empty" Starter chart of accounts (default general; empty for a migration).periodsboolean Create this fiscal year's and the next one's monthly periods (default true; false for a custom calendar)
- Responses
201Created, with the starter chart applied and this fiscal year's and the next one's monthly periods (object)- Errors
400,401,403,409,422,429,500(Error:error.type,message)
POST/v1/firm/clients/{id}/owner-invite
Issue a new owner invitation for a client the firm created (firm admin), replacing an unclaimed one. Refused once the owner has claimed the company or after the client revoked the firm's access.
- Operation
createOwnerInvite - Scope: admin
- Write: needs Idempotency-Key (or dry_run)
- Parameters
idpath, string, required
- Request body
Empty object
{}.- Responses
201Issued (object)- Errors
400,401,403,404,409,422,429,500(Error:error.type,message)
POST/v1/firm/clients/lock-period
Bulk: lock the period containing a date in each selected client (people only). Each company is locked separately, as you, and audited in its own log; one failure never blocks the others. dry_run previews.
- Operation
lockClientPeriods - Scope: approve
- Write: needs Idempotency-Key (or dry_run)
- Request body
company_idsarray of string, requireddatestring, required Calendar date, YYYY-MM-DD.status"soft_locked" | "hard_locked", requiredreasonstring, requireddry_runboolean
- Responses
200Per-company results (object)- Errors
400,401,403,409,422,429,500(Error:error.type,message)
POST/v1/firm/kill-switch
Suspend or resume every firm agent's writes in every client (firm admin)
- Operation
setFirmKillSwitch - Scope: admin
- Write: needs Idempotency-Key (or dry_run)
- Request body
suspendedboolean, requiredreasonstring, required
- Responses
200Updated (object)- Errors
400,401,403,409,422,429,500(Error:error.type,message)
POST/v1/firm/sessions
Open a firm web session with a member's firm key (ebf_ token shown once, stored hashed; 8 hours idle, 7 days at most)
- Operation
createFirmSession - Scope: read
- Write: needs Idempotency-Key (or dry_run)
- Request body
Empty object
{}.- Responses
201Opened (object)- Errors
400,401,403,409,422,429,500(Error:error.type,message)
GET/v1/firm/sessions
Your active firm sessions
- Operation
listFirmSessions - Scope: read
- Read
- Responses
200Sessions (object)- Errors
400,401,403,429,500(Error:error.type,message)
POST/v1/firm/sessions/{id}/revoke
Sign a firm session out (your own; firm admins: anyone's)
- Operation
revokeFirmSession - Scope: read
- Write: needs Idempotency-Key (or dry_run)
- Parameters
idpath, string, required
- Request body
reasonstring
- Responses
200Revoked (object)- Errors
400,401,403,404,409,422,429,500(Error:error.type,message)
GET/v1/firm/audit/verify
Verify the firm's own audit hash chain
- Operation
verifyFirmAudit - Scope: read
- Read
- Responses
200Verdict (AuditVerdict)- Errors
400,401,403,429,500(Error:error.type,message)
GET/v1/firm/audit/events
The firm's audit events, newest first
- Operation
listFirmAuditEvents - Scope: read
- Read
- Parameters
before_seqquery, integerlimitquery, integer
- Responses
200Events (object)- Errors
400,401,403,429,500(Error:error.type,message)
GET/v1/firm/proposals
The approval queue across every client that granted the firm access: pending proposals, oldest first, filtered by client, agent (the agent in the company or the firm agent behind it; or by name), amount and age.
- Operation
listClientProposals - Scope: read
- Read
- Parameters
company_idquery, stringagent_idquery, stringagent_namequery, stringmin_centsquery, integermax_centsquery, integerolder_than_daysquery, integerlimitquery, integer
- Responses
200Pending proposals (object)- Errors
400,401,403,429,500(Error:error.type,message)
POST/v1/firm/proposals/decide
Batch approve or reject proposals across clients (firm members only; reject needs a reason). Each decision runs separately in its company as you, through the same rules as a single approval, and is audited in that company's log; one failure never blocks the others (per-item results). dry_run previews.
- Operation
decideClientProposals - Scope: approve
- Write: needs Idempotency-Key (or dry_run)
- Request body
decision"approve" | "reject", requiredreasonstringitemsarray of object, requireddry_runboolean
- Responses
200Per-item results (object)- Errors
400,401,403,409,422,429,500(Error:error.type,message)
GET/v1/firm/close
The close checklist of the period containing a date in every client that granted the firm access
- Operation
listClientCloseStatus - Scope: read
- Read
- Parameters
datequery, stringunapplied_daysquery, integer
- Responses
200Per client (object)- Errors
400,401,403,429,500(Error:error.type,message)