---
title: "Webhook Event Registry"
slug: webhook-event-registry
section: Integrations
status: stable
description: "This registry reconciles the source-audited application event contract with a dated report of wider webhook routing."
last-updated: 2026-10-07
---

# Webhook Event Registry

This registry reconciles the source-audited application event contract with a dated report of wider webhook routing. The n8n handler table below is a 2026-06-26 reported routing snapshot—not proof of current deployment, active subscriptions, successful delivery, or business processing. The live routing table and deployed state require verification with their owning systems.

## Purpose

This page separates source evidence from reported routing and runtime outcomes. The application contract inventory is grounded in the BackOfficePrototype development source listed below. Older n8n and portal tables are retained as dated reported evidence; their present configuration and outcomes are unknown.

> **Historical routing note — not a delivery guarantee**
>
> A prior report described managed-row fan-out deduplication. That report does not establish current deployment or that any event reaches n8n exactly once. Verify current dispatcher configuration and receipts with the n8n owner before relying on it.

> **Grounding & ownership boundary**
>
> The n8n routing and Applicant Portal rows are a 2026-06-26 reported snapshot. Its claims are not independently verified here against deployed workflows, subscriptions, receipts, or processing. This page documents the contract and verification gaps; changes to runtime handlers belong to their owning teams.

## Evidence Levels & Version

**Version:** 1.0.0

**Source audit:** BackOfficePrototype development, commit `02306ee3114ee0a370f36de6bc18276408881834`. Relevant source references: `server/services/eventEmitter.ts`, `server/services/lifecycle/reconcileEvents.ts`, `server/webhook.ts`, `server/services/webhookDispatcher.ts`, and `server/services/webhookEventCatalog.ts`. Inventory rows added after that audit (applicant and host events) were read from `server/services/webhookEventCatalog.ts` and related source on the BackOfficePrototype `development` branch on 2026-09-30.

Evidence labels used on this page:

- **Source-audited** means the development source defines or constructs the contract; it does not mean that code is deployed or invoked in production.
- **Reported snapshot** means recorded routing/configuration information as of 2026-06-26; it is not current-state verification.
- **Catalogued**, **helper**, **emitter**, and **outbox** describe source-level catalog entries and code paths only.
- **Subscribed**, **delivered**, and **processed** are separate runtime states. No deployed subscription, delivery receipt, or downstream business processing is verified by this audit.

The [machine-readable draft](/api/events/inventory/v1) is backed by `content/event-contracts.v1.json`. this repo's inventory test (`node --test tests/event-inventory.test.ts`, nexus-docs, not Globus) validates the [synthetic fixtures](/api/events/fixtures/v1) locally; neither is production evidence. With a checked-out Globus source tree, run `GLOBUS_SOURCE_ROOT=/path/to/BackOfficePrototype node --import tsx --test tests/event-inventory.test.ts` to catch removed source event names and required payload keys; it still does not prove deployed routing.

## System Coverage & Owners

Coverage below is intentionally bounded to source evidence and explicit gaps. “Next check” identifies the verification needed before treating a path as operational.

| System | Evidence / coverage boundary | Owning team | Next check |
| --- | --- | --- | --- |
| Globus / BackOfficePrototype | Source-audited application event construction and outbox/dispatch paths in the cited development SHA; deployed status is unknown. | Globus / BackOffice | Confirm deployed revision, outbox rows, dispatcher configuration, and representative receipts. |
| n8n | Only a 2026-06-26 reported routing snapshot; active handlers, subscriptions, and processing are unverified. | Automation / n8n | Inspect deployed router and workflows, test a representative event, and correlate receipt with processing logs. |
| Applicant Portal | A 2026-06-26 report lists direct handlers; current webhook endpoint and deployed behavior are unverified. | Applicant Portal | Verify deployed endpoint, subscribed event list, and persisted result for a test delivery. |
| Host Portal | Historical routing report mentions forwarding; portal subscription and processing are unverified. | Host Portal | Confirm deployed endpoint and event subscription/receipt with its owner. |
| Partner Portal | No source-audited contract or verified subscription established here. | Partner Portal | Identify intended event contract and owner; verify endpoint and subscription. |
| HubSpot | Historical n8n actions are reports, not proof of current credentials, mappings, or writes. | CRM / HubSpot integration | Inspect deployed mapping and verify a test object's write and correlation ID. |
| NetSuite | Historical handler/action report only; current invoice delivery and finance-summary writes are unverified. | Finance / NetSuite integration | Confirm handler state and safely trace a test invoice through to the Globus finance summary. |
| SEVIS | No verified subscription or processing path established here. | SEVIS integration | Confirm intended event keys, owning service, and deployed consumer. |
| Keycloak | Provisioning is described in the historical routing snapshot only; current provisioning is unverified. | Identity / Keycloak | Verify deployed provisioning trigger and correlate a test identity without exposing credentials. |
| GCS | No source-audited webhook consumer or verified delivery path established here. | Platform / Storage | Identify whether GCS participates in this event flow and inspect the owning integration if so. |
| SendGrid | Historical email actions are not evidence of current delivery or email processing. | Messaging / SendGrid | Verify deployed template/action mapping and provider receipt for a controlled test. |
| MCP coordination | This document is a local registry update; connector visibility or ecosystem sync is not verified. | Ecosystem / MCP coordination | Confirm the connector sees this revision and record the sync result. |

## Application Contract Inventory

This inventory is source-level contract evidence, not a claim that any event is subscribed to or processed in a deployed system. Statuses deliberately distinguish code/catalog evidence from runtime states.

| Event key | Source evidence / status | Contract details |
| --- | --- | --- |
| `application.created` | Catalogued; emitter/outbox path source-audited. | Preserve this established event key; this registry does not rename it. |
| `application.updated` | Legacy helper; no callers found in the ticket investigation. | Legacy helper envelope only; `eventId` is not promised. Do not infer an active application-update emitter from its existence. |
| `application.journey_changed` | Emitter/outbox source-audited. | Carries journey transition identifiers and previous/new journey values; optional staff actor. `POST /api/admin/applications/:id/force-sync` (`applications.manage`, audited as `application.force_sync`, 404 if the application is missing) re-emits it with `forceResync: true`, equal previous and new position, and a `force-resync:<timestamp>` dedupe suffix so it never collides with the natural journey dedupe. It exists for applications whose journey events were never delivered, so that downstream listeners such as the Applicant Portal re-fetch step progress. |
| `application.readiness_changed` | Emitter/outbox source-audited. | Carries readiness transition identifiers and previous/new readiness values; optional staff actor and reason may be present. |
| `application.stage_transitioned` | Source/catalog evidence includes a comment that the managed n8n subscription excludes this event; deployed subscription state is unknown. | Carries `historyId`, nullable ID/from fields, required `toStage*` fields, `changeSource`, and `transitionedAt`. |
| `application.submitted` | Source/catalog evidence; deployment and subscription unknown. | `submittedAt` is optional. |
| `application.lifecycle_reconciled` | Direct `ops_events` insert/outbox path source-audited. | `entityId` identifies the application; includes previous/new journey and readiness values, nullable stage IDs, next-action, actor, source, and reasons. |
| `applicant.updated` | Contact snapshot event; it is about the applicant, not an application update. | Snapshot nulls are intentional clears, not missing values to preserve. |
| `applicant.created` | Catalogued; emitter path read on `development` (2026-09-30). | Optional season/operational-cycle context (`seasonId`, `seasonName`, `operationalCycleId`, `operationalCycleName`). Program-associated creations (the HubSpot onboarding provision route and any atomic applicant+application create) also carry optional `brandId`, `brandName` (always emitted as a matched pair; `brandName` is resolved from the authoritative brands row, not the denormalised program copy) and a `program` context object `{ id, name, brandId, brandName }`. These brand/program keys are omitted — never null — when the applicant is created before a program is resolved (for example portal self-registration). |
| `applicant.invite_resent` | Catalogued; emitter path read on `development` (2026-09-30). | Staff re-sent the portal onboarding invite. Payload carries a freshly minted one-time token and the URL nested at `accessToken.redemptionUrl`; prior tokens are revoked. Never fires for applicants who already activated. The `development` n8n Applicant Domain handler writes this URL to HubSpot `portal_invite_url` (same precedence as `applicant.created`); it does not change `portal_onboarding_status`, and a missing/empty URL does not clear a stored one. |
| `host.verification.verified` / `failed` / `needs_review` | Catalogued; emitter paths read on `development` (2026-09-30). | Internal signals: payload is `{ hostOrgId, status }` (the staff review route also adds `reviewedBy`) and deliberately carries **no host contact email**, so the n8n host email relay cannot deliver them to host-side contacts; the Account Manager is notified through the staff path instead. An earlier change that resolved `hostEmail` into these payloads is not present on `development`. The automated run is advisory and always emits `needs_review`; `verified`/`failed` only follow a human compliance decision. |
| `host.user_invited` | Catalogued; `development` (2026-09-30). | Carries the tokenized activation URL plus sponsor branding resolved from the host's effective agreement scope: `sponsorBrandName`, `sponsorPortalLabel`, `sponsorContactEmail`, `sponsorContactNumber`, `sponsorWebsite`, `sponsorSignature`. Unresolved or failed branding falls back to `Sponsor` / `Sponsor Portal` / `Sponsor Portal Team` with null contact details. |
| `host.user.first_login` | Catalogued; `development` (2026-09-30). | A host portal user completed their first successful login; emitted once per host user. |
| `host.ev_removed` / `host.visa_denied` | Catalogued; host email templates read in `server/seed/notificationTemplates.ts` on `development` (2026-09-30). | Both host-audience templates share the approved roster-change copy: title "Change to Your Participant Roster", body "Hello {{hostName\}\}, We would like to notify you of a change to your participant roster. Participant {{participantName\}\} has been removed from the program due to a visa denial or personal request…" (the earlier per-event subjects and the removal-reason text are gone). |
| `host.participant_recommended_digest` | Catalogued; `development` (2026-09-30). | Daily rollup of participants newly added to a host's recommended list by a Placement Specialist; one event per host and day, delivered through the managed n8n Dispatcher. |
| `host.reservation_three_day_digest` | Catalogued; `development` (2026-09-30). | Daily host rollup of active reservations entering the three-day remaining window. |
| `host.org_document_expiring_soon` | Catalogued; `development` (2026-09-30). | Emitted once per (document, warning tier) for a current, approved host organization compliance document. The 30- and 14-day tiers are Account Manager-only; the seven-day tier also resolves the host recipient and uses the existing n8n host-email relay. `host.org_document_expired` is an internal alert with `hostEmail` null. |

