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
idstringrequiredEvent identifier — use this for deduplication. Format is service-defined
(typically evt_ + 32 hex chars or a ULID); treat as an opaque string.
sourcestringrequiredEvent source in the format vecu.{service} (e.g., vecu.custody-service).
typestringrequiredEvent type using the {service}.{resource}.{action} convention (e.g.,
custody.vehicle.released). This is the value you match against in your
event filters.
specversionstringrequiredCloudEvents spec version. Always "1.0".
timestringrequiredEvent timestamp in ISO 8601 format.
datacontenttypestringrequiredAlways "application/json".
dataobjectrequiredEvent-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.correlationIdstringCorrelator 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.causationIdstringThe 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.traceIdstringAWS X-Ray (or compatible) distributed trace identifier in the
Root=1-...;Parent=...;Sampled=...;Lineage=... format. Use for
cross-service trace correlation.
_platform.actorobjectThe entity that triggered the upstream domain action. Object shape is service-defined; observed fields:
_platform.actor.actorIdstringStable 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.actorTypestringservice for system-initiated events; user for events triggered by an
end-user action.
_platform.metadataobjectService-defined metadata about the emitting deployment. Object content is
loosely typed (dict[str, Any]); observed fields:
_platform.metadata.environmentstringDeployment environment: sandbox, non-prod, pre-prod, or
production.
_platform.metadata.serviceNamestringShort service identifier (e.g., custody-service, credential-service).
_platform.metadata.serviceVersionstringSemantic version of the service deployment that emitted the event.
_platform.sourceRegionstringAWS region where the event was emitted (us-east-1 or us-west-2). Useful
for diagnosing cross-region replication race conditions.
_platform.deduplicationIdstringThe 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
typevalue (CloudEvents) is case-sensitive
Examples:
| Event Name | Meaning |
|---|---|
credential.identity.issued | An identity credential was issued |
credential.custody.issued | A custody credential was issued |
custody.vehicle.released | A vehicle was released from custody |
idv.verification.completed | Identity verification finished successfully |
authorizationpool.authorization.created | A 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.0to2.0.0): Breaking changes -- required fields removed or types changed - MINOR (e.g.,
1.0.0to1.1.0): New optional fields added (backward compatible) - PATCH (e.g.,
1.0.0to1.0.1): Documentation or description changes
Your webhook handler should tolerate unknown fields to remain compatible with minor version bumps.