***
id: e82f548a-f56c-4e0b-ab8d-a981119597a8
title: pay
slug: /reference/pay
description: Enable secure payment processing during voice calls.
max-toc-depth: 3
----------------
[supported-languages-voice]: /docs/platform/voice/tts
[currency-code]: https://en.wikipedia.org/wiki/ISO_4217
Enable secure payment processing during voice calls. When implemented in your voice application, it manages the entire payment flow, including data collection, validation, and processing, through your configured payment gateway.
## **Transaction Types**
The `pay` method supports two primary transaction types: `charges` and `tokenization`.
### Charges
When you need to process a payment right away, use a charge transaction.
This collects the payment details and processes the transaction in real-time.
```yaml
version: 1.0.0
sections:
main:
- pay:
charge_amount: 25.00
payment_connector_url: "https://example.com/process"
```
```json
{
"version": "1.0.0",
"sections": {
"main": [
{
"pay": {
"charge_amount": 25.0,
"payment_connector_url": "https://example.com/process"
}
}
]
}
}
```
Setting any positive value for `charge_amount` initiates a charge transaction.
### Tokenization
Tokenization allows you to securely store payment information for future use. Instead of processing a payment immediately, it generates a secure token that represents the payment method.
To initiate a tokenization transaction, either pass `charge_amount` as `0` or omit the `charge_amount` attribute entirely.
The token is provided and stored by your payment processor and can be used for future transactions without requiring customers
to re-enter their payment details. Note that this behavior may vary depending on the payment processor you are using.
```yaml
version: 1.0.0
sections:
main:
- pay:
charge_amount: 0
payment_connector_url: "https://example.com/process"
```
```json
{
"version": "1.0.0",
"sections": {
"main": [
{
"pay": {
"charge_amount": 0,
"payment_connector_url": "https://example.com/process"
}
}
]
}
}
```
## **Properties**
An object that accepts the following properties.
The URL to make `POST` requests with all the gathered payment details. This URL processes the final payment transaction and returns the results in the response. See [`payment_connector_url` details](#payment_connector_url) below.
The amount to charge against payment method passed in the request. `Float` value with no currency prefix passed as string.
Uses the [ISO 4217 currency code][currency-code] of the charge amount.
Custom description of the payment provided in the request.
The method of how to collect the payment details. Currently only `dtmf` mode is supported.
Language to use for prompts being played to the caller by the `pay` method. Supported languages are listed in the [Voice and Languages][supported-languages-voice] page.
Number of times the `pay` method will retry to collect payment details.
The minimum length of the postal code the user must enter.
Array of parameter objects to pass to your payment processor.
Enables you to pass custom parameters or include additional payment details not covered by the standard `pay` attributes.
The identifier for your custom parameter. This will be the key in the `parameters` object.
The value associated with the parameter. This will be the value in the `parameters` object.
Indicates the payment method which is going to be used in this payment request. Currently only `credit-card` is supported.
Takes true, false or real postcode (if it's known beforehand) to let pay method know whether to prompt for postal code.
Array of prompt objects for customizing the audio prompts played during different stages of the payment process.
If no custom prompts are provided, default prompts will be used.
If custom prompts are provided but certain payment steps are omitted, the system will fall back to the default prompts for those steps.
The payment step this prompt is for. Possible values:
* `payment-card-number` - Collect the payment card number. Default: *"Please enter your credit card number"*
* `expiration-date` - Collect the expiration date. Default: *"Please enter your credit card's expiration date. 2 digits for the month and 2 digits for the year"*
* `security-code` - Collect the security code. Default: *"Please enter your credit card's security code. It's the 3 digits located on the back of your card"*
* `postal-code` - Collect the postal code. Default: *"Please enter your billing postal code"*
* `payment-processing` - Played during payment processing. Default: *"Payment processing. Please wait"*
* `payment-completed` - Played when payment succeeds. Default: *"Payment completed. Thank you"*
* `payment-failed` - Played when payment fails. Default: *"Payment failed"*
* `payment-canceled` - Played when payment is cancelled. Default: *"Payment canceled"*
Array of action objects to execute for this prompt. Each action can either play an audio file or speak a phrase using text-to-speech.
The action to perform. Allowed values: `Say` (text-to-speech), `Play` (play an audio file).
When `type` is `Say`, the text to be spoken. When `type` is `Play`, the URL to the audio file.
Which payment attempt(s) this prompt applies to. The value increments when a payment fails. Use a single number (e.g., `"1"`) or space-separated numbers (e.g., `"2 3"`) to target specific attempts.
Space-separated list of card types this prompt applies to.
Allowed values: `visa`, `mastercard`, `amex`, `maestro`, `discover`, `optima`, `jcb`, `diners-club`.
Space-separated list of error types this prompt applies to. Possible values:
* `timeout` - User input timeout
* `invalid-card-number` - Failed card validation
* `invalid-card-type` - Unsupported card type
* `invalid-date` - Invalid expiration date
* `invalid-security-code` - Invalid CVV format
* `invalid-postal-code` - Invalid postal code format
* `session-in-progress` - Concurrent session attempt
* `invalid-bank-routing-number` - Invalid bank routing number
* `invalid-bank-account-number` - Invalid bank account number
* `input-matching-failed` - Input matching failed
* `card-declined` - Payment declined
Takes true or false to let pay method know whether to prompt for security code.
The URL to send requests for each status change during the payment process. See the [status\_url request body](#status_url-request-body) section for more details.
Limit in seconds that pay method waits for the caller to press another digit before moving on to validate the digits captured.
Whether the payment is a one off payment or re-occurring. Allowed values: `one-time`, `reusable`.
List of payment cards allowed to use in the requested payment process, separated by a space.
Allowed values: `visa`, `mastercard`, `amex`, `maestro`, `discover`, `jcb`, `diners-club`.
Text-to-speech voice to use. Supported voices are listed in the [Voice and Languages][supported-languages-voice] page.
## `status_url` request body
The `status_url` parameter is used to send requests for each status change during the payment process.
The type of event that is being reported. Will always be `calling.call.pay`.
The channel that the event is being reported from.
The timestamp of the event in the format of unix timestamp.
The project ID the event is being reported from.
The Space ID the event is being reported from.
An object containing the parameters of the event.
The URL to send requests to for each status change during the payment process.
The method to use for the requests to the `status_url`.
The status of the payment process.
The error type of the payment process.
The payment method of the payment process.
The payment card number of the payment process.
The payment card type of the payment process.
The security code of the payment process.
The expiration date of the payment process.
The payment card postal code of the payment process.
The control ID of the payment process.
The call ID of the payment process.
The node ID of the payment process.
#### Request format
Below is an example of the request body that will be sent to the `status_url`.
```json
{
"event_type": "calling.call.pay",
"event_channel": "swml:XXXX-XXXX-XXXX-XXXX-XXXX",
"timestamp": 1743707517.12267,
"project_id": "XXXX-XXXX-XXXX-XXXX-XXXX",
"space_id": "XXXX-XXXX-XXXX-XXXX-XXXX",
"params": {
"status_url": "https://example.com/status",
"status_url_method": "POST",
"for": "payment-completed",
"error_type": "",
"payment_method": "credit-card",
"payment_card_number": "************1234",
"payment_card_type": "visa",
"security_code": "***",
"expiration_date": "1225",
"payment_card_postal_code": "23112",
"control_id": "XXXX-XXXX-XXXX-XXXX-XXXX",
"call_id": "XXXX-XXXX-XXXX-XXXX-XXXX",
"node_id": "XXXX-XXXX-XXXX-XXXX-XXXX"
}
}
```
## `payment_connector_url`
SignalWire sends a `POST` request to the `payment_connector_url` once all required payment information has been collected from the caller.
Your endpoint processes the payment and returns the result.
### Request body
Unique identifier for the transaction.
The payment method (e.g., `credit-card`).
The card number collected from the caller.
The card security code.
The card expiry month (e.g., `12`).
The card expiry year (e.g., `99`).
The billing postal code.
The amount to charge.
The [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) currency code.
The token type (`one-time` or `reusable`).
The payment description provided in the `pay` method.
#### Request example
```json
{
"transaction_id": "8c9d14d5-52ae-4e2e-b880-a14e6e1cda7d",
"method": "credit-card",
"cardnumber": "************1234",
"cvv": "***",
"postal_code": "123456",
"description": "Payment description",
"chargeAmount": "10.55",
"token_type": "reusable",
"expiry_month": "12",
"expiry_year": "99",
"currency_code": "usd"
}
```
### Response format
Your endpoint must respond with JSON. The format varies depending on the transaction type.
Return a `200` HTTP status code with:
A unique identifier for the successful transaction.
Must be `null` for successful transactions.
Must be `null` for successful transactions.
```json
{
"charge_id": "ch_123456789",
"error_code": null,
"error_message": null
}
```
Return a `200` HTTP status code with:
A unique identifier for the stored payment method.
Must be `null` for successful transactions.
Must be `null` for successful transactions.
```json
{
"token_id": "tok_123456789",
"error_code": null,
"error_message": null
}
```
Return a non-`200` HTTP status code with:
Must be `null` for failed transactions.
An error code identifying the type of failure.
A human-readable description of the error.
```json
{
"charge_id": null,
"error_code": "insufficient_funds",
"error_message": "Card has insufficient funds"
}
```
Return a non-`200` HTTP status code with:
Must be `null` for failed transactions.
An error code identifying the type of failure.
A human-readable description of the error.
```json
{
"token_id": null,
"error_code": "invalid_card",
"error_message": "Card validation failed"
}
```
Error responses will trigger the `payment-failed` prompt in your SWML application.
## **Variables**
When the payment process completes, the following [variables](/docs/swml/reference/variables) are set in the `vars` scope.
Access them in subsequent SWML instructions using the `${variable}` syntax (e.g., `${pay_result}`).
The overall outcome of the payment process. Possible values:
* `success` - The payment was successful.
* `too-many-failed-attempts` - The caller exceeded the `max_attempts` limit.
* `payment-connector-error` - The payment connector returned an error.
* `caller-interrupted-with-star` - The caller pressed the `*` key to cancel.
* `relay-pay-stop` - The payment was stopped via the `STOP` command.
* `caller-hung-up` - The caller hung up before completing payment.
* `validation-error` - Card details failed validation.
* `internal-error` - An internal system error occurred.
Detailed payment results returned by the payment processor, including card details, tokens, and any error information.
Access nested properties with dot notation (e.g., `${pay_payment_results.payment_token}`).
Token generated by the payment processor. Use this for future transactions when using tokenization (`charge_amount: 0`).
Confirmation code returned by the payment processor for a successful charge.
Redacted card number (e.g., `************1234`).
Type of card used (e.g., `visa`, `mastercard`, `amex`).
Card expiration date (e.g., `1225` for December 2025).
Redacted security code (e.g., `***`).
Postal code entered by the caller.
Error description if the payment failed. Empty on success.
Error code if the payment failed. Empty on success.
Error object from the payment connector. Only present when the connector returns an error.
Connector-specific error code.
Connector-specific error message.
## **Examples**
### Simple payment collection
```yaml
version: 1.0.0
sections:
main:
- pay:
charge_amount: '20.45'
payment_connector_url: "https://example.com/process"
status_url: "https://example.com/status"
```
```json
{
"version": "1.0.0",
"sections": {
"main": [
{
"pay": {
"charge_amount": "20.45",
"payment_connector_url": "https://example.com/process",
"status_url": "https://example.com/status"
}
}
]
}
}
```
### Basic tokenization
```yaml
version: 1.0.0
sections:
main:
- pay:
token_type: "reusable"
charge_amount: '0'
payment_connector_url: "https://example.com/tokenize"
```
```json
{
"version": "1.0.0",
"sections": {
"main": [
{
"pay": {
"token_type": "reusable",
"charge_amount": "0",
"payment_connector_url": "https://example.com/tokenize"
}
}
]
}
}
```
### Retry logic
```yaml
version: 1.0.0
sections:
main:
- pay:
charge_amount: '75.00'
payment_connector_url: "https://example.com/process"
max_attempts: 3
timeout: 10
```
```json
{
"version": "1.0.0",
"sections": {
"main": [
{
"pay": {
"charge_amount": "75.00",
"payment_connector_url": "https://example.com/process",
"max_attempts": 3,
"timeout": 10
}
}
]
}
}
```
### Custom parameters
```yaml
version: 1.0.0
sections:
main:
- pay:
charge_amount: "10.00"
payment_connector_url: "https://example.com/process"
parameters:
- name: "my_custom_parameter_1"
value: "my_custom_value_1"
```
```json
{
"version": "1.0.0",
"sections": {
"main": [
{
"pay": {
"charge_amount": "10.00",
"payment_connector_url": "https://example.com/process",
"parameters": [
{
"name": "my_custom_parameter_1",
"value": "my_custom_value_1"
}
]
}
}
]
}
}
```
### International payment with custom prompts
```yaml
version: 1.0.0
sections:
main:
- pay:
charge_amount: '100.00'
payment_connector_url: "https://example.com/process"
currency: "pln"
language: "pl-PL"
description: "Polish zloty transaction"
prompts:
- for: "payment-card-number"
actions:
- type: "Say"
phrase: "Witamy w telefonicznym systemie płatności"
- type: "Say"
phrase: "Proszę wprowadzić numer karty płatniczej"
- for: "payment-card-number"
error_type: "invalid-card-number timeout invalid-card-type"
actions:
- type: "Say"
phrase: "Wprowadziłeś błędny numer karty płatniczej. Proszę spróbować ponownie"
- for: "payment-completed"
actions:
- type: "Say"
phrase: "Płatność zakończona powodzeniem"
```
```json
{
"version": "1.0.0",
"sections": {
"main": [
{
"pay": {
"charge_amount": "100.00",
"payment_connector_url": "https://example.com/process",
"currency": "pln",
"language": "pl-PL",
"description": "Polish zloty transaction",
"prompts": [
{
"for": "payment-card-number",
"actions": [
{
"type": "Say",
"phrase": "Witamy w telefonicznym systemie p\u0142atno\u015bci"
},
{
"type": "Say",
"phrase": "Prosz\u0119 wprowadzi\u0107 numer karty p\u0142atniczej"
}
]
},
{
"for": "payment-card-number",
"error_type": "invalid-card-number timeout invalid-card-type",
"actions": [
{
"type": "Say",
"phrase": "Wprowadzi\u0142e\u015b b\u0142\u0119dny numer karty p\u0142atniczej. Prosz\u0119 spr\u00f3bowa\u0107 ponownie"
}
]
},
{
"for": "payment-completed",
"actions": [
{
"type": "Say",
"phrase": "P\u0142atno\u015b\u0107 zako\u0144czona powodzeniem"
}
]
}
]
}
}
]
}
}
```
### Handling payment results
```yaml
version: 1.0.0
sections:
main:
- answer: {}
- pay:
charge_amount: '25.00'
payment_connector_url: "https://example.com/process"
- cond:
- when: "pay_result == 'success'"
then:
- play:
url: 'say: Payment successful. Your confirmation code is ${pay_payment_results.payment_confirmation_code}.'
- else:
- play:
url: 'say: Payment was not completed. Please try again later.'
```
```json
{
"version": "1.0.0",
"sections": {
"main": [
{ "answer": {} },
{
"pay": {
"charge_amount": "25.00",
"payment_connector_url": "https://example.com/process"
}
},
{
"cond": [
{
"when": "pay_result == 'success'",
"then": [
{
"play": {
"url": "say: Payment successful. Your confirmation code is ${pay_payment_results.payment_confirmation_code}."
}
}
]
},
{
"else": [
{
"play": {
"url": "say: Payment was not completed. Please try again later."
}
}
]
}
]
}
]
}
}
```