Skip to main content
Spec ID: FA-18
Status: 📋 Contract frozen (implementation 📝 Planned — no production RPC until migrations ship)
Last Updated: 2026-04-26
Canonical integration reference for FA-18: revenue contracts, revenue schedules (invoice XOR contract source), deferred revenue, single fiscal period recognition runs, and GL posting via FA-02. Authoritative duplicates: Event payload is defined identically in EVENT_CONTRACTS.md § FA-18. HTTP shape (if used) is defined in API_CONTRACTS.md § FA-18. This file ties them together and documents GL line mapping and transport choice.

Integration Summary


Transport (frozen)

Callers must hold PF-30 fa.revenue_recognitions.process (or equivalent) in addition to tenant RLS.

RPC: fa_process_revenue_recognition

Signature (frozen):
Semantics:
  1. Select active fa_revenue_schedules for p_organization_id that intersect the fiscal period identified by p_fiscal_period_id (via fa_fiscal_periods), have remaining_to_recognize > 0, and satisfy date window rules per spec.
  2. For each schedule, insert at most one fa_revenue_recognitions row for (revenue_schedule_id, fiscal_period_id) (UNIQUE).
  3. Update fa_revenue_schedules.total_recognized in the same transaction as the insert.
  4. Phase 1 GL scope (DEFERRED): Do not call fa_create_journal_entry() from fa_process_revenue_recognition() in Phase 1. Recognition rows are written with journal_entry_id IS NULL and journal_entry_line_id IS NULL. A Phase 2 task will post GL via FA-02 and back-fill the linkage. This boundary keeps Phase 1 self-contained and decoupled from FA-02’s not-yet-frozen RPC signature.
  5. Inserts MUST use ON CONFLICT (revenue_schedule_id, fiscal_period_id) DO NOTHING so the function is idempotent on retry.
Optional filter (HTTP only): If the HTTP layer accepts schedule_ids?: uuid[], it MUST filter to those IDs within p_organization_id only; omitting the array means “all due schedules” for the period (same as RPC-only callers invoking for the whole org period batch).

Event: revenue_recognized

Publisher: FA (FA-18)
Subscribers (planned): FA-02, FA-05, FA-13
Emit after a recognition row is committed (and ideally after GL post when GL is in scope for that run). Payload (frozen) — see EVENT_CONTRACTS.md:

HTTP: Recognize revenue (optional wrapper)

Endpoint: POST /api/v1/fa/revenue/recognize
Logical mapping: Body → fa_process_revenue_recognition with p_user_id = auth.uid().
Request:
Response (200):
Errors: 400 invalid body / unknown period; 403 tenant or permission; 422 schedule not eligible (closed period, zero remaining, etc.). Do not echo internal SQL.

GL mapping (FA-02)

Exact account resolution: FA-01 CoA + org policy; implementation calls FA-02’s standard journal entry API/RPC. journal_entry_line_id SHOULD reference the credit revenue line (or documented pair) for audit trail per FA-18 spec clarifications.

Planned consumers (Phase 2)

  • invoice_sent (FA-05), contract_signed (FA-13) — auto-create schedules/contracts; not in Phase 1.

Spec reference

PENDING_CONTRACTS: FA-18 integration IOU resolved 2026-04-26 — row archived under Resolved Stubs.