Skip to main content

Outcome

Your integration temporarily gates delegated writes for every access event, reconciles the current company projection, applies unavailable cleanup only when current access is unavailable, and resumes future authorized work when current access is available.

Prerequisites

  • A verified Partner webhook receiver with durable deduplication by event UUID.
  • A company-indexed command queue and an access gate that can block work before any /v2/ request.
  • Durable storage for company UUID, last observed case_access, access-event UUIDs and authorization-version provenance, and finalized Case UUIDs.
  • A Partner key for state reconciliation.
  • Python 3.11+ with requests and your integration’s access_control module. Its AccessControlStore.accept_event method must be idempotent and durable; its state methods must atomically control queue admission and cleanup for one company.

Lifecycle context

API-only onboarding starts provisionally; first setup/login confirms the named Partner once for the current authorization version. Hosted onboarding confirms terms and delegation in its flow. A revocation is the final event whose creation and signature are permitted by the preceding authorized state. That does not make it the last delivery chronologically: Partner deliveries are unordered and at least once. An active company admin can reconnect through the client-authorized connection flow. The company keeps its UUID. authorization_version identifies consent text; it is not a sequence number or ordering clock. Reconnection does not replay missed events or restore discarded drafts.

1. Reconcile every access event against current state

After signature verification, validate all three access-event types. This sandbox reference flow proves its environment with an authenticated safe read, durably accepts/deduplicates the event, gates writes, and only then fetches the authoritative company projection:
Python access handler
accept_event must return success for an already stored event so duplicates still trigger reconciliation. gate_company temporarily prevents queue admission and dispatch. apply_current_state with unavailable commits that state, cancels or quarantines not-yet-sent commands, and removes local projections of inaccessible Partner drafts. Applying available commits the current state; only the separate successful release_company call removes the temporary gate, without replaying old work. Each state application binds the accepted event UUID, company UUID, authorization version, exact event bytes, exact Company request URL, exact response bytes and HTTP status, and the fetched access/readiness projection in one durable record. The environment proof uses the authenticated Partner-wide token-info read. It requires no company selection and fails closed unless one case-insensitively named response header has the exact lowercase value sandbox. Exceptions from validation, exact identifier/body capture, durable acceptance, gating, state application, or release remain terminal; the fetch branches handle expected HTTP outcomes explicitly without releasing the gate accidentally. If a delayed revocation arrives after restoration, the fresh company response is available, so the available branch preserves or restores traffic. If the current response is unavailable, cleanup applies regardless of which access event triggered the fetch. Never branch on event arrival order or compare authorization_version values to decide access. Company detail 404 is a legitimate hidden-resource outcome after final revocation. It is handled only after durable acceptance and gating: record unavailable access with reconciliation still pending and keep the gate. A transport failure, malformed 200, or other HTTP status also records pending reconciliation, keeps the gate, and exits for retry. Only a verified 200 whose exact id matches and whose current case_access is available can apply available state and release the gate. Never interpret hidden access as deletion of the company’s legal records.

2. Interpret the current company projection

The response below shows a connected company whose Case Management API access is unavailable, for example because paywise suspended Case Management API use. A disconnected company is hidden with 404. Readiness can remain green while access is unavailable, so the reconciliation worker takes the unavailable branch; a schema-valid response with case_access: available would take the available branch instead.

Representative response

This complete response matches Company and demonstrates why readiness cannot stand in for delegation: the data is ready while Partner access is unavailable.

3. Preserve finalized knowledge and discard draft work

paywise deletes Partner-created drafts that become inaccessible. Remove them from retry queues and mark local draft projections unavailable; do not attempt to recreate them under a new key. Keep finalized order and mandate UUIDs in the audit trail. Finalized cases remain available to company and staff channels, even when the Partner can no longer retrieve them. Do not infer finalization from a lost 404. Only a previously stored successful finalize response or authoritative pre-revocation read establishes that state.

4. Repair missed events with scheduled reconciliation

Run the same gate, exact Company GET, and case_access branch periodically for every company your integration already knows, even without a new event. This repairs a missed restoration so traffic cannot remain stranded behind a stale local block. It also repairs a delayed or missed revocation from current state. Restoration resumes future Partner events, but events missed while access was unavailable are not replayed. Reconcile every still-relevant finalized resource your Partner can currently access. Treat any new draft or command as a new business decision with a new idempotency key—never replay the revoked queue. If rebuilding an all-company projection from GET /partner/v2/companies/, use overlapping updated_since scans, follow every exact next URL, reconcile by (id, updated_at), and periodically repeat a full scan. Mutable offset pagination has no snapshot, so one pass cannot prove completeness under concurrent changes.

Failure and recovery

  • Duplicate access event: deduplicate by event UUID, then refetch the company; do not skip current-state reconciliation.
  • Out-of-order delivery: temporarily gate and fetch current state. Do not use authorization_version to order confirmation, revocation, or restoration.
  • Company 404 after revocation: record unavailable/pending reconciliation and keep traffic gated. The Company may legitimately be hidden; an inaccessible Partner draft may also have been deleted.
  • Missing events during revocation: expected. Restoration has no replay; run current-state reconciliation. Deliveries that were still queued when access ended are closed as failed with error_message: partner_access_unavailable without an HTTP call; they cannot be redelivered (404).
  • Membership commands after a release: 404, like every other request for a company outside your access. An offboarded company answers 409 company_offboarded to every membership command instead.
  • Company detail still unavailable after restoration: do not unblock. Verify entitlement with the authorized portal/support path.

Verify

Exercise revocation, restoration, and delayed-revocation delivery with queued work. Confirm the event is durably accepted before 2xx, every delivery first gates writes, unavailable cleanup follows only current case_access: unavailable, and a delayed revocation cannot override current available state. Confirm finalized IDs remain, drafts are not recreated, and a periodic run repairs a deliberately missed restoration without replaying commands.