Back to top

GOV.UK Pay Telephone Payments reporting

Document status

Date Author Comment
12/6/19 David Heath Add optional telephone number to notification payload
12/6/19 David Heath Add notes of decisions made 27/3 (reference, description and date semantics)
5/6/19 David Heath return GOV.UK Pay status from notification endpoint, changes to payment_outcome structure. Idempotency based on provider_id. Add 422 HTTP response code.
24/1/19 David Heath first draft

Purpose and intended audience

this document describes requirements for the API integration between ECKOH and GOV.UK Pay.

Security requirements

The integration with GOV.UK Pay will be via a new endpoint on the existing GOV.UK Pay Public API, and so this document should be read in conjunction with our public API documentation.

In particular the Security section outlines overal security requirements including secure handling of API tokens and PCI DSS compliance.

Overview of architectural components

Component Description
Worldpay payment gateway used to process payments on behalf of NHS BSA
ECKOH Payments IVR and integration with Worldpay
KCOM Call centre IVR
GOV.UK Pay integrated payment processing
NHS BSA delivering the end-user service

For each completed telephone payment transaction ECKOH will send a payment notification to GOV.UK Pay satisfying the following requirements:

  1. Encryption - Transmitted via HTTPS protocol with TLS1.2+ encryption

  2. Timeliness - Transmitted as soon as possible after the event occurs. Ideally in a few seconds or less.

  3. Authenticity - using OAuth 2 bearer token

  4. Retries - If the notification is not acknowledged via a successful 200 response then you must retry notification delivery for up to 72 hours.

  5. Configuration - API tokens are issued via GOV.UK Pay’s selfservice interface, NHSBSA will have access to this interface, and may choose to grant access to ECKOH staff by issuing user accounts.

Technical decisions agreed

  1. GOV.UK Pay does not require an HMAC signature for authentication. OAuth bearer token is sufficient

  2. Retries will be done individually on a per-payment basis

  3. processor_id will be populated with the 23 digit unique_reference_number generated by ECKOH

  4. Worldpay Notifications - Eckoh do not expect to receive notifications from Worldpay; therefore worldpay notifications will be directed to GOV.UK Pay’s endpoint.

  5. auth_code corresponds to the AuthorisationId in the Worldpay auth response

  6. Payloads will be in JSON format with UTF8 character encoding

  7. The reference field is intended as the primary way for end-users and NHS BSA support staff to identify a payment, and will be used for online NHS BSA payments. NHS BSA will set a reference for each payment which will be passed to ECKOH and on to GOV.UK Pay

  8. The description field is intended as a human-readable description of the payment. NHS BSA will set a description for each payment which is passed to ECKOH and on to GOV.UK Pay.

  9. Transaction date - GOV.UK Pay will accept two optional fields with the notification payload:

    • created_date - date/time when the payment was initiated by NHS BSA
    • authorised_date - date/time when the payment was authorised by Worldpay

Points still awaiting confirmation

  1. NHS BSA gateway configuration - we recommend Option 1 (Separate accounts)

Features of GOV.UK Pay not available for telephone payments

  1. Email notifications GOV.UK Pay offers a feature to send email notifications about payments and refunds to users. For telephone payments this will not be possible unless we are provided with an email address for the user. If the NHS BSA wishes to use this feature they would need to pass an email address to ECKOH who would then propagate it to GOV.UK Pay via the email_address field.

NHS BSA Gateway configuration

NHS BSA will process payments via two channels:

  1. online using GOV.UK Pay

  2. by telephone using ECKOH, with payment information reported to GOV.UK Pay

There are several options for structuring accounts.

Option 1 - separate pay services

Channel GOV.UK Pay Service Worldpay merchant code
Online A MC1
Telphone B MC2

Each channel uses a separate pay service and a separate worldpay merchant code.

The advantage of this approach is that it allows separate access control for online transaction data and telephone payment transaction data.

Separate GOV.UK Pay API tokens will be required for each Service.

Transactions would be stored in separate ‘ledgers’ in GOV.UK Pay.

Option 2 - single Pay service

Channel GOV.UK Pay Service Worldpay merchant code
Online A MC1
Telphone A MC1

GOV.UK Pay manages access controls on a per-service basis, so in this scenario users with access to Pay’s selfservice interface would have access to payments via both channels.

Furthermore, API tokens issued here provide read and write access to transactions from both channels.

Assumption

