Skip to main content

The 1st method - Webhook Message Consumer

Overview

  • This is the first way of communication:
    • To register consumer and consume events of application domain services using message gateway
    • Webhook API follows the REST API guidelines
    • The event messages are supported by .NET connectors of platform services using nuget packages

Message Gateway

MessageGateway is platform service encapsulating external communication with message broker to HTTP based technologies, gRPC and Webhooks. It is the only way for external cloud and on-premise services integrated with AVAplace platform.

See more: OIDC/OAuth2 authentication

How webhooks work (short overview)

A webhook is a lightweight HTTP callback used to deliver events in near real-time. You register a consumer webhook URL in the MessageGateway and, when an event occurs, the gateway sends an HTTP POST to that URL with a JSON payload and security headers.

Key expectations for consumers:

  • Verify the JWT in the Authorization header (RS256) before accepting a notification.
  • Process payloads idempotently and use messageId/path variables for deduplication and correlation.
  • Return an HTTP 2xx response to acknowledge the message; non-2xx responses or network errors trigger redelivery with retry/backoff.
  • Prefer separate webhook URLs per stage (DEMO/PROD) and per message type when practical.

images/webhook-notification.png

How to consume webhook message using message gateway

Webhook URL template

  • Consumer webhook URL is provided by developer partner, e.g. https://yourwebhookapi.com/webhook
  • It is recommended to use different URL for each stage (DEMO and PROD)
POST {webhookUrl}/{messageType}/{contractType}/{messageId}
path variabledescription
messageTypename of the message type (routing key)
contractTypename of the class/contract
messageIdunique id of the message

Webhook request headers

Sample of request headers (shortened):

Authorization: Bearer ...
Content-Type: application/json; charset=utf-8
X-Tenant-Id: ...
X-UserClaim-Actort: ...
X-UserClaim-client_id: ...
X-UserClaim-iss: ...
X-UserClaim-locale: ...
X-UserClaim-orgs_codes: ...
X-UserClaim-sub: ...
X-UserClaim-tid: ...
X-UserClaimsExtended: ...
headerdescription
AuthorizationJWT token created by MessageGateway. It identifies the service context of the communication channel and is not tenant-specific.
X-UserClaim-ActortPerson id (Actor) in user context.
X-UserClaim-client_idClient identification in user or service context.
X-UserClaim-issIssuer in user or service context.
X-UserClaim-localeLanguage and region context (RFC 5646 / ISO-639-2) in user or service context.
X-UserClaim-orgs_codesSelected organizations (organization.code) - Organization national number|Country code.
X-UserClaim-subUser identification (SSO unique identifier) in user context.
X-UserClaim-tidTenant identification of selected tenant in user or service context.
X-UserClaimsExtendedExtended claims in user or service context in Base64 encoded JSON format.
X-MessageSecurityCodeThe legacy message security code for the message to keep compatibility with legacy systems.
X-Tenant-IdTenant context identification of the specific message. The value originates in the service that published the message.

Sample of UserClaimsExtended request header (shortened):

