Event Envelope

The VECU Event Relay delivers all events conforming to the CloudEvents 1.0 specification (structured content mode, application/json). Your webhook endpoint receives an HTTP POST with a CloudEvents 1.0 JSON body.

CloudEvents 1.0 Format

{
  "id": "evt_d70e8b93314042f2a6f2eaaf93041c96",
  "source": "vecu.custody-service",
  "type": "custody.vehicle.released",
  "specversion": "1.0",
  "time": "2026-03-15T14:30:00.123Z",
  "datacontenttype": "application/json",
  "data": {
    "_platform": {
      "correlationId": "corr_cust789xyz",
      "traceId": "Root=1-5e3f4b5c-7a8b9c0d1e2f3a4b5c6d7e8f",
      "actor": { "actorId": "vecu.custody-service", "actorType": "service" },
      "metadata": {
        "environment": "sandbox",
        "serviceName": "custody-service",
        "serviceVersion": "0.1.0"
      },
      "sourceRegion": "us-east-1",
      "deduplicationId": "evt_d70e8b93314042f2a6f2eaaf93041c96"
    },
    "vin": "5XXXX00000XEXMPL0",
    "...": "// event-specific fields"
  }
}

CloudEvents Fields

idstringrequired

Event identifier — use this for deduplication. Format is service-defined (typically evt_ + 32 hex chars or a ULID); treat as an opaque string.

sourcestringrequired

Event source in the format vecu.{service} (e.g., vecu.custody-service).

typestringrequired

Event type using the {service}.{resource}.{action} convention (e.g., custody.vehicle.released). This is the value you match against in your event filters.

specversionstringrequired

CloudEvents spec version. Always "1.0".

timestringrequired

Event timestamp in ISO 8601 format.

datacontenttypestringrequired

Always "application/json".

dataobjectrequired

Event-specific payload. See individual event documentation for data schemas. The _platform sub-object documented below appears inside data for every event delivered by vecu-event-relay.

The outer CloudEvents envelope is strict — only the seven fields above are present at the top level. Unrecognized top-level keys do not appear.


data._platform — Platform Metadata

Every event carries a _platform object inside data. The relay service populates it when translating the originating event onto the outbound CloudEvents shape.

The block is built from the seven fields below; any field whose upstream value is null is dropped from the wire rather than included as null. That means _platform is always present but its keys vary per event.

_platform.correlationIdstring

Correlator ID that groups related events across services for the same logical operation (e.g., one authorization flow's lifecycle). May be an empty string when the originating service didn't set a correlator.

_platform.causationIdstring

The id of the event that directly caused this one, when the producing service tracks event causation chains. Absent when the producing service doesn't set it.

_platform.traceIdstring

AWS X-Ray (or compatible) distributed trace identifier in the Root=1-...;Parent=...;Sampled=...;Lineage=... format. Use for cross-service trace correlation.

_platform.actorobject

The entity that triggered the upstream domain action. Object shape is service-defined; observed fields:

_platform.actor.actorIdstring

Stable identifier for the actor. For service actors, the canonical service name (e.g., vecu.custody-service). For user actors, the mapped personIdentityKey or internal user ID.

_platform.actor.actorTypestring

service for system-initiated events; user for events triggered by an end-user action.

_platform.metadataobject

Service-defined metadata about the emitting deployment. Object content is loosely typed (dict[str, Any]); observed fields:

_platform.metadata.environmentstring

Deployment environment: sandbox, non-prod, pre-prod, or production.

_platform.metadata.serviceNamestring

Short service identifier (e.g., custody-service, credential-service).

_platform.metadata.serviceVersionstring

Semantic version of the service deployment that emitted the event.

_platform.sourceRegionstring

AWS region where the event was emitted (us-east-1 or us-west-2). Useful for diagnosing cross-region replication race conditions.

_platform.deduplicationIdstring

The value the SQS/EventBridge dedup layer used to detect duplicate deliveries inside vecu-event-relay. Currently always equal to the envelope id — but consumers should still dedupe on id, not on this field, in case the relationship changes.

Why `_platform` is loosely typed

The relay-side schema for _platform is intentionally open so the upstream platform-events library can add new fields without breaking delivery. As a downstream consumer, treat unknown keys inside _platform as additive — log them, ignore them, but don't fail on them.


Event Naming Convention

All VECU events follow a three-segment, dot-separated naming pattern:

{service}.{resource}.{action}

Rules:

  • All lowercase, dot-separated
  • Exactly three segments: service prefix, resource noun, past-tense action verb
  • The type value (CloudEvents) is case-sensitive

Examples:

Event NameMeaning
credential.identity.issuedAn identity credential was issued
credential.custody.issuedA custody credential was issued
custody.vehicle.releasedA vehicle was released from custody
idv.verification.completedIdentity verification finished successfully
authorizationpool.authorization.createdA pool authorization was created

Deduplication

Use the CloudEvents id field to deduplicate events. The relay service provides at-least-once delivery, so your endpoint may receive the same event more than once in rare cases (network retries, regional failover). Store processed event IDs and skip duplicates. The X-VECU-Event-ID request header contains the same value for convenience.

Schema Versioning

The event data schema follows semantic versioning:

  • MAJOR (e.g., 1.0.0 to 2.0.0): Breaking changes -- required fields removed or types changed
  • MINOR (e.g., 1.0.0 to 1.1.0): New optional fields added (backward compatible)
  • PATCH (e.g., 1.0.0 to 1.0.1): Documentation or description changes

Your webhook handler should tolerate unknown fields to remain compatible with minor version bumps.