Our assumption is that NHS BSA will use Option 1.

In both scenarios, notifications from Worldpay for BOTH online and telephone payments MUST be directed to GOV.UK Pay as per the instructions.

ECKOH have indicated that they do not need to receive worldpay notifications.

Configuration of GOV.UK Pay gateway accounts

Full details of the configuration process are covered in our documentation:

https://docs.payments.service.gov.uk/switching_to_live/set_up_a_live_worldpay_account/

Example payment flow

  1. End user calls call centre operated by KCOM, and requests a service which requires payment

  2. Call is transferred to ECKOH who receive the payment details and process the payment with Worldpay. Payment will be AUTHORISED and if successful, CAPTURE requested.

  3. ECKOH will make a [Payment Notification] call to GOV.UK Pay, containing transaction details and the status of the payment.

  4. GOV.UK Pay records the transaction details

  5. GOV.UK Pay receives a CAPTURED notification from Worldpay

Refunds

NHS BSA will be able to issue refunds of telephone payments via the GOV.UK Pay selfservice interface or GOV.UK Pay API.

Resource Group

Notifications

Payment notification
POST/v1/payment_notification

When we receive this call we expect the payment to be in one of three statuses, indicated in the payment_outcome:

  1. status success - payment has been authorised successfully and sent for capture

  2. status failed, code P0050 - error processing payment, further details in supplemental

  3. status failed, code P0010 - authorisation declined

Retries will be processed idempotently, keyed by provider_id.

GOV.UK Pay will respond with either a 200 or 201 status code to indicate a successfully received transaction.

  • 201 indicates a transaction not seen before

  • 200 indicates a transaction already seen (provider_id seen before)

On receipt of a response outside of the 200-299 range, the notification MUST be retried.

Retries must continue at a maximum frequency of once per hour for up to 72 hours.

Other response codes possible are:

Code Meaning
200 OK
201 Created
401 Unauthorised - invalid API token
400 Bad request - unparsable, missing required fields, or invalid fields. Details are in the response body json.
422 Unprocessable entity - unparsable, missing required fields, or invalid fields. Details are in the response body json.
5xx Technical error. Request should be retried

Example URI

