diff --git a/docs/runner/fee-options.md b/docs/runner/fee-options.md index 2fec048441..38ea0ed03f 100644 --- a/docs/runner/fee-options.md +++ b/docs/runner/fee-options.md @@ -147,15 +147,31 @@ This will be parsed and sent to GOV.UK Pay as: When viewing this payment in GOV.UK Pay, you can sort by these columns, and will appear as "metadata" in their interface. -## Other - Reference numbers +## Additional payment metadata -Reference numbers are generated with the alphabet "1234567890ABCDEFGHIJKLMNPQRSTUVWXYZ-_". Note that the letter O is omitted. +With fee options, there is the possibility to send through more payment metadata to your webhook outputs. This metadata will tell your webhook about the status of the payment, the payment id, and the payment reference. -You may configure the length of the reference number by setting the environment variable `PAY_REFERENCE_LENGTH`. The default is 10 characters. -Use [Nano ID Collision Calculator](https://zelark.github.io/nano-id-cc/) to determine the right length for your service. -Since each user will "keep" their own reference number for multiple attempts, calculate the speed at unique users per hour. +If you require this metadata, add the `sendAdditionaPayMetadata` option to your webhook output configuration as below: -e.g. If your service expects 100,000 users per annum, you should expect ~274 users per day, and 11 users per hour. -Using nano-id-cc, and a reference length of 10 characters it will take 102 years, or 9 million IDs generated for a 1% chance of collision. +```json5 +{ + name: "outputName", + title: "Webhook output", + type: "webhook", + outputConfiguration: { + url: "https://some-url.com", + sendAdditionalPayMetadata: true, + }, +} +``` + +## Other - Reference numbers +Reference numbers are generated with the alphabet "1234567890ABCDEFGHIJKLMNPQRSTUVWXYZ-\_". Note that the letter O is omitted. +You may configure the length of the reference number by setting the environment variable `PAY_REFERENCE_LENGTH`. The default is 10 characters. +Use [Nano ID Collision Calculator](https://zelark.github.io/nano-id-cc/) to determine the right length for your service. +Since each user will "keep" their own reference number for multiple attempts, calculate the speed at unique users per hour. + +e.g. If your service expects 100,000 users per annum, you should expect ~274 users per day, and 11 users per hour. +Using nano-id-cc, and a reference length of 10 characters it will take 102 years, or 9 million IDs generated for a 1% chance of collision. diff --git a/model/src/data-model/types.ts b/model/src/data-model/types.ts index 44fa373730..68e88654e9 100644 --- a/model/src/data-model/types.ts +++ b/model/src/data-model/types.ts @@ -95,6 +95,7 @@ export type NotifyOutputConfiguration = { export type WebhookOutputConfiguration = { url: string; + sendAdditionalPayMetadata?: boolean; }; export type OutputConfiguration = diff --git a/model/src/schema/schema.ts b/model/src/schema/schema.ts index 5847eeb747..1bf37c0c5c 100644 --- a/model/src/schema/schema.ts +++ b/model/src/schema/schema.ts @@ -213,6 +213,7 @@ const emailSchema = joi.object().keys({ const webhookSchema = joi.object().keys({ url: joi.string(), + sendAdditionalPayMetadata: joi.boolean().optional().default(false), allowRetry: joi.boolean().default(true), }); diff --git a/runner/src/server/plugins/engine/models/SummaryViewModel.ts b/runner/src/server/plugins/engine/models/SummaryViewModel.ts index 1e2cf439c5..6f4d437490 100644 --- a/runner/src/server/plugins/engine/models/SummaryViewModel.ts +++ b/runner/src/server/plugins/engine/models/SummaryViewModel.ts @@ -136,6 +136,8 @@ export class SummaryViewModel { type: "webhook", outputData: { url: output.outputConfiguration.url, + sendAdditionalPayMetadata: + output.outputConfiguration.sendAdditionalPayMetadata, allowRetry: output.outputConfiguration.allowRetry, }, }; diff --git a/runner/src/server/services/queueStatusService.ts b/runner/src/server/services/queueStatusService.ts index f7ed10c01b..33b892b15e 100644 --- a/runner/src/server/services/queueStatusService.ts +++ b/runner/src/server/services/queueStatusService.ts @@ -88,8 +88,13 @@ export class QueueStatusService extends StatusService { const requests = [ ...notify.map((args) => this.notifyService.sendNotification(args)), - ...webhook.map(({ url, formData }) => - this.webhookService.postRequest(url, formData) + ...webhook.map(({ url, sendAdditionalPayMetadata, formData }) => + this.webhookService.postRequest( + url, + formData, + "POST", + sendAdditionalPayMetadata + ) ), ]; diff --git a/runner/src/server/services/statusService.ts b/runner/src/server/services/statusService.ts index ab1b5d2a2c..0b42cff3ed 100644 --- a/runner/src/server/services/statusService.ts +++ b/runner/src/server/services/statusService.ts @@ -1,4 +1,4 @@ -import { HapiRequest, HapiResponseToolkit, HapiServer } from "../types"; +import { HapiRequest, HapiServer } from "../types"; import { CacheService, NotifyService, @@ -151,7 +151,9 @@ export class StatusService { if (firstWebhook) { newReference = await this.webhookService.postRequest( firstWebhook.outputData.url, - formData + { ...formData }, + "POST", + firstWebhook.outputData.sendAdditionalPayMetadata ); await this.cacheService.mergeState(request, { reference: newReference, @@ -167,8 +169,15 @@ export class StatusService { const requests = [ ...notify.map((args) => this.notifyService.sendNotification(args)), - ...webhook.map(({ url, formData }) => - this.webhookService.postRequest(url, formData) + ...webhook.map(({ url, sendAdditionalPayMetadata, formData }) => + this.webhookService.postRequest( + url, + { + ...formData, + }, + "POST", + sendAdditionalPayMetadata + ) ), ]; @@ -261,11 +270,11 @@ export class StatusService { notify.push(args); } if (isWebhookModel(currentValue.outputData)) { - const { url } = currentValue.outputData; - webhook.push({ url, formData }); + const { url, sendAdditionalPayMetadata } = currentValue.outputData; + webhook.push({ url, sendAdditionalPayMetadata, formData }); this.logger.trace( ["StatusService", "outputArgs", "webhookArgs"], - JSON.stringify({ url, formData }) + JSON.stringify({ url, sendAdditionalPayMetadata, formData }) ); } diff --git a/runner/src/server/services/webhookService.ts b/runner/src/server/services/webhookService.ts index 7d32c987a4..a357f2a3ae 100644 --- a/runner/src/server/services/webhookService.ts +++ b/runner/src/server/services/webhookService.ts @@ -20,12 +20,14 @@ export class WebhookService { * @param url - url of the webhook * @param data - object to send to the webhook * @param method - POST or PUT request, defaults to POST + * @param sendAdditionalPayMetadata - whether to include additional metadata in the request * @returns object with the property `reference` webhook if the response returns with a reference number. If the call fails, the reference will be 'UNKNOWN'. */ async postRequest( url: string, data: object, - method: "POST" | "PUT" = "POST" + method: "POST" | "PUT" = "POST", + sendAdditionalPayMetadata: boolean = false ) { this.logger.info( ["WebhookService", "postRequest body"], @@ -33,6 +35,9 @@ export class WebhookService { ); let request = method === "POST" ? post : put; try { + if (!sendAdditionalPayMetadata) { + delete data?.metadata?.pay; + } const { payload } = await request(url, { ...DEFAULT_OPTIONS, payload: JSON.stringify(data),