CloudEvents Envelope
Every event the Business Wallet emits to an integration channel is wrapped in a CloudEvents 1.0 envelope. Using a standard envelope means you can plug any CloudEvents-aware library on the receiver side and get parsing, validation, and observability for free.
Binary mode vs structured mode
CloudEvents 1.0 defines two ways to put an event on the wire. The wallet picks the right one for each transport.
| Mode | Used for | What it looks like |
|---|---|---|
| Binary | HTTP webhooks | Envelope attributes are HTTP headers prefixed with ce-. The HTTP body is only the event's data payload (raw JSON). |
| Structured | Kafka, JMS | The entire envelope (attributes and data) is serialized as a single JSON document and that JSON is the message body. The Content-Type is application/cloudevents+json. |
Both modes carry exactly the same information; only the framing differs. If you switch transports you can keep your event-handling code unchanged and only swap the parser.
"Binary" here doesn't mean the payload has to be binary data — our data is always JSON. It refers to the fact that the event data is placed in the message body in its native byte form, untouched and unwrapped by CloudEvents. The transport (HTTP) sees it as opaque bytes; the CloudEvents metadata travels separately in the headers. This contrasts with structured mode, where the data is re-encoded inside a JSON envelope alongside the metadata.
The naming comes from the CloudEvents HTTP Protocol Binding §3.1 Binary Content Mode and §3.2 Structured Content Mode, which echo the long-standing MIME/HTTP convention of "binary" transfer meaning bytes pass through unmodified.
Binary mode (webhook delivery)
POST /webhooks/credenco HTTP/1.1
Host: receiver.example.com
Content-Type: application/json
ce-specversion: 1.0
ce-type: com.credenco.businesswallet.wallet.created.v1
ce-source: /credenco/wallets
ce-id: 9c7d6b1f-1d17-4c2c-8a5d-2e0f6b1a4f10
ce-time: 2026-05-01T09:42:17.812Z
ce-subject: wallets/3f2504e0-4f89-41d3-9a0c-0305e82c3301
ce-dataschema: https://wallet.acc.credenco.com/api/public/schemas/integration/wallet-created/v1.json
ce-datacontenttype: application/json
ce-walletexternalkey: 3f2504e0-4f89-41d3-9a0c-0305e82c3301
ce-correlationid: 5b1e2dca-6c3a-4b9b-9f0d-7c12da3a1b88
X-Credenco-Signature: t=1746094937,v1=2c1f8e30…
{ "walletExternalKey": "3f2504e0-…", "displayName": "Acme Healthcare B.V.", … }
Structured mode (Kafka or JMS message body)
{
"specversion": "1.0",
"type": "com.credenco.businesswallet.wallet.created.v1",
"source": "/credenco/wallets",
"id": "9c7d6b1f-1d17-4c2c-8a5d-2e0f6b1a4f10",
"time": "2026-05-01T09:42:17.812Z",
"subject": "wallets/3f2504e0-4f89-41d3-9a0c-0305e82c3301",
"dataschema": "https://wallet.acc.credenco.com/api/public/schemas/integration/wallet-created/v1.json",
"datacontenttype": "application/json",
"walletexternalkey": "3f2504e0-4f89-41d3-9a0c-0305e82c3301",
"correlationid": "5b1e2dca-6c3a-4b9b-9f0d-7c12da3a1b88",
"data": {
"walletExternalKey": "3f2504e0-4f89-41d3-9a0c-0305e82c3301",
"displayName": "Acme Healthcare B.V.",
"email": "ops@acme-healthcare.example"
}
}
For Kafka, the JSON above is the value; the key is set to walletExternalKey so downstream partitioning preserves per-wallet ordering. For JMS, the JSON is the message body and the broker's standard JMSMessageID and JMSCorrelationID are populated from id and correlationid respectively.
Envelope reference
All required CloudEvents attributes plus the optional ones we always set.
| Attribute | Required | Type | Description |
|---|---|---|---|
specversion | yes | string | Always 1.0. |
type | yes | string | Reverse-DNS-style event type, ending in .v<major> (e.g. com.credenco.businesswallet.wallet.created.v1). |
source | yes | URI-reference | Identifies the producer. The wallet always emits /credenco/wallets. |
id | yes | string (UUID v4) | Unique per logical event. Stable across retries — use this as your dedupe key. |
time | yes | RFC 3339 timestamp | UTC time the event was produced (not the time it was delivered). |
subject | yes | string | Resource the event is about, in URI-path form (e.g. wallets/{walletExternalKey} or wallets/{walletExternalKey}/identifiers/{identifierExternalKey}). |
dataschema | yes | URI | URL of the JSON Schema that the data payload conforms to. Pin this for forward compatibility. |
datacontenttype | yes | string | Always application/json. |
walletexternalkey | yes (extension) | string (UUID) | Wallet that produced the event. Useful for routing in shared receivers. |
correlationid | yes (extension) | string (UUID) | Correlates the event with the originating user request or job. Identical for all events that share the same originating cause. |
Header naming in binary mode
In binary HTTP mode every attribute is sent as an HTTP header named ce-<attribute> (lower-case). HTTP header names are case-insensitive, but receivers should compare against the lower-case form to match the CloudEvents HTTP binding spec.
Extension attributes
CloudEvents allows producers to define extra attributes outside the spec. The wallet uses two:
walletexternalkey— present on every event. Lets a single receiver service serve multiple wallets without parsing thesubject.correlationid— present on every event. Set to the originating request's correlation ID (or a fresh UUID for system-initiated events) and propagated to all derived events. Use it to stitch traces together across wallet, your receivers, and downstream systems.
Extension attribute names are all lower-case (per CloudEvents spec) — walletexternalkey, not walletExternalKey. They are mirrored verbatim in both binary headers (ce-walletexternalkey) and structured JSON keys.
Versioning policy
The wallet honours the following compatibility contract for every event type:
- Major version is in the type. A type ends in
.v<major>— e.g.wallet.created.v1. There is no separate "version" header. - New optional fields are backward-compatible. They ship under the same major version. Receivers MUST ignore unknown fields.
- Breaking changes mint a new type. A removed field, a renamed field, or a changed field type is shipped as
wallet.created.v2. Thev1type keeps emitting in parallel for at least one major release cycle so you have time to migrate. Customers subscribe explicitly to the new type when ready. - Schema URLs are stable. Once a schema URL has been emitted in a
dataschemaattribute, it never changes meaning. Schemas are versioned in the path (/v1.json,/v2.json).
Pin the dataschema URL alongside your persisted events; that gives you a guaranteed-stable contract regardless of how the wallet evolves.
Where to next
- Event catalog — the events you can subscribe to today.
- Webhook authentication — what
X-Credenco-Signaturelooks like and how to verify it. - CloudEvents 1.0 specification — the upstream standard.