Hosted payment pages

A payment created in the default mode (authorisation_mode: web) comes back with a next_url. Redirect the user's browser there, exactly as you would with GOV.UK Pay. The mock hosts the pages the user sees, so a full citizen journey works end to end: your service, the payment pages, and back to your return_url.

Real card entry is replaced with a scenario picker, so nobody has to type fake card details during a demo. The layout, wording and steps follow the GOV.UK Pay payment pages. There is no crown or GOV.UK logo, and every page carries a Demo banner.

The journey

  1. Your service creates the payment with POST /v1/payments, including a return_url (https).
  2. Redirect the user to _links.next_url.href. Alternatively submit a form POST to _links.next_url_post.href with the chargeTokenId field, so the token is not in a URL.
  3. The user sees Enter payment details: a payment summary (description and total amount) and the scenario picker. prefilled_cardholder_details and email are carried through.
  4. If they choose Payment succeeds and select Continue, they see Confirm your payment with the mock card details. Selecting Confirm payment completes the payment.
  5. The user is redirected (303) to your return_url.
  6. Your service finds the outcome with GET /v1/payments/{paymentId}, or receives a webhook. The return_url does not carry the result, as with the real service.

Scenarios

User selectsUser seesPayment ends asEvents recorded
Payment succeeds, then Confirm paymentConfirm your payment, then your return_urlsuccess, or capturable if delayed_capture is truecreated, started, submitted, success (or capturable)
Card is declinedYour payment has been declinedfailed, code P0010created, started, failed
Payment provider errorWe're experiencing technical problemserror, code P0050created, started, error
Cancel payment (on either page)Your payment has been cancelledfailed, code P0030 (cancelled by the user)created (, started), failed

Each error page has a Continue button that sends the user to your return_url. Cancelling through the API (POST .../cancel) is different: it gives status cancelled, code P0040.

Behaviour to know about

  • The pages are public. They need no bearer token, because the user's browser is redirected to them.
  • Once a payment has finished (or is capturable), opening its page again redirects to the return_url.
  • Submitting the first page without choosing shows an error message and changes nothing.
  • An unknown or mistyped link shows a "Page not found" page (404). Payments created with moto_api have no hosted page; they complete through POST /v1/auth.
  • Payment data expires after 7 days, so old links stop working.
  • Not modelled: real card fields, Apple Pay and Google Pay, 3D Secure, billing address entry, the 90 minute expiry, and confirmation emails.

Trying it without a browser

Create a payment, then follow the redirects by hand:

curl -s -X POST https://publicapi.payments.platform-engineering.com/v1/payments \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"amount":2500,"reference":"CAZ-1","description":"Clean air zone charge","return_url":"https://example.com/done"}'
# take _links.next_url.href from the response, then:

curl -s https://publicapi.payments.platform-engineering.com/secure/<token> # the Enter payment details page (HTML) curl -si -X POST https://publicapi.payments.platform-engineering.com/secure/<token> -d scenario=success # 303 to .../confirm curl -s https://publicapi.payments.platform-engineering.com/secure/<token>/confirm # the Confirm your payment page curl -si -X POST https://publicapi.payments.platform-engineering.com/secure/<token>/confirm # 303 to your return_url curl -s https://publicapi.payments.platform-engineering.com/v1/payments/<payment_id> -H "Authorization: Bearer $TOKEN" # state: success

Use scenario=declined, scenario=error or scenario=cancel for the other outcomes.

Routes

RoutePurpose
GET /secure/{token}Enter payment details (the next_url)
POST /secure/{token}Submit the scenario (scenario = success, declined, error or cancel)
GET /secure/{token}/confirmConfirm your payment
POST /secure/{token}/confirmConfirm payment, then redirect to the return_url
POST /secureStart from the next_url_post form (chargeTokenId field)