Vertex e-Invoicing Webhook

This section explains how you can use the provided Webhook.

Vertex e-Invoicing includes the ability to send events via Webhook.

The following steps summarize the process of creating and integrating the webhook:

  1. Create the webhook in the Webhook Connection UI.
  2. Review the received data structure.
  3. Review the headers.
  4. Review signature verification.
  5. Review the receiving Webhook.

1. Create the webhook in the Webhook Connection UI

First, you need to create a connection in Vertex e-Invoicing. Open the UI and go to the Webhook Connection UI.

Webhook Connection UI

Complete the required fields:

FieldDescription
Target URLThe endpoint to receive webhook events.
Secret KeyUsed for HMAC SHA-256 signature verification.
Events Select the All Events checkbox or select individual events.
ContentSelect the Include Metadata checkbox to include metadata.

2. Review the received data structure

Vertex e-Invoicing sends data in the following fields:

FieldDescription
DocumentId (GUID)The GUID of the document you requested to view the status of.
TenantId (GUID)The GUID of the Tenant.
DocumentNumberThe logical invoice number.
IssueDateThe issue date.
StatusThe document workflow status. See Note 1 below.
TransmissionDirectionIndicates the direction of invoice transmission.
TransmissionDateTimeThe timestamp at which the invoice was transmitted to Vertex e-Invoicing.
EndpointsAn object providing structured information about the routing information for the document.
ErrorDetailAn object providing structured details about any errors encountered in document processing.

Notes

  1. The following are the possible statuses for the Status field:
StatusDescription
PendingThe initial state of the document while it is being pre-processed. While in this status, the document is not yet visible in the e-Invoicing dashboard. This is a transient state. Documents move from this status to either In Progress when they are successfully validated or Processing Issue in the case of an error.
In ProgressAfter initial validation, a document is visible in the e-Invoicing dashboard, and delivery is in progress through the network to the tax authority and the final recipient. This is a transient state. Documents move from this status to either Completed or Error.
CompletedThe business process of the document is complete and all deliveries are final.
Processing IssueThe document shows this status when an error occurs in the early stages of ingestion, for example, the input document is not correctly formatted.
ErrorThe document shows this status once it has made it through early validation but has a business error, for example, it was rejected by the tax authority. This category of error can generally be resolved by the user by correcting the issue indicated.

3. Review the Headers

The following Headers are available and are sent alongside the webhook data:

HeaderPurpose
X-SignatureProvides integrity and authenticity (using HMAC SHA-256).
X-Event-TimestampProvides ordering and a replay protection window (using RFC1123).
Idempotency-KeyEnsures the same logical event is only stored once per document and facilitates status transition.

4. Review signature verification

What is signed?

The signature is calculated based on the following:

  • Raw request body bytes. This means the JSON must be an exact match in content and formatting.
  • Location: Checks that the target webhook URL is correct.
  • Idempotency-Key header value (GUID string).
  • X-Event-Timestamp header value (RFC1123 string).

What does the Receiver verify?

The following steps summarize how the receiving webhook verifies the signature:

  1. Capture raw body bytes before reading or altering.
  2. Read the required headers.
  3. Look up the secret key securely (for example KeyVault or the environment secret).
  4. Rebuild the byte sequence (body + Location + IdempotencyKey + EventInstant).
  5. Compute HMAC SHA-256.
  6. Encode Base64Url.
  7. Constant-time comparison with incoming X-Signature value.

Psuedocode

// rawBody: byte[] original request body
var memory = new MemoryStream();
memory.Write(rawBody, 0, rawBody.Length);
using (var writer = new StreamWriter(memory, leaveOpen: true))
{
    writer.Write(options.Location.OriginalString);
    writer.Write(idempotencyKeyString);
    writer.Write(eventInstantString);
}
memory.Position = 0;
var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
var signature = WebEncoders.Base64UrlEncode(hmac.ComputeHash(memory));

Why include these fields?

The following fields are included for the following reasons:

  • Raw body: Ensures payload not tampered.
  • Location: Binds signature to intended destination (mitigates redirected replay).
  • Idempotency-Key: Prevents substitution attacks across events.
  • Event Timestamp: Can enable freshness checks (reject if too old / far in future).

5. Receiving Webhook

For the receiving webhook, you can use a POST to webhook-consumer where the body contains the required fields.

If an event is accepted, the204 No Content response is generated.

The following example shows how you might receive a webhook:

curl -X POST https://{webhook_url}:{port}/{webhook_handler}/ \
  -H "Content-Type: application/json" \
  -H "X-Signature: <base64UrlSignature>" \
  -H "X-Event-Timestamp: Tue, 22 Jul 2025 14:51:40 GMT" \
  -H "Idempotency-Key: 5f3c0f1d-5d1a-4d9c-9c5d-2a1fd7f5d123" \
  -d '{"documentId":"...","tenantId":"...","status":"Pending"}'

Security Considerations

  • Integrity & authenticity: Verify X-Signature using the shared secret before trusting the payload.
  • Replay mitigation: Reject events whose X-Event-Timestamp is outside an allowed time window (for example more 5 to 10 minutes old) and rely on the Idempotency-Key to ignore duplicates.
  • Destination binding: Including the configured Location URI in the signature input prevents reuse of a valid body and headers against a different endpoint.
  • Secret hygiene: Use a random 32+ byte secret, rotate periodically, never log it.
  • Transport security: Always require HTTPS; disable plain HTTP externally.
  • Least logging: Log identifiers (TenantId, DocumentId, Idempotency-Key) but avoid logging full payloads if they might contain sensitive business data.