The source-level statuses above do not assert **subscribed**, **delivered**, or **processed**. In particular, the contradictory `application.updated` row in the historical n8n report and its legacy-helper-only source evidence remain unverified. The historical portal `stage.transition` row is also stale/unverified and is not equivalent evidence for `application.stage_transitioned`.

## Transport Envelopes & Delivery Semantics

The source defines distinct envelope shapes; consumers should not assume fields from one path are present on another:

| Path | Envelope / semantics |
| --- | --- |
| Outbox | `{eventId, id, eventType, timestamp, data}` with optional `callbackUrl`. Delivery-time enrichment can be absent or fall back. `id` aliases `eventId`; `status` mirrors `journeyPosition`; `operationalCycleId`/`operationalCycleName` mirror season fields. |
| Normal subscription | `{event, eventType, data, timestamp}` with `eventId` when supplied by `emitEvent`. `data` includes `entityType`, `entityId`, and the original event fields (flattened, not a nested `payload`). No n8n enrichment is added. |
| Legacy helper | `{event, eventType, data: {globusApplicationId, status}, timestamp}`. No `eventId` is promised. |
| Season / operational-cycle dual publish | Season catalog changes (`created`, `updated`, `deleted`) and status changes emit the canonical `operational_cycle.*` event (including `operational_cycle.status_changed`) always, and also the legacy `season.*` event while `WEBHOOK_DUAL_PUBLISH_OPERATIONAL_CYCLE` is on. The variable is read at emit time; unset or empty means on, and only `false` (any case) or `0` turns the legacy emit off. Both events carry `seasonId` and `operationalCycleId` with the same value. The legacy event's envelope carries `deprecated: true` and `successorEventType`. |

Subscriptions use `X-Globus-Signature` HMAC verification. The n8n push uses `X-N8N-API-KEY` when configured; this is a distinct optional credential, not the webhook signature. Do not publish either secret. An HTTP 2xx response proves receipt/acknowledgement only, not downstream business processing. Eligible failed outbox deliveries may retry; `not_subscribed` rows are skipped. Subscription retries can also repeat attempts. Do not assume exactly-once delivery, deduplication, or global ordering unless verified by the receiving system.