[
{ "Key": "nbf", "Value": "..." },
{ "Key": "idp", "Value": "..." },
{ "Key": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "Value": "..." },
{ "Key": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress", "Value": "..." },
{ "Key": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname", "Value": "..." },
{ "Key": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname", "Value": "..." },
{ "Key": "tname", "Value": "..." },
{ "Key": "organizations", "Value": "..." },
{ "Key": "auth_orgs", "Value": "..." },
{ "Key": "auth_orgs_codes", "Value": "..." },
{ "Key": "jti", "Value": "..." },
{ "Key": "iat", "Value": "..." }
]

Webhook request body

Message is sent in HTTP body in JSON format.

Securing incoming webhook requests

A webhook endpoint is publicly reachable over HTTPS, therefore the consumer must validate the incoming request before processing the notification. The current webhook security model combines a signed authentication token representing identification of communication channel with delivery-context headers of incoming http requests.

Authentication token

Each request contains Authorization: Bearer <token>. MessageGateway creates this JWT as the authentication identity and context of the communication channel. The token is intentionally not tied to a specific tenant or to the identity/context of an individual notification message. It can therefore be used for messages with different tenants and different originating message contexts.

The token is signed using the RS256 algorithm. The consumer verifies its signature using public signing keys published through the AVAplace identity-provider configuration:

https://[hostname]/api/asol/idp/.well-known/openid-configuration
https://[hostname]/api/asol/idp/.well-known/jwks

For example, the DEMO signing keys are published at:

https://demo.avaplace.com/api/asol/idp/.well-known/jwks

Signing keys may be rotated. Consumers should therefore use the published OpenID Connect/JWKS configuration instead of embedding a certificate or public key permanently in application code.

A successful JWT validation authenticates the communication channel. Claims contained in this token, such as iss, sub or client_id describe that channel authentication context. They must not be interpreted as the identity or tenant context of every individual message delivered through the channel.

This distinction is important for multi-tenant processing. The notification-channel JWT is non-tenant specific, while the each message can carry own tenant and user context.

Message request headers

Headers such as X-Tenant-Id and X-UserClaim-* describe the tenant-context and user-context of the specific notification message. These values are created by the originating platform service when that service publishes the notification message to the message bus. They are propagated with the message and later included by MessageGateway into the webhook request.

A webhook consumer can therefore need the tenant header to process the notification in the correct tenant context.

  • X-UserClaim-tid - represents the specific tenant-context in user identity (so called runtime-context)
  • X-Tenant-Id - represents the specific tenant-context explicitly assigned to message (so called tenant-context), typically used when user identity is impersonated by service context

Under normal circumstances, both values should be the same.

The message-context headers can also be used by the messaging infrastructure for message filtering/routing before the notification is delivered. On the webhook consumer side they describe the original message context and can be useful for processing, diagnostics, troubleshooting and correlation according to the integration contract.

X-MessageSecurityCode is a legacy proprietary mechanism that was introduced to protect propagated messages against spoofing or modification. It is still present in the current webhook contract and legacy integrations may be required to validate it, but it is no longer recommended for new integrations.

Before the notification payload is accepted for business processing, the consumer should:

  1. Accept the webhook only over HTTPS.
  2. Require an Authorization header using the Bearer scheme.
  3. Cryptographically validate the JWT signature against a currently published identity-provider signing key and require the expected signing algorithm (RS256).
  4. Validate standard JWT validity constraints, especially token lifetime (exp and nbf when present), and validate the expected issuer (iss) and audience (aud) when defined for the integration. Expected values must come from trusted consumer configuration.
  5. Read the message-specific user identity and tenant context from the request headers required by the integration contract.
  6. Validate the request route and payload required by the integration before business processing.
  7. Use messageId to make processing idempotent. A repeated delivery of the same message must not create the same business effect twice.
  8. Return an HTTP 2xx response only after the notification has been accepted according to the consumer's processing strategy.

The exact implementation depends on the consumer technology. Standard JWT/OIDC libraries are recommended because they handle signature verification, key selection by kid, token lifetime validation and signing-key rotation. See the technical webhook integration examples for implementation guidance.

Message acknowledgment and redelivery

Examples - OrderReleased scenario

Webhook URL

POST https://yourwebhookapi.com/webhook/ASOL.PlatformStore.OrderReleased/OrderReleased/c0eb0000-5dfe-0015-8604-08dbd6ef8bf7
path variablevalue
messageTypeASOL.PlatformStore.OrderReleased
contractTypeOrderReleased
messageIdunique for each receive message

Webhook headers

Authorization: Bearer ...
Content-Type: application/json; charset=utf-8
X-Tenant-Id: ASOLEU-DEV-fd9ad6b9-2f29-4c7a-9a3a-c7469e19b1ff
X-UserClaim-Actort: c042e6ad-f293-4e36-8266-574b665792ff
X-UserClaim-client_id: plaza-pass
X-UserClaim-iss: https://demo.avaplace.com/api/asol/idp
X-UserClaim-locale: cs-CZ
X-UserClaim-orgs_codes: 64949541|CZ
X-UserClaim-sub: 6388701d4a20a1c1bc1f0831
X-UserClaim-tid: ASOLEU-DEV-fd9ad6b9-2f29-4c7a-9a3a-c7469e19b1ff
X-UserClaimsExtended: [{"Key":"nbf","Value":"1698409522"},{"Key":"idp","Value":"local"},{"Key":"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name","Value":"petr.tomala@assecosol.com"},{"Key":"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress","Value":"petr.tomala@assecosol.com"},{"Key":"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname","Value":"Petr"},{"Key":"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname","Value":"Tomala"},{"Key":"tname","Value":"ASOLEU-DEV"},{"Key":"organizations","Value":"fff2d400-9838-4513-9c7b-535a03bd8c94"},{"Key":"auth_orgs","Value":"fff2d400-9838-4513-9c7b-535a03bd8c94"},{"Key":"auth_orgs_codes","Value":"64949541|CZ"},{"Key":"jti","Value":"9781FBFE8F78C7F7802F494947860804"},{"Key":"iat","Value":"1698409522"}]

Webhook body

{
"orderId": "b0588700-f3a2-4bde-bbb4-d2022bf7851e",
"productId": "98fa6110-ec8b-45a4-882f-b5a1e89812ca",
"vendorCode": "64949541|CZ"
}

See examples:

Examples - RefreshSourceStatus scenario

Webhook URL

POST https://yourwebhookapi.com/webhook/ASOL.DataService.RefreshSourceStatus/RefreshStatusEvent/01000000-d3ff-1268-1fe0-08df06d5fef7
path variablevalue
messageTypeASOL.DataService.RefreshSourceStatus
contractTypeRefreshStatusEvent
messageIdunique for each receive message

Bearer token

{
"iss": "https://beta.avaplace.com/api/asol/idp",
"exp": 1788286751,
"iat": 1788283151,
"aud": "apiim",
"sub": "plaza-services",
"client_id": "plaza-services",
...
}

Webhook headers

Authorization: Bearer ...
Content-Type: application/json; charset=utf-8
X-Tenant-Id: ASOLEU-DEV-fd9ad6b9-2f29-4c7a-9a3a-c7469e19b1ff
X-UserClaim-client_id: ASOLEU-DataService-AP-
X-UserClaim-tid: ASOLEU-DEV-fd9ad6b9-2f29-4c7a-9a3a-c7469e19b1ff
X-UserClaimsExtended: []

Webhook body

{
"sourceId": "6049f30a-ce57-48e4-a97c-02e3e2edae1f",
"checkConnection": true
}

See examples: