Skip to main content

Receive automatic payment event updates using webhooks

This section tells you how to use webhooks to automatically receive updates after payment events. You’ll need a technical team to build a webhooks integration.

A webhook is when GOV.UK Pay sends automatic POST requests to your service after payment events. A payment event is when a payment reaches a milestone in its journey and its state updates, such as when it’s created, paid, or refunded.

You can receive updates when:

  • a payment succeeds
  • a payment fails
  • a payment expires
  • a payment is captured
  • a payment is settled
  • a payment is refunded

After each of these payment events, we’ll send a message in a POST request to your webhook’s secure callback URL. Your service acknowledges receipt of the webhook message.

You can create webhooks in the GOV.UK Pay admin tool.

Set up a callback URL to receive a webhook message

You need to set up an endpoint (callback URL) that can receive webhook messages before creating the webhook.

You must set up your endpoint to receive the POST body from your webhook and respond with a 2xx successful response as soon as possible. To avoid timeouts, return this response before you process the webhook message.

Your callback URL must use HTTPS and present a valid certificate. GOV.UK webhooks support TLS version 1.2.

Your callback URL must have a domain that ends with .gov.uk. This restriction does not apply if you’re using webhooks on a test service.

We can allow other domains if you cannot host your callback URL on a domain that ends with .gov.uk. You can ask us to allow a domain by emailing support at govuk-pay-support@digital.cabinet-office.gov.uk. We’ll only allow domains that exclusively belong to your service or your service’s parent organisation. There may be a delay before we allow your domain to give us time to discuss your request.

Create a webhook

You can create a webhook for your service from the GOV.UK Pay admin tool.

  1. Select your service from the Overview page in the GOV.UK Pay admin tool.

  2. Select Settings.

  3. Select Webhooks.

  4. Select Create a new webhook.

  5. Enter a Callback URL and Description.

  6. Select the payment events that the webhook will send.

  7. Select Create webhook.

To change the callback URL, description, and payment event subscriptions select Manage webhook from the Webhooks page in the GOV.UK Pay admin tool.

Deactivate a webhook

You can deactivate a webhook at any time. Deactivated webhooks do not send events to your callback URL.

To deactivate your webhook:

  1. Open the Webhooks page in the GOV.UK Pay admin tool.

  2. Select Manage webhook.

  3. Select Deactivate webhook.

You can reactivate the webhook at any time.

Receiving webhook messages

Once you’ve created a webhook, GOV.UK Pay sends a webhook message to your callback URL after any of the events you subscribed to.

Your service must send a 2xx successful response as soon as possible. To avoid timeouts, return this response before you process the webhook message.

Warning Your service may receive webhooks messages in an unexpected order. Make sure that your integration does not depend on receiving events in a particular order.

Verifying webhook messages from GOV.UK Pay

Every webhook message from GOV.UK Pay is signed with the Pay-Signature header. The value of this header is a lower-case, hexadecimal hash-based message authentication code (HMAC) of the webhook message body, generated using the SHA-256 hash function. Your webhook signing secret is used as the key.

To view your webhook’s signing secret, select Manage signing secret from the Manage webhook page in the GOV.UK Pay admin tool.

Use your signing secret and the webhook message payload to verify the webhook message:

1. Generate a HMAC of the webhook message body. When generating the HMAC:

  • use the SHA-256 hash function
  • the message is the HTTP request body, which is encoded as UTF-8 with no byte order mark (BOM)
  • the key is your webhooks’s signing secret, encoded as UTF-8 bytes with no BOM
  • output the HMAC as a lower-case hexadecimal string

2. Compare the value of the Pay-Signature header to your generated HMAC. If they do not match, the request has not come from GOV.UK Pay and should be ignored.

Example code:

// JavaScript
// webhookMessageBody - the POST body sent from GOV.UK Pay
// webhookSigningSecret - the signing secret unique to the GOV.UK Pay webhook
// paySignatureHeader - the value of the `Pay-Signature` header received with the POST from GOV.UK Pay

const crypto = require('crypto')

const hmac = crypto.createHmac('sha256', webhookSigningSecret)
  .update(webhookMessageBody)
  .digest('hex')

const valid = hmac === paySignatureHeader

Webhook message example

When your webhook receives a message, it’ll look like this:

{
  "webhook_message_id": "123abc",
  "api_version": 1,
  "created_date": "2019-07-11T10:36:26.988Z",
  "resource_id": "hu20sqlact5260q2nanm0q8u93",
  "resource_type": "payment",
  "event_type": "card_payment_captured",
  "resource": {
    "amount": 5000,
    "description": "Pay your council tax",
    "reference": "12345",
    "language": "en",
    "email": "sherlock.holmes@example.com",
    "state": {
      "status": "submitted",
      "finished": false
    },
    "payment_id": "hu20sqlact5260q2nanm0q8u93",
    "payment_provider": "stripe",
    "created_date": "2021-10-19T10:05:45.454Z",
    "refund_summary": {
      "status": "pending",
      "amount_available": 5000,
      "amount_submitted": 0
    },
    "settlement_summary": {},
    "card_details": {
      "last_digits_card_number": "1234",
      "first_digits_card_number": "123456",
      "cardholder_name": "Sherlock Holmes",
      "expiry_date": "04/24",
      "billing_address": {
        "line1": "221 Baker Street",
        "line2": "Flat b",
        "postcode": "NW1 6XE",
        "city": "London",
        "country": "GB"
      },
      "card_brand": "Visa",
      "card_type": "debit"
    },
    "delayed_capture": false,
    "moto": false,
    "provider_id": "10987654321",
    "return_url": "https://your.service.gov.uk/completed"
  }
}

Attributes you’ll receive in a webhook message

Name Type Meaning
id string The unique identifier of this webhook message.
created_date date (ISO 8601) When the payment event happened and activated the webhook.

This value uses Coordinated Universal Time (UTC) and ISO 8601 format - YYYY-MM-DDThh:mm:ssZ
resource_id string The unique ID that GOV.UK Pay automatically generated for the payment or refund.

When the resource is a payment, resource_id is identical to the payment_id. When the resource is a refund, resource_id is identical to the refund_id.
resource object Contains details of the payment or refund that has activated the webhook.

Attributes in resource are the same as you get when finding a payment in the GOV.UK Pay API.

You can read about the attributes in the resource object on our reference page for getting information about a payment.
resource_type string Indicates whether the resource is a payment or a refund.

resource_type is one of the following:

  • payment
  • refund
  • event_type string The event that activated the webhook. This value will be one of the events you selected when you created the webhook.

    Possible values are:

  • card_payment_succeeded - your payment service provider has authorised the payment
  • card_payment_captured - GOV.UK Pay has taken (‘captured’) the payment from the user’s bank account
  • card_payment_settled - your payment service provider has sent the payment to your bank account.
  • card_payment_refunded - the refund has been sent to the user’s bank account by your payment service provider
  • Retry mechanism

    If your service does not return a 2xx successful response quickly after receiving a webhook message, we’ll try to send the message again. After several attempts, we’ll stop retrying.

    You can see the history of payment events and the message delivery status of each event by selecting Manage webhook in the GOV.UK Pay admin tool. Each line of the Events history table is a single event. Select a payment event to see details of that event, including when it was sent, the body of the webhook message, and any previous delivery attempts.