Events outbox admin routes: `GET /api/admin/events/outbox/pending` lists pending events and `GET /api/admin/events/outbox` lists the newest 100, optionally filtered by `status` (`pending`, `published`, `failed`, `dead_letter`), `eventType`, `aggregateType` and `brandId`; `GET /api/admin/events/outbox/:id` returns one event (404 if unknown). All three need `audit_log.view`. `POST /api/admin/events/outbox/:id/retry` and `/mark-published` need `system_settings.manage` and are audited. `GET /api/admin/webhooks/delivery-queue/health` (`api_keys.view`) returns `pending` (no attempts yet), `inFlight` (pending with attempts), `failedLastHour`, `deadLetter` and `observedAt`, counted from `webhook_deliveries`.

The existing n8n implementation is tracked by [the application handler ticket](https://app.asana.com/1/817430812898727/project/1213692464709683/task/1218957811099469); that reference is not runtime verification. This documentation task does not change runtime code, rename events, or request replay.

**Related operator and inbound webhook routes.** `POST /api/admin/events/outbox/:id/mark-published` (permission `system_settings.manage`; API-key scope `admin.write`) sets an outbox row to `published` with `published_at` now and returns `success: true`; it does not deliver the event, and a non-UUID id returns 400. The inbound `POST /api/webhooks/portal/document-review` authenticates with an `X-API-Key` header (401 if missing or invalid, 403 if revoked, expired or lacking `*`, `portal.partner_proxy` or `portal.host_proxy`). Its body takes `documentId`, `status` (`verified`, `approved`, `rejected` or `resubmission_requested`) and optional `reason`, `reviewerName`, `reviewedAt` and `deliveryId`; a repeated `deliveryId` returns 200 with `deduplicated: true`. Once the key is accepted, errors use flat bodies rather than the standard envelope: 400 `Invalid webhook payload`, 404 `Document not found`, and 409 with `code` `INVALID_STATE_TRANSITION`, `currentState` and `requestedState` when the review state change is not allowed.

## Verification & Open Gaps

- Verify deployed subscriptions and handlers with their owning teams; the development SHA and 2026-06-26 routing report cannot establish current deployment.
- Resolve the `application.updated` contradiction: source investigation found a legacy helper with no callers, while the dated routing snapshot lists an active application handler.
- Verify whether the `application.stage_transitioned` exclusion comment still matches deployed n8n subscription configuration. The older portal `stage.transition` row is stale/unverified and uses a different key.
- Obtain correlated evidence for each delivery path: subscription/configuration, HTTP receipt, and downstream processing are separate checks.
- Confirm event-specific retry, deduplication, ordering, and delivery-time enrichment behavior with the dispatcher and receiving consumers.
- Confirm MCP connector visibility and ecosystem sync separately; a local document change is not evidence of sync.

The machine-readable draft and synthetic local test fixture are useful for contract validation only; neither proves live traffic or external-system behavior.

## Reported n8n Handlers — 2026-06-26 Snapshot

**Historical 2026-06-26 reported routing snapshot only.** The workflow IDs and actions below are reported configuration/action claims, not proof of active deployment, current routing, delivery, or processing.

| Domain | Handler ID | Events | Action |
| --- | --- | --- | --- |
| applicant.* | vrd1rkcp7fxcpZ6u | applicant.created | Writes portal_invite_url and onboarding status to HubSpot Contact; triggers Keycloak provisioning; sends Welcome email via SendGrid; calls NetSuite Delivery |
| applicant.* | vrd1rkcp7fxcpZ6u | applicant.updated | Syncs profile fields (phone, DOB, passport, address) to HubSpot Contact; calls NetSuite Delivery |
| application.* | 3JmDhlns2mAyzBnj | application.created / updated / submitted / journey_changed / readiness_changed / lifecycle_reconciled | Reported HubSpot Application upsert; `application.updated` conflicts with source evidence (see inventory) |
| document.* | FM4h8By6UkMmMvBU | document.* (all states) | Upserts HubSpot Document custom object with status, type, url, rejection_reason; if passport type, triggers Passport Verification workflow |
| host.* | g2VNVRuVzqF9I3Hg | host.profile_created / updated / deactivated | Sends status email to host admin; forwards to Host Portal |
| host.* | g2VNVRuVzqF9I3Hg | host.participant_matched / participant_recommended | Sends match/digest email; forwards to Host Portal |
| host.* | g2VNVRuVzqF9I3Hg | host.verification.verified / failed / needs_review | Sends verification status email; forwards to Host Portal |
| host.* | g2VNVRuVzqF9I3Hg | host.user_invited | Sends activation link email to invitee; forwards to Host Portal |
| job.* | 3EqRMbNJ2uWl6yBZ | job.submitted / approved / published / created / updated | Upserts HubSpot Job custom object (2-59396510) with status, approval stage, partner result |
| provisioning.* | drYz2ppelNE9zvxV | provisioning.* | Checks/provisions Portal user via Globus onboarding API; calls HubSpot and NetSuite Delivery |
| reference.* | JrLUvlyOWe0cCQ5A | reference.invited | Sends invite email to referee via SendGrid |
| reference.* | JrLUvlyOWe0cCQ5A | reference.reminder_requested | Sends reminder email to referee via SendGrid |
| reference.* | JrLUvlyOWe0cCQ5A | reference.completed | Sends confirmation email to applicant + ops alert to ops@allianceabroad.com |
| reference.* | JrLUvlyOWe0cCQ5A | reference.expired | Sends expiry alert to ops@allianceabroad.com only |
| step.* | vL57Sf5msbvutmav | step.updated | Builds HMAC-signed envelope and forwards to Applicant Portal /api/globus/webhook |
| step_review.* | 3TVV1Ed8do0FPXGW | step_review.approved | Updates HubSpot Application record with review metadata |
| step_review.* | 3TVV1Ed8do0FPXGW | step_review.rejected | Updates HubSpot Application record; sets readiness_state=blocked; sends applicant notification via SendGrid |
| eligibility_override.* | XgB1zruWDPfnWXS1 | eligibility_override.approved / rejected / revoked | Writes override metadata to HubSpot Application; sends notification to requesting staff member via SendGrid |
| notification.* | uTdm5XQ3MJDxgmYx | notification.send_requested | Looks up HubSpot Contact; routes via WhatsApp > Email > SMS; sends via HubSpot APIs; PATCHes delivery status back to Globus |
| catalog.* / operational_cycle.* | UByWEMK39HspDXU0 | catalog.program_created / updated | Upserts HubSpot Program custom object |
| catalog.* / operational_cycle.* | UByWEMK39HspDXU0 | catalog.season_created / updated / operational_cycle.created / updated | Upserts HubSpot Season/OC custom object; creates Program association |
| catalog.* / operational_cycle.* | UByWEMK39HspDXU0 | catalog.country_created / updated | Upserts HubSpot Country custom object |
| staff.* | Mo70yfbw5YOgwVvW | staff.send_message | Sends direct message email to applicant via SendGrid |
| staff.* | Mo70yfbw5YOgwVvW | staff.request_document | Sends document request email to applicant via SendGrid |
| staff.* | Mo70yfbw5YOgwVvW | staff.request_payment | Sends payment request email with Globus payment URL to applicant via SendGrid |
| workflow.* | ILh2zCp5uWv1fNNB | workflow.published / config_published | Builds HMAC-signed envelope; fans out to Applicant Portal and Host Portal /api/globus/webhook |
| netsuite.* | rvLCpGsMjgkxNFPE | netsuite.invoice.created / updated | Snapshot reported handler inactive; described target prepares invoice data from NetSuite and calls NetSuite Invoice Delivery to PUT `/api/applications/:id/finance-summary` on Globus Hub |

> **Repository note (n8n-workflows `development`, read 2026-09-30) — not deployment proof**
>
> The repository's `[Globus] Handler: Host Domain` workflow (`workflows/1oNUgxEtjFljL83Q__globus-handler-host-domain.json`) differs from the snapshot rows above: it delivers through SendGrid only (`delivery_channel` = `sendgrid`) and contains no Host Portal forward node; it builds an email for both `host.participant_recommended` and `host.participant_recommended_digest` (a digest without a contact email looks up the partner organization's contact email by `hostOrgId` first); and its `host.verification.*` templates cannot send because those events carry no host email (see inventory), so they skip cleanly. The repository's `[Globus] Handler: Applicant Domain` workflow (`workflows/MUdORjJIsdInSSGF__globus-handler-applicant-domain.json`) handles `applicant.invite_resent` by writing the redemption URL to HubSpot `portal_invite_url` (see inventory), and its HubSpot delivery path is the only delivery node wired in that file; the snapshot's Keycloak, SendGrid welcome and NetSuite claims for `applicant.created` are not visible there. The snapshot's handler IDs (`vrd1rkcp7fxcpZ6u`, `3JmDhlns2mAyzBnj`, `g2VNVRuVzqF9I3Hg`, `rvLCpGsMjgkxNFPE`, `vL57Sf5msbvutmav` and others) do not appear in the repository's `workflows/id-map.json`, which maps the applicant handler to `MUdORjJIsdInSSGF` (qa, prod), the application handler to `albIaWgKqO3ta571`, the host handler to `1oNUgxEtjFljL83Q` (dev) / `Tx8shxkRs1po6WJA` (qa, prod) and the NetSuite invoice handler to `dTZEVLpRSk6xFrLC` (dev) / `cHQOJV8CHAsVaPMz` (qa, prod). The dispatcher registers `step`, `step_status`, `screening` and `sevis` as noOps (the `step.*` push handler was deactivated 2026-09-02 and the portal pulls step data via workflow-snapshot), so the snapshot's `step.updated` forward to the Applicant Portal is not routed there.

## Applicant Portal — Direct Handlers

**Historical 2026-06-26 report; current portal subscriptions and processing are unverified.** A subset was reported as direct Applicant Portal handling, outside the n8n Dispatcher.

| Event(s) | Portal action |
| --- | --- |
| application.created / updated / submitted / stage.transition | Historical reported `syncApplicationFromGlobus` behavior. The `stage.transition` row is stale/unverified and is not source proof for `application.stage_transitioned`. |
| compliance.decision | Log only (no state mutation) |
| document.verified / document.rejected | Log only (no state mutation) |
| workflow.published | Upserts step library, phase library, program phases, program steps into Portal DB |
| workflow.config_published | Granular upserts by entitySyncType: step_library, phases, program_steps, hub_sub_tasks, placeholder_conditions |

## Intentional noOps

The following were reported as acknowledged noOps in the 2026-06-26 routing snapshot. Current registration and whether these events are safe to ignore are unverified; confirm with the n8n/domain owner before relying on this list. The last two rows (`integrity.*`, `reference_submission.*`) post-date that snapshot and were read from the `development` dispatcher workflow in n8n-workflows on 2026-09-30.

| Domain | Registered | Reason |
| --- | --- | --- |
| host_verification.* | backlog | Pending handler build |
| workflow.* (dispatcher) | #1706/#1707 | Delivered directly Globus→AP via HMAC |
| sla.* | — | Internal recalculations, no notification target |
| capacity.* | — | No handler defined yet |
| extension_request.* | 2026-05-08 | Handler not yet scoped |
| queue.* | 2026-05-13 | Internal job queue events |
| job_order.* | 2026-05-26 | Handler not yet scoped |
| housing_lead.* | 2026-05-13 | Handler not yet scoped. `housing_lead.deleted` began emitting in QA 2026-07 (housing lead delete endpoint, Task #1948) — still a noOp until a handler is scoped |
| brand.* | 2026-06-19 | Handler not yet scoped |
| system.* | 2026-06-24 | Internal platform health signals |
| integrity.* | 2026-08-26 | Handler not yet scoped |
| reference_submission.* | 2026-09-02 | Handler not yet scoped. `reference_submission.referee_changed` had no routing entry and threw `Unregistered domain 'reference_submission' received` on each Globus retry (Platform Pulse error storm, 2026-09-02), so the domain was registered as a noOp acknowledgement in the dispatcher |

## Needs Action — Defined, Not noOp

The following were reported as lacking a handler/noOp in the 2026-06-26 snapshot. Their present routing and delivery outcomes are unknown; they must not be described as currently dropped without verification. Recommendations remain proposals for owner review.

> **Recommended dispositions — pending owner confirmation**
>
> The disposition column is a recommendation based on each event's apparent intent, not a final decision. Confirm with the domain owner, then implement in the n8n Dispatcher / Domain Handler workflows (owning repo). "Build handler" means register a route and handler; "Register noOp" means add an explicit noOp acknowledgement; "Verify" means confirm coverage or intended consumer first.

| Event(s) | Recommended disposition | Notes |
| --- | --- | --- |
| applicant.arrival_confirmed | Build handler | Not in dispatcher |
| applicant.assignment.created / reassigned / auto_assigned | Register noOp | Not in dispatcher — internal assignment signals, no external notification target confirmed |
| applicant.finance_linked | Build handler | Not in dispatcher |
| applicant.next_action.invoked | Register noOp | Not in dispatcher — internal workflow signal |
| applicant.placement_confirmed | Build handler | Not in dispatcher |
| applicant.registered | Build handler | Not in dispatcher |
| applicant.status_changed | Build handler | Not in dispatcher |
| applicant.submitted | Build handler | Not in dispatcher |
| application.flow_available / flow_ineligible_observed | Register noOp | Not in dispatcher — internal eligibility signals |
| application.flow_reminder | Build handler | Not in dispatcher |
| application.stage_changed / stage_transitioned / status_changed / step.completed | Build handler | Not in dispatcher |
| catalog.program_* (wildcard) | Verify | catalog.program_created/updated ARE handled — verify wildcard coverage is sufficient or additional events need routing |
| checkin.reminder_due / checkin.submitted | Build handler | Domain not in dispatcher |
| commute_assessment.completed | Build handler | Domain not in dispatcher |
| compliance.became_compliant / became_non_compliant | Handled | The compliance domain is routed in the dispatcher (enabled, not noOp). The handler emails staff only for compliance.became_non_compliant, which needs resolved staff recipient emails on the payload (it errors without them); compliance.became_compliant and any other compliance.* event are acknowledged without an email |
| document.approved / deleted / replaced / resubmission_requested / uploaded / documents.all_verified | Build handler | Partial — only status events currently handled |
| finance_payment.created | Build handler | Domain not in dispatcher |
| host.contact_changed / document_expired / document_expiring_soon / ev_removed / operating_agreement.renewed / org_document_expired / org_document_expiring_soon / reservation.cancelled / reservation_expiring / status_changed / visa_denied | Build handler | Partial — only profile/verification/user_invited handled |
| partner.* (all events) | Verify | The partner domain is routed in the dispatcher (enabled, not noOp) — verify which partner.* events the handler covers |
| sevis_readiness.restored / sevis_readiness.revoked | Build handler | Domain not in dispatcher |
| staff.notification | Build handler | Not in dispatcher — send_message/request_document/request_payment ARE handled |
| step.lock_changed | Build handler | Only step.updated is handled |
| travel_request.* | Build handler | Domain not in dispatcher |
| business_bundle.* | Verify | Domain not in dispatcher — confirm intended consumer before choosing handler vs noOp |

## netsuite.* Handler Status — historical report

The 2026-06-26 snapshot reported the `netsuite.*` domain handler (`rvLCpGsMjgkxNFPE`) as inactive with no noOp registration. Repository check (n8n-workflows `development`, read 2026-09-30): the dispatcher routes `netsuite` to a handler with `enabled: true` and `noOp: false` (`dTZEVLpRSk6xFrLC` in the development file; `workflows/id-map.json` lists `cHQOJV8CHAsVaPMz` for qa and prod), and the workflow file `workflows/dTZEVLpRSk6xFrLC__globus-handler-netsuite-invoice-domain.json` exists. The snapshot ID `rvLCpGsMjgkxNFPE` does not appear in the repository. This is repository evidence, not proof of the live state of any environment.

> **Superseded: the repository registers and enables the handler**
>
> The historical re-enable recommendation no longer matches the repository, where `netsuite.*` is already routed to an enabled handler. The historical report described a target that prepares invoice data from NetSuite and PUTs to `/api/applications/:id/finance-summary` on the Globus Hub via NetSuite Invoice Delivery. Verify the live handler and target before choosing any disposition. Any runtime change belongs to the n8n owning repo.

## Dispositions & Follow-Up

Summary of follow-up questions surfaced by this registry. This page is documentation; the proposed routing dispositions below derive from the dated snapshot and need owner confirmation. Runtime changes belong to the owning system, not this docs page.

- Build handlers for the Needs-Action events marked **Build handler** (applicant / application lifecycle milestones, host expiry & status events, document state extensions, sevis_readiness, checkin, partner, travel_request, finance_payment, staff.notification, step.lock_changed).
- Register explicit dated noOps for the internal-only signals (applicant.assignment.*, applicant.next_action.invoked, application.flow_available / flow_ineligible_observed).
- Verify the ambiguous domains (catalog.program_* wildcard coverage; business_bundle.* consumer) before choosing handler vs noOp.
- Re-enable the netsuite.* handler (rvLCpGsMjgkxNFPE) or register it as an explicit noOp.
