Webhook Security

Webhook security is optional

In order to secure and validate your webhook subscriptions, Aeropay provides the option to generate a signing key that can be used to validate the payload sent from Aeropay. Once a signing key has been generated, ensure it is stored in a safe place. The same signingKey will be used for all webhook topics you subscribe to.


Step 1: Generate a Signing Key

Begin by generating a signing key by calling POST /v2/createWebhookSigningKey

Code Example - Request

curl --request POST \
     --url https://api.sandbox-pay.aero.inc/v2/createWebhookSigningKey \
     --header 'accept: application/json' \
     --header 'authorization: Bearer {merchant-token}' \
     --header 'content-type: application/json'

Code Example - Response

{
    "success": true,
    "message": "This is your signingKey used to validate any Webhooks you are subscribed to. Please store this key for future use, as it will not be displayed at any point afterwards.",
    "signingKey": "8a001072f14546d95c861ef77b6bb6899f4c7f0f8c275978e1bd3edcdacf34da"
}

Step 2: Using your signingKey

Once you've created a signingKey and stored the key securely, all webhooks sent to you from Aeropay will include a signature token in the header labeled ap-signature.

Example webhook from Aeropay

{
    "headers": {
        "ap-signature": "c46f292ed0a1b308cf55c3af6de926a8ff8a738cbcf575e9650222955d6477bf"
    },
    "body": {
        "topic": "transaction_completed",
        "payloadVersion": "2.0",
        "data": {
            "uuid": "8bc20976-2e18-4c5c-93b4-20fd853d78a4",
            "id": "231933",
            "status": "completed"
        },
        "date": "2024-04-12 20:42:35"
    }
}

Step 3: Validating the Webhook

Cross-Language JSON Serialization

Different languages serialize JSON differently (key ordering, whitespace, number formatting). We strongly recommend thorough testing of your HMAC implementation with real webhook payloads from sandbox before deploying to production.

How Aeropay Signs Webhooks

Aeropay computes the signature by:

  1. Taking all fields from the webhook body (including topic, data, date, payloadVersion, etc.)
  2. Adding a url field containing your registered webhook callback URL
  3. Serializing to JSON with specific formatting (spaces after colons and commas)
  4. Computing an HMAC-SHA256 hash using your signing key
⚠️

Important: JSON Formatting Requirements

The signature is sensitive to JSON formatting. You must match Aeropay's exact serialization:

  • Spacing: Use ', ' after commas and ': ' after colons (with spaces)
  • All fields: Include every field from the webhook body, not just a subset
  • Add URL: Append your registered webhook callback URL to the payload as a url field

Critical Notes

1. Use Your Registered Webhook URL

The url field must match exactly what you passed when calling POST /v2/webhook to subscribe. This includes:

  • Protocol (http:// vs https://)
  • Trailing slashes
  • Port numbers (if applicable)
  • Subdomain

Example: If you registered https://api.example.com/webhooks/aeropay, use that exact string, not https://api.example.com/webhooks/aeropay/

2. Include All Body Fields

Don't manually select specific fields. Include everything from the webhook body. These should be:

  • topic
  • data
  • date
  • payloadVersion

3. Signing Key Timing

Only webhooks sent after creating the signing key will have valid signatures. If you:

  1. Set up webhook subscriptions
  2. Then create a signing key
  3. Webhooks sent before step 2 won't have valid signatures

You'll need to trigger new events (create transactions, etc.) to test validation.

4. One Key Per Merchant Account

All webhook subscriptions for your merchant account use the same signing key, regardless of:

  • Webhook topic (transaction_completed, user_suspended, etc.)
  • Callback URL
  • Number of subscriptions

Creating a new signing key replaces the old one for all webhooks.

5. Replacing Your Signing Key

If you need to replace your signingKey (due to misplacing it, security concerns, or periodic rotation), call POST /v2/createWebhookSigningKey again. This will:

  • Generate a new signing key
  • Invalidate the old signing key immediately
  • Apply to all future webhooks

There is no grace period where both keys work simultaneously.


Testing Your Implementation

Before going to production:

  • Create a signing key in sandbox
  • Subscribe to a webhook (e.g., transaction_completed)
  • Trigger a test transaction in sandbox
  • Capture the webhook and verify your code produces a matching signature
  • Test with multiple webhook topics to ensure consistency

What’s Next

See common language examples of webhook security implementation: