Event catalog
This catalog lists GoodVision event types, triggers, and fields. Events use versioned names and are delivered through approved, active Webhook subscriptions.
For signature verification, token validation, deduplication, and acknowledgements, see Receive webhooks. Fields, enums, and permissions follow the event schema provided by the current Application's API product.
Complete subscription envelope
This complete business event represents activation and contains every required field. Plaintext HTTP delivery adds a top-level verification_token: validate and remove it to obtain this envelope. Encrypted delivery requires signature verification, decryption, and Token validation first.
{
"event_id": "evt_demo_activated",
"event_type": "oem.subscription.activated.v1",
"schema_version": "1",
"occurred_at": "2026-10-06T00:00:00Z",
"producer": "opaque",
"tenant_id": "org_customer_demo",
"resource_id": "sub_demo_cancel",
"resource_version": 2,
"correlation_id": "req_demo_activation",
"data": {
"id": "sub_demo_cancel",
"organization_id": "org_customer_demo",
"open_platform_application_id": "app_demo_saas",
"environment": "sandbox",
"product_tenant_id": "tenant_demo_cancel",
"party_id": "party_customer_demo",
"order_id": "order_demo_initial",
"product_code": "relaydesk",
"plan_code": "basic_monthly_demo",
"plan_version": 1,
"status": "active",
"current_period_start": "2026-10-06T00:00:00Z",
"current_period_end": "2026-11-06T00:00:00Z",
"status_effective_at": "2026-10-06T00:00:00Z",
"payment_reference": "payment_demo_initial",
"operation_id": "op_demo_activation",
"reason_code": "example_activation",
"resource_version": 2,
"created_at": "2026-10-05T23:55:00Z",
"updated_at": "2026-10-06T00:00:00Z"
}
}All IDs, plans, and reason codes are synthetic. producer: "opaque" is a display placeholder for an opaque source; use the issued schema for actual source enums. Do not hard-code the placeholder or example reason codes. Download JSON or see the complete HTTP request with headers, Token, and reproducible signature.
Every top-level field below is required for subscription events:
| Field | Type | Meaning and validation |
|---|---|---|
event_id | string | Stable business event ID; Inbox unique key |
event_type | string | Complete versioned name from the table; matches the header |
schema_version | string | Currently "1", not integer 1 |
occurred_at | RFC3339 string | Business event time, not the signing timestamp |
producer | string | Opaque source; validate against the issued schema |
tenant_id | string | Purchasing customer Organization; equals data.organization_id, not the application's owner Organization |
resource_id | string | SaaS subscription ID; equals data.id |
resource_version | integer ≥ 1 | Subscription version; equals data.resource_version |
correlation_id | string | Diagnostic correlation, never a deduplication key |
data | object | Current subscription summary; fields below |
Validate fields against the current event schema. Open objects may ignore additive fields within a supported major version. Objects with additionalProperties: false must reject or isolate unknown fields. Reject or isolate unsupported major versions rather than parsing them as an older format.
Required subscription data fields
All 19 subscription events share this summary. Do not send or handle only {id, status}. Field combinations must match the event and current state.
| Field | Type | Meaning |
|---|---|---|
id | string | Subscription ID; matches top-level resource_id |
organization_id | string | Purchasing customer Organization; matches tenant_id |
party_id | string | Commercial customer record ID, not a user or Membership ID |
product_code | string | Approved product code |
plan_code | string | Current plan; remains current during a scheduled change |
plan_version | integer ≥ 1 | Immutable plan-definition version, not a subscription version |
status | string | Current commercial state; must match the event table |
current_period_start | RFC3339 string | Current period start |
current_period_end | RFC3339 string | Current period end; later than start |
status_effective_at | RFC3339 string | When the current status took effect |
operation_id | string | Associated commercial asynchronous operation ID, not payment proof |
reason_code | string | Change reason; values and meaning follow the issued contract |
resource_version | integer ≥ 1 | Monotonically increasing version of this subscription |
created_at | RFC3339 string | Subscription creation time |
updated_at | RFC3339 string | Latest summary update |
Integration scope and state-specific fields
These fields are optional in the common summary. Follow the actual event and schema, and preserve missing fields rather than converting them to null.
Third-party delivery must bind an application and environment. Reject missing bindings instead of substituting a customer organization or application slug.
| Field | Type | Purpose |
|---|---|---|
open_platform_application_id / environment | string / sandbox or production | Validate the third-party Application/environment together; reject other scopes |
application_slug / brand_profile_code | string | Display identifiers; never replace Application ID for authorization |
product_tenant_id | string | Customer tenant in the product; never replaces Organization |
order_id | string | Original commercial order; query payment outcomes separately |
billing_mode | free / paid | Commercial billing mode; free activation creates no payment evidence |
upgrade_from_subscription_id | string | Original free subscription for a paid upgrade; reconcile each subscription version independently |
price_version_ref | string | Immutable price reference; consumers cannot override amounts |
trial_ending_at / trial_end | RFC3339 string | Trial reminder and trial end |
renewal_window_start / grace_deadline | RFC3339 string | Renewal window opening and grace deadline |
pause_end / resume_status | RFC3339 string / state string | Pause end and resume state; follow actual values |
cancel_at / cancel_at_period_end | RFC3339 string / boolean | Cancellation effect time and period-end flag |
pending_plan_code / pending_plan_version / pending_plan_effective_at | string / integer ≥ 1 / RFC3339 string | Scheduled plan and effect time, not currently effective entitlements |
ended_at | RFC3339 string | End time matching cancellation, expiry, or termination |
Subscription summaries do not provide amounts, currency, old_plan, new_plan, Role or Entitlement. Query payment details and member access through their separately authorized APIs.
Complete subscription event table
Event names and data.status are not always one-to-one: payment failure can enter several states, and a payment-method update does not change state. This is the complete v1 set of 20 subscription events. Related fields explain the scenario; they do not replace schema required-field definitions.
| Complete event name | Trigger | Allowed data.status | Handling |
|---|---|---|---|
oem.subscription.created.v1 | Commercial subscription created | trialing / pending_payment / active | Read actual state; creation does not prove payment |
oem.subscription.updated.v1 | Subscription record revised, for example when a cancellation or restoration request is accepted | active / trialing / trial_ending / renewal_pending / plan_change_pending / pause_pending / paused / cancellation_pending / past_due / grace_period / suspended | Preserve the revision sequence and actual current state; await confirmation rather than treating the request as completed |
oem.subscription.trial_started.v1 | Trial begins | trialing | Read period and trial_end; do not extend locally |
oem.subscription.trial_ending.v1 | Trial-ending reminder stage begins | trial_ending | Read trial_ending_at and trial_end; prompt conversion |
oem.subscription.activated.v1 | Commercial subscription activated | active | Update the subscription record; check member access separately; complete request |
oem.subscription.renewal_upcoming.v1 | Renewal window opens | renewal_pending | Read renewal_window_start; reminder is not renewal success |
oem.subscription.renewed.v1 | Renewal completes | active | Apply new period boundaries; never add a month/year locally |
oem.subscription.payment_failed.v1 | Subscription payment fails | payment_failed / past_due / grace_period | Read actual state and grace deadline; await recovery or expiry |
oem.subscription.past_due.v1 | Subscription enters overdue/grace handling | past_due / grace_period | Read grace_deadline; never infer a fixed grace duration |
oem.subscription.payment_method_updated.v1 | Payment method updated | Current subscription state unchanged | Update related messaging; not payment or renewal success |
oem.subscription.pause_scheduled.v1 | Pause scheduled | pause_pending | Distinguish scheduling from effect; never infer pause time locally |
oem.subscription.paused.v1 | Pause effective | paused | Use pause_end / resume_status and query current access |
oem.subscription.resumed.v1 | Resume operation effective | active / trialing / trial_ending / renewal_pending / plan_change_pending / cancellation_pending / paused | Read actual resumed state; never force active |
oem.subscription.cancellation_scheduled.v1 | Cancellation scheduled | cancellation_pending | Read cancel_at / cancel_at_period_end; complete scenario |
oem.subscription.cancelled.v1 | Cancellation effective | cancelled | Record ended_at, restrict and reconcile access; do not infer refund |
oem.subscription.plan_change_scheduled.v1 | Plan change scheduled | plan_change_pending | Read pending_plan_*; do not enable new entitlements early |
oem.subscription.plan_changed.v1 | Plan change effective | active / trialing / trial_ending | Current plan_code / plan_version updated; complete scenario |
oem.subscription.suspended.v1 | Commercial subscription restricted | suspended | Restrict access; use approved recovery |
oem.subscription.expired.v1 | Period/grace ends and subscription expires | expired | Read ended_at, guide resubscription; complete scenario |
oem.subscription.terminated.v1 | Commercial subscription terminated | terminated | Stop access immediately; retain history and audit |
Event families
| Family | Representative events |
|---|---|
| Identity and access | identity.registration.completed.v1, oem.product.activated.v1, oem.access_context.changed.v1 |
| Subscription | See the complete names and state mappings for all 20 events, including record revisions, payment-method updates, pause, cancellation, plan changes, and expiry |
| Plan changes | oem.subscription.plan_changed.v1 |
| Payment results | payment.order.created.v1, payment.intent.created.v1, payment.requires_action.v1, payment.pending.v1, payment.succeeded.v1, payment.failed.v1, payment.cancelled.v1, payment.unknown.v1 |
| Refund results | payment.refund.pending.v1, payment.refund.unknown.v1, payment.refund.succeeded.v1, payment.refund.failed.v1 |
| Billing state | billing.statement.published.v1 |
| Support | oem.support.request_received.v1, reply_created, status_changed |
Only events listed in the current API access grant are delivered. Do not assume similar names or unpublished events are available.
Consumer requirements
- Deduplicate with
event_id. - Apply state using monotonic
resource_versionvalues. - Retain
correlation_idfor cross-system diagnostics. - Reconcile version gaps through an authorized status API.
- Keep secrets, tokens, and unnecessary business data out of logs.
Effective access changes
oem.access_context.changed.v1 means that a subject's effective access context for an Organization and Product is stale. It is not a Role, Entitlement, or Capability snapshot.
{
"event_id": "evt_opaque",
"event_type": "oem.access_context.changed.v1",
"schema_version": "1",
"producer": "opaque",
"occurred_at": "2026-09-17T03:00:00Z",
"tenant_id": "org_opaque",
"resource_id": "membership_opaque",
"resource_version": 42,
"correlation_id": "req_opaque",
"data": {
"subject_type": "membership",
"subject_id": "membership_opaque",
"organization_id": "org_opaque",
"open_platform_application_id": "app_opaque",
"environment": "sandbox",
"product_code": "relaydesk",
"access_revision": 42
}
}After receiving an access-change event:
- Validate
produceragainst the current schema. Sample placeholders cannot determine actual behavior. - Check that
tenant_id/organization_ididentifies the purchasing customer. Matchopen_platform_application_idandenvironmentexactly against server configuration; organizations or slugs cannot replace them. - Confirm
resource_versionequalsdata.access_revision, verify the signature and deduplicate byevent_id. - Use the current application service identity with
openplatform.api.invoketo callPOST /open-platform/v1/applications/{id}/events/{event_id}/access-snapshotwith{}. The original event selects exactly one customer and Membership. Read currentroles,entitlements,capabilitiesandaccess_revision; current-user context cannot replace the target member. See Product access snapshot for requests and failure handling. - Check the API-defined Entitlement for paid tiers rather than a Role named
VIP. Keep access restricted if the version is uncertain or the query fails.
Member snapshots require a boolean product_access_allowed:
| Result | Action |
|---|---|
true with valid identity, Membership and ProductAccess | Apply current roles, entitlements and capabilities |
false | Clear local effective permissions and restrict access |
| Missing or non-boolean | Treat as an invalid response and keep access restricted |
Organization purchase, role names and active Membership do not establish member assignment. Upgrade receivers and clear old permission records before adopting this version, so older receivers cannot ignore the field and continue granting access.
Product access activated
oem.product.activated.v1 only says that ProductAccess for an Organization entered trial or active. It never enables a member by itself.
{
"event_id": "evt_product_access_opaque",
"event_type": "oem.product.activated.v1",
"schema_version": "1",
"producer": "opaque",
"occurred_at": "2026-09-17T03:00:00Z",
"tenant_id": "org_opaque",
"resource_id": "product_access_opaque",
"resource_version": 3,
"correlation_id": "req_opaque",
"data": {
"organization_id": "org_opaque",
"product_access_id": "product_access_opaque",
"product_code": "relaydesk",
"product_tenant_id": "tenant_opaque",
"open_platform_application_id": "app_opaque",
"environment": "sandbox",
"status": "active",
"version": 3
}
}Check Application, environment, Organization, ProductAccess ID and version. Deduplicate by event_id and use versions to prevent stale local updates. Confirm member access separately through oem.access_context.changed.v1 and an authorized query.
Payment and refund events currently use USD. payment.succeeded.v1 confirms payment; payment.refund.succeeded.v1 confirms a refund.
For pending, requires_action, unknown or failed states, wait for a later Webhook or server query. Do not activate subscriptions or access before confirmation.
The snapshot API is not yet open to standard applications. Review Product access snapshot and contact support to confirm customer-scoped read access before integration.
User and event correlation keys
Subscriptions belong to customer spaces; renewal has no current-login prerequisite. Membership subjects match the user-context membership_id. Public aliases do not merge spaces or subscriptions. See Applications, users and events.