Evenbead docs

Firm

27 operations. All areas

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
  • name string, required
  • admin_name string, required
Responses
  • 201 Created (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
  • 200 Firm (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
  • name string, required
  • role "admin" | "cpa" | "bookkeeper", required admin and cpa: all scopes in clients (admin also manages the firm); bookkeeper: read and propose.
Responses
  • 201 Added (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_removed query, boolean
Responses
  • 200 Members (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
  • id path, string, required
Request body
  • reason string, required
Responses
  • 200 Removed (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", required
  • member_id string
  • firm_agent_id string
  • scopes array of "read" | "propose" | "approve" | "admin", required
  • expires_in_days integer Lifetime in days. Default: 365 for a member's key, 30 for a firm agent's (at most 90).
  • rate_limit_rpm integer | null This key's own rate budget in requests per minute (null: the firm default).
Responses
  • 201 Created (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
  • 200 Keys (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
  • id path, string, required
Request body
  • overlap_seconds integer
  • expires_in_days integer Lifetime in days. Default: 365 for a member's key, 30 for a firm agent's (at most 90).
  • rate_limit_rpm integer | null This key's own rate budget in requests per minute (null: the firm default).
  • reason string
Responses
  • 201 Rotated (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
  • id path, string, required
Request body
  • reason string, required
Responses
  • 200 Revoked (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
  • name string, required
  • scopes array of "read" | "propose" | "approve" | "admin", required
Responses
  • 201 Created (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
  • 200 Agents (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
  • id path, string, required
Request body
  • company_id string, required
  • posting_threshold_cents integer, required Integer cents.
  • scopes array of "read" | "propose" | "approve" | "admin"
Responses
  • 200 Assigned (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
  • id path, string, required
Request body
  • company_id string, required
  • reason string, required
Responses
  • 200 Unassigned (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
  • id path, string, required
Request body
  • reason string, required
Responses
  • 200 Revoked (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_of query, string
Responses
  • 200 Clients (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
  • name string, required
  • owner_name string, required
  • starter_chart "general" | "services" | "retail" | "empty" Starter chart of accounts (default general; empty for a migration).
  • periods boolean Create this fiscal year's and the next one's monthly periods (default true; false for a custom calendar)
Responses
  • 201 Created, 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
  • id path, string, required
Request body

Empty object {}.

Responses
  • 201 Issued (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_ids array of string, required
  • date string, required Calendar date, YYYY-MM-DD.
  • status "soft_locked" | "hard_locked", required
  • reason string, required
  • dry_run boolean
Responses
  • 200 Per-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
  • suspended boolean, required
  • reason string, required
Responses
  • 200 Updated (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
  • 201 Opened (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
  • 200 Sessions (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
  • id path, string, required
Request body
  • reason string
Responses
  • 200 Revoked (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
  • 200 Verdict (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_seq query, integer
  • limit query, integer
Responses
  • 200 Events (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_id query, string
  • agent_id query, string
  • agent_name query, string
  • min_cents query, integer
  • max_cents query, integer
  • older_than_days query, integer
  • limit query, integer
Responses
  • 200 Pending 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", required
  • reason string
  • items array of object, required
  • dry_run boolean
Responses
  • 200 Per-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
  • date query, string
  • unapplied_days query, integer
Responses
  • 200 Per client (object)
  • Errors 400, 401, 403, 429, 500 (Error: error.type, message)