POST http://publicapi.payments.service.gov.uk//v1/payment_notification
Request
HideShow
Headers
Content-Type: application/json
Body
{
  "amount": 12000,
  "reference": "MRPC12345",
  "description": "New passport application",
  "created_date": "2018-02-21T16:04:25Z",
  "authorised_date": "2018-02-21T16:05:33Z",
  "processor_id": "183f2j8923j8",
  "provider_id": "17498-8412u9-1273891239",
  "auth_code": "666",
  "payment_outcome": {
    "status": "success",
    "code": "P0010",
    "supplemental": {
      "error_code": "ECKOH01234",
      "error_message": "textual message describing error code"
    }
  },
  "card_type": "master-card",
  "name_on_card": "Jane Doe",
  "email_address": "jane_doe@example.com",
  "card_expiry": "02/19",
  "last_four_digits": "1234",
  "first_six_digits": "654321",
  "telephone_number": "+447700900796"
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "amount": {
      "type": "number",
      "description": "the amount in pence"
    },
    "reference": {
      "type": "string",
      "description": "a reference code determined by you, max 255 chars, this may have been provided by the NHS service when they initiated the telephone payment"
    },
    "description": {
      "type": "string",
      "description": "human readable description, this may have been provided by the NHS service when they initiated the telephone payment"
    },
    "created_date": {
      "type": "string",
      "description": "date/time when the payment was initiated by NHS BSA - ISO8601 including timezone"
    },
    "authorised_date": {
      "type": "string",
      "description": "date/time when the payment was authorised by Worldpay - ISO8601 including timezone"
    },
    "processor_id": {
      "type": "string",
      "description": "Unique Eckoh Reference generated by Eckoh"
    },
    "provider_id": {
      "type": "string",
      "description": "WorldPay `orderCode`"
    },
    "auth_code": {
      "type": "string",
      "description": "[Worldpay `AuthorisationId`](http://support.worldpay.com/support/kb/gg/corporate-gateway-guide/content/directintegration/paymentrequests.htm#ExampleAuth)"
    },
    "payment_outcome": {
      "type": "object",
      "properties": {
        "status": {
          "type": "string",
          "enum": [
            "success",
            "failed"
          ]
        },
        "code": {
          "type": "string",
          "enum": [
            "P0010",
            "P0030",
            "P0050"
          ],
          "description": "explanatory error code. For status `failed` a code is required"
        },
        "supplemental": {
          "type": "object",
          "properties": {
            "error_code": {
              "type": "string",
              "description": "a code indicating the error reason. This will be persisted in a GOV.UK Pay custom metadata field named `notification_error_code`."
            },
            "error_message": {
              "type": "string",
              "description": "human readable message describing the error. This will be persisted in a GOV.UK Pay custom metadata field named `notification_error_message`"
            }
          },
          "description": "optional additional details about the error or failure. These fields are stored as [custom metadata](https://docs.payments.service.gov.uk/optional_features/custom_metadata/#adding-custom-metadata) in GOV.UK Pay, so they would be visible in the selfservice interface and reporting"
        }
      },
      "required": [
        "status"
      ]
    },
    "card_type": {
      "type": "string",
      "enum": [
        "master-card",
        "visa",
        "maestro",
        "diners-club",
        "american-express"
      ]
    },
    "name_on_card": {
      "type": "string"
    },
    "email_address": {
      "type": "string"
    },
    "card_expiry": {
      "type": "string",
      "description": "card expiry date as MM/YY"
    },
    "last_four_digits": {
      "type": "string"
    },
    "first_six_digits": {
      "type": "string"
    },
    "telephone_number": {
      "type": "string",
      "description": "caller's phone number (stored as metadata field in GOV.UK Pay)"
    }
  },
  "required": [
    "amount",
    "reference",
    "description",
    "processor_id",
    "provider_id",
    "card_type",
    "name_on_card",
    "card_expiry",
    "last_four_digits",
    "first_six_digits"
  ]
}
Response  200
HideShow
Headers
Content-Type: application/json
Body
{
  "amount": 12000,
  "reference": "MRPC12345",
  "description": "New passport application",
  "created_date": "2018-02-21T16:04:25Z",
  "authorised_date": "2018-02-21T16:05:33Z",
  "processor_id": "183f2j8923j8",
  "provider_id": "17498-8412u9-1273891239",
  "auth_code": "666",
  "payment_outcome": {
    "status": "success",
    "code": "P0010",
    "supplemental": {
      "error_code": "ECKOH01234",
      "error_message": "textual message describing error code"
    }
  },
  "card_type": "master-card",
  "name_on_card": "Jane Doe",
  "email_address": "jane_doe@example.com",
  "card_expiry": "02/19",
  "last_four_digits": "1234",
  "first_six_digits": "654321",
  "telephone_number": "+447700900796",
  "payment_id": "hu20sqlact5260q2nanm0q8u93",
  "state": {
    "status": "success",
    "finished": true,
    "message": "Hello, world!",
    "code": "P0010"
  }
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "amount": {
      "type": "number",
      "description": "the amount in pence"
    },
    "reference": {
      "type": "string",
      "description": "a reference code determined by you, max 255 chars, this may have been provided by the NHS service when they initiated the telephone payment"
    },
    "description": {
      "type": "string",
      "description": "human readable description, this may have been provided by the NHS service when they initiated the telephone payment"
    },
    "created_date": {
      "type": "string",
      "description": "date/time when the payment was initiated by NHS BSA - ISO8601 including timezone"
    },
    "authorised_date": {
      "type": "string",
      "description": "date/time when the payment was authorised by Worldpay - ISO8601 including timezone"
    },
    "processor_id": {
      "type": "string",
      "description": "Unique Eckoh Reference generated by Eckoh"
    },
    "provider_id": {
      "type": "string",
      "description": "WorldPay `orderCode`"
    },
    "auth_code": {
      "type": "string",
      "description": "[Worldpay `AuthorisationId`](http://support.worldpay.com/support/kb/gg/corporate-gateway-guide/content/directintegration/paymentrequests.htm#ExampleAuth)"
    },
    "payment_outcome": {
      "type": "object",
      "properties": {
        "status": {
          "type": "string",
          "enum": [
            "success",
            "failed"
          ]
        },
        "code": {
          "type": "string",
          "enum": [
            "P0010",
            "P0030",
            "P0050"
          ],
          "description": "explanatory error code. For status `failed` a code is required"
        },
        "supplemental": {
          "type": "object",
          "properties": {
            "error_code": {
              "type": "string",
              "description": "a code indicating the error reason. This will be persisted in a GOV.UK Pay custom metadata field named `notification_error_code`."
            },
            "error_message": {
              "type": "string",
              "description": "human readable message describing the error. This will be persisted in a GOV.UK Pay custom metadata field named `notification_error_message`"
            }
          },
          "description": "optional additional details about the error or failure. These fields are stored as [custom metadata](https://docs.payments.service.gov.uk/optional_features/custom_metadata/#adding-custom-metadata) in GOV.UK Pay, so they would be visible in the selfservice interface and reporting"
        }
      },
      "required": [
        "status"
      ]
    },
    "card_type": {
      "type": "string",
      "enum": [
        "master-card",
        "visa",
        "maestro",
        "diners-club",
        "american-express"
      ]
    },
    "name_on_card": {
      "type": "string"
    },
    "email_address": {
      "type": "string"
    },
    "card_expiry": {
      "type": "string",
      "description": "card expiry date as MM/YY"
    },
    "last_four_digits": {
      "type": "string"
    },
    "first_six_digits": {
      "type": "string"
    },
    "telephone_number": {
      "type": "string",
      "description": "caller's phone number (stored as metadata field in GOV.UK Pay)"
    },
    "payment_id": {
      "type": "string"
    },
    "state": {
      "type": "object",
      "properties": {
        "status": {
          "type": "string",
          "description": "the [GOV.UK Pay state](https://docs.payments.service.gov.uk/api_reference/#payment-status-lifecycle) that has been recorded,"
        },
        "finished": {
          "type": "boolean",
          "description": "indicating whether this is a terminal state"
        },
        "message": {
          "type": "string",
          "description": "human readable description of the error condition based on [GOV.UK Pay's status codes `P00xx`](https://docs.payments.service.gov.uk/api_reference/#errors-caused-by-payment-statuses)"
        },
        "code": {
          "type": "string",
          "description": "[GOV.UK Pay error code](https://docs.payments.service.gov.uk/api_reference/#errors-caused-by-payment-statuses) indicating the error condition."
        }
      },
      "required": [
        "status",
        "finished"
      ],
      "description": "https://govukpay-api-browser.cloudapps.digital/#tocspaymentstate"
    }
  },
  "required": [
    "amount",
    "reference",
    "description",
    "processor_id",
    "provider_id",
    "card_type",
    "name_on_card",
    "card_expiry",
    "last_four_digits",
    "first_six_digits",
    "payment_id",
    "state"
  ]
}
Response  201
HideShow
Headers
Content-Type: application/json
Body
{
  "amount": 12000,
  "reference": "MRPC12345",
  "description": "New passport application",
  "created_date": "2018-02-21T16:04:25Z",
  "authorised_date": "2018-02-21T16:05:33Z",
  "processor_id": "183f2j8923j8",
  "provider_id": "17498-8412u9-1273891239",
  "auth_code": "666",
  "payment_outcome": {
    "status": "success",
    "code": "P0010",
    "supplemental": {
      "error_code": "ECKOH01234",
      "error_message": "textual message describing error code"
    }
  },
  "card_type": "master-card",
  "name_on_card": "Jane Doe",
  "email_address": "jane_doe@example.com",
  "card_expiry": "02/19",
  "last_four_digits": "1234",
  "first_six_digits": "654321",
  "telephone_number": "+447700900796",
  "payment_id": "hu20sqlact5260q2nanm0q8u93",
  "state": {
    "status": "success",
    "finished": true,
    "message": "Hello, world!",
    "code": "P0010"
  }
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "amount": {
      "type": "number",
      "description": "the amount in pence"
    },
    "reference": {
      "type": "string",
      "description": "a reference code determined by you, max 255 chars, this may have been provided by the NHS service when they initiated the telephone payment"
    },
    "description": {
      "type": "string",
      "description": "human readable description, this may have been provided by the NHS service when they initiated the telephone payment"
    },
    "created_date": {
      "type": "string",
      "description": "date/time when the payment was initiated by NHS BSA - ISO8601 including timezone"
    },
    "authorised_date": {
      "type": "string",
      "description": "date/time when the payment was authorised by Worldpay - ISO8601 including timezone"
    },
    "processor_id": {
      "type": "string",
      "description": "Unique Eckoh Reference generated by Eckoh"
    },
    "provider_id": {
      "type": "string",
      "description": "WorldPay `orderCode`"
    },
    "auth_code": {
      "type": "string",
      "description": "[Worldpay `AuthorisationId`](http://support.worldpay.com/support/kb/gg/corporate-gateway-guide/content/directintegration/paymentrequests.htm#ExampleAuth)"
    },
    "payment_outcome": {
      "type": "object",
      "properties": {
        "status": {
          "type": "string",
          "enum": [
            "success",
            "failed"
          ]
        },
        "code": {
          "type": "string",
          "enum": [
            "P0010",
            "P0030",
            "P0050"
          ],
          "description": "explanatory error code. For status `failed` a code is required"
        },
        "supplemental": {
          "type": "object",
          "properties": {
            "error_code": {
              "type": "string",
              "description": "a code indicating the error reason. This will be persisted in a GOV.UK Pay custom metadata field named `notification_error_code`."
            },
            "error_message": {
              "type": "string",
              "description": "human readable message describing the error. This will be persisted in a GOV.UK Pay custom metadata field named `notification_error_message`"
            }
          },
          "description": "optional additional details about the error or failure. These fields are stored as [custom metadata](https://docs.payments.service.gov.uk/optional_features/custom_metadata/#adding-custom-metadata) in GOV.UK Pay, so they would be visible in the selfservice interface and reporting"
        }
      },
      "required": [
        "status"
      ]
    },
    "card_type": {
      "type": "string",
      "enum": [
        "master-card",
        "visa",
        "maestro",
        "diners-club",
        "american-express"
      ]
    },
    "name_on_card": {
      "type": "string"
    },
    "email_address": {
      "type": "string"
    },
    "card_expiry": {
      "type": "string",
      "description": "card expiry date as MM/YY"
    },
    "last_four_digits": {
      "type": "string"
    },
    "first_six_digits": {
      "type": "string"
    },
    "telephone_number": {
      "type": "string",
      "description": "caller's phone number (stored as metadata field in GOV.UK Pay)"
    },
    "payment_id": {
      "type": "string"
    },
    "state": {
      "type": "object",
      "properties": {
        "status": {
          "type": "string",
          "description": "the [GOV.UK Pay state](https://docs.payments.service.gov.uk/api_reference/#payment-status-lifecycle) that has been recorded,"
        },
        "finished": {
          "type": "boolean",
          "description": "indicating whether this is a terminal state"
        },
        "message": {
          "type": "string",
          "description": "human readable description of the error condition based on [GOV.UK Pay's status codes `P00xx`](https://docs.payments.service.gov.uk/api_reference/#errors-caused-by-payment-statuses)"
        },
        "code": {
          "type": "string",
          "description": "[GOV.UK Pay error code](https://docs.payments.service.gov.uk/api_reference/#errors-caused-by-payment-statuses) indicating the error condition."
        }
      },
      "required": [
        "status",
        "finished"
      ],
      "description": "https://govukpay-api-browser.cloudapps.digital/#tocspaymentstate"
    }
  },
  "required": [
    "amount",
    "reference",
    "description",
    "processor_id",
    "provider_id",
    "card_type",
    "name_on_card",
    "card_expiry",
    "last_four_digits",
    "first_six_digits",
    "payment_id",
    "state"
  ]
}
Response  401
HideShow
Headers
Content-Type: application/json
Body
+ Body - empty body
Response  400
HideShow
Headers
Content-Type: application/json
Body
{
  "field": "amount",
  "code": "P0102",
  "description": "Invalid attribute value: amount. Must be less than or equal to 10000000"
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "field": {
      "type": "string",
      "description": "may specifiy which field is invalid"
    },
    "code": {
      "type": "string",
      "description": "as per https://docs.payments.service.gov.uk/api_reference/#http-status-codes"
    },
    "description": {
      "type": "string",
      "description": "human readable description of the error"
    }
  },
  "required": [
    "code",
    "description"
  ]
}
Response  422
HideShow
Headers
Content-Type: application/json
Body
{
  "field": "amount",
  "code": "P0102",
  "description": "Invalid attribute value: amount. Must be less than or equal to 10000000"
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "field": {
      "type": "string",
      "description": "may specifiy which field is invalid"
    },
    "code": {
      "type": "string",
      "description": "as per https://docs.payments.service.gov.uk/api_reference/#http-status-codes"
    },
    "description": {
      "type": "string",
      "description": "human readable description of the error"
    }
  },
  "required": [
    "code",
    "description"
  ]
}

Generated by aglio on 12 Jun 2019