Payments

link iconAPI Reference

Idempotency

The Create a Payment and Tokenise a Payment Method APIs support idempotency for safely retrying requests without accidentally performing the same operation twice. This is useful when an API call is disrupted in transit and you do not receive a response. For example, if a request to Create a Payment does not respond due to a network connection error, you can retry the request with the same idempotency key to guarantee that no more than one charge is created.

To perform an idempotent request, provide an additionalX-Idempotency-Key:<key> to the request.

Requests made with the same idempotency key will return the original result. As an example, if a request has failed due to validation and the request is amended and resubmitted with the same idempotency key value, then our server will return the same validation error as the initial request. A new idempotency key value should be generated for the amended (new) request.

An idempotency key is a unique value generated by the client which the server uses to recognize subsequent retries of the same request. How you create unique keys is up to you, but we suggest using V4 UUIDs, or another random string with enough entropy to avoid collisions. Idempotency keys can be up to 255 characters long.

Idempotency keys are deleted from the system automatically after 24 hours, and a new request is generated if a key is reused after this period.

We recommend setting your client timeout to 30 seconds.

Vault

Using our PCI DSS Level 1 compliant Vault you can securely tokenise payment methods. Then, whenever you're ready to process a payment, you can use a WhenThen token with any of your payment processors using our single unified API. All while minimizing your PCI scope and remaining compliant.

info icon

We recommend you use our Checkout SDK to do this. Or visit Tokenisation for other options

Customers

Use the Vault API to create customers and associate payment methods. This allows you to perform recurring charges, and to track multiple charges, that are associated with the same customer all while using a tokenised payment method.

Tokenising a payment method

1

Create a customer (optional)

API Reference Create Customer.

First we can optionally create a new customer

  curl
  -X POST
  -H "Content-Type: application/json"
  -H "Authorization: Bearer xxxxxxx"
  -d '{
    "query": "mutation createCustomer($data: CustomerInput!){
      createCustomer(data: $data)
    }",
    "variables": {
      "customer": {
        "email": "john@example.com",
        "name": "John Smith",
        "phone": "406-694-3629"
      }
      }
  }'
  https://api.whenthen.com/api/graphql

2

Tokenise Payment Method

API Reference Tokenise Payment Method.

  curl
  -X POST
  -H "Content-Type: application/json"
  -H "Authorization: Bearer xxxxxxx"
  -d '{
    "query": "mutation tokenisePaymentMethod($data: TokenInput!){
      tokenisePaymentMethod(data: $data) {
        id
        token
        createdDate
     }
   }",
    "variables": {
      "paymentMethod": {
          "card": {
            "number":"4000056655665556",
            "expMonth": 8,
            "expYear": 2026,
            "cvc": "342",
            "name": "John Smith",
            "isDefault": true
          }
        },
      "customer": {
          "id": "421dd9b0-0af6-41ee-9fc5-48f42d5ad640"
      }
     }
  }'
  https://api.whenthen.com/api/graphql

Create a Payment

API Reference Create a Payment.

A payment method will be authorised according to the orchestration automation of your payment flow. There are 2 payment methods supported at the moment:

Depending on the choice of the payment method, the payment will be captured immediately (CARD) or intermediate step might be required (APM). After successful completion, we return a status of SUCCEEDED.

If you have created a capture automation for your payment flow, then capture will take place according to your automation. See details on the Capture API below.

1

Authorise a payment method token

  curl
  -X POST
  -H "Content-Type: application/json"
  -H "Authorization: Bearer xxxxxxx"
  -d '{
    "query": "mutation authorizePayment($authorisePayment: AuthorisedPaymentInput!) {
      authorizePayment(authorisePayment: $authorisePayment) {
        id
        status 
      }
   }",
    "variables": {
      "authorisePayment": {
         "orderId": "557512fb-e5f3-45ce-9e60-b9418b92153b",
         "flowId": "2d0fc623-f1ca-4051-b60a-7366ca14783c",
         "amount":4999,
         "currencyCode":"EUR",
         "paymentMethod":{
            "type":"CARD",
            "token":"ZLlVBBXFDQtBnfxT"
         }
      }
    }
  }'
  https://api.whenthen.com/api/graphql

2

Authorise a payment method with raw card data

Note : Passing raw card details to and from your backend means you will need to be PCI compliant according to SAQ D, the most extensive form of certification. We recommend using our vault.

  curl
  -X POST
  -H "Content-Type: application/json"
  -H "Authorization: Bearer xxxxxxx"
  -d '{
    "query": "mutation authorizePayment($authorisePayment: AuthorisedPaymentInput!) {
      authorizePayment(authorisePayment: $authorisePayment) {
        id
        status
      }
   }",
    "variables": {
      "authorisePayment": {
         "orderId": "557512fb-e5f3-45ce-9e60-b9418b92153b",
         "flowId": "2d0fc623-f1ca-4051-b60a-7366ca14783c",
         "intentId": "9106d9e7-87ba-4b39-9e99-599559aede60",
         "amount": 100,
         "currencyCode": "ISO 4217",
         "paymentMethod":{
            "type":"CARD",
            "card":{
               "number":"4000056655665556",
               "expMonth":8,
               "expYear":2026,
               "cvc":"342",
               "name":"John Smith"
            }
         }
      }
    }
  }'
  https://api.whenthen.com/api/graphql

3

Authorise a customer

We will authorise the default payment method for this customer

  curl
  -X POST
  -H "Content-Type: application/json"
  -H "Authorization: Bearer xxxxxxx"
  -d '{
    "query": "mutation authorizePayment($authorisePayment: AuthorisedPaymentInput!) {
      authorizePayment(authorisePayment: $authorisePayment) {
        id
        status
      }
   }",
    "variables": {
      "authorisePayment": {
         "orderId": "557512fb-e5f3-45ce-9e60-b9418b92153b",
         "flowId": "2d0fc623-f1ca-4051-b60a-7366ca14783c",
         "amount":4999,
         "currencyCode":"EUR",
         "customer":{
            "id":"421dd9b0-0af6-41ee-9fc5-48f42d5ad640"
         }
      }
    }
  }'
  https://api.whenthen.com/api/graphql

4

Authorise a customer and payment method id

We will authorise the chosen payment method for this customer

  curl
  -X POST
  -H "Content-Type: application/json"
  -H "Authorization: Bearer xxxxxxx"
  -d '{
    "query": "mutation authorizePayment($authorisePayment: AuthorisedPaymentInput!) {
      authorizePayment(authorisePayment: $authorisePayment) {
        id
        status
      }
   }",
    "variables": {
      "authorisePayment": {
         "orderId": "557512fb-e5f3-45ce-9e60-b9418b92153b",
         "flowId": "2d0fc623-f1ca-4051-b60a-7366ca14783c",
         "amount":4999,
         "currencyCode":"EUR",
         "customer":{
            "id":"421dd9b0-0af6-41ee-9fc5-48f42d5ad640"
         },
         "paymentMethod":{
            "type":"CARD",
            "token":"ZLlVBBXFDQtBnfxT"
         }
      }
    }
  }'
  https://api.whenthen.com/api/graphql

3D Secure

You can indicate to use 3D Secure (3DS) authentication. This requires customers to complete a verification step with their card issuer. A challenge will be presented to customers where they enter a password, code sent to their phone or any others to be identified.

In Europe, the Strong Customer Authentication (SCA) requires the use of 3DS for card payments to comply with new regulations. This is optional in others regions.

A customer's bank may trigger SCA during a payment regardless of whether you have requested 3DS or not. For this reason you should always pass a redirectUrl in the authorisePayment API. 3D Secure options are configured in.

You can use the "3D Secure" action in your payment processing automation to explicitly set 3D Secure on or off based on conditions.

1

Configure 3DS Configuration Options

Open your payment flow in the WhenThen Web Application and check your payment action(s) have 3DS Configuration Options set.

Automation configure 3ds

2

Create a Payment using 3D Secure

As mentioned above, always pass redirectUrl in the API call. If you wish to explicitly trigger 3DS then use the "3D Secure" action in your payment processing automation.

Automation configure 3ds
  curl
  -X POST
  -H "Content-Type: application/json"
  -H "Authorization: Bearer xxxxxxx"
  -d '{
    "query": "mutation authorizePayment($authorisePayment: AuthorisedPaymentInput!) {
      authorizePayment(authorisePayment: $authorisePayment) {
        id
        status
      }
   }",
    "variables": {
      "authorisePayment": {
         "orderId": "557512fb-e5f3-45ce-9e60-b9418b92153b",
         "flowId": "2d0fc623-f1ca-4051-b60a-7366ca14783c",
         "amount": 4999,
         "currencyCode": "EUR",
         "paymentMethod":{
           "type": "CARD",
           "token": "ZLlVBBXFDQtBnfxT"
        },
         "perform3DSecure":{
            "redirectUrl": "http://3dsecure.url.com"
       }
      }
    }
  }'
  https://api.whenthen.com/api/graphql

3

Handle Error Response

We use an error pattern to handle next steps required. When an error is returned with error code error.authorize.requires3DSecure then you must redirect your web application to the url. The customer will be redirected to their bank to confirm the payment. We provide you with the id of the payment to track the payment

{
     "data":{
        "authorizePayment":null
     },
     "errors":[
        {
           "message":"Payment authorization needs 3D Secure completed: https://hooks.stripe.com/redirect/authenticate/src_1KLlIDEzEzSmOSVmTfcufkaR?client_secret=src_client_secret_vvHMa9FFscLwoWNUTyD86XoZ&source_redirect_slug=test_YWNjdF8xSmVubkdFekV6U21PU1ZtLF9MMW93QmQ2ZE5lSlFqcWQ0UjJkYm5JWUhvbEs0RE400100Pl7js44l",
           "extensions":{
              "noTrace":true,
              "code":"error.authorize.requires3DSecure",
              "id":"payments:cc9d00ac-1c85-400f-8ad1-958100ca0e06",
              "url":"https://hooks.stripe.com/redirect/authenticate/src_1KLlIDEzEzSmOSVmTfcufkaR?client_secret=src_client_secret_vvHMa9FFscLwoWNUTyD86XoZ&source_redirect_slug=test_YWNjdF8xSmVubkdFekV6U21PU1ZtLF9MMW93QmQ2ZE5lSlFqcWQ0UjJkYm5JWUhvbEs0RE400100Pl7js44l"
           }
        }
     ]
  }

4

Handle Response

When the customer has completed 3D Secure we will return to the redirectUrl with the following query parameters:

  • id of the payment for future reference
  • 3ds_status - COMPLETED/FAILED
  • decline_code as optional if the payment was declined.

It is recommended you use the id to call the getPayment API and verify the status of the payment. You may also want to notify your backend that 3D Secure process is complete and to continue with any payment logic in your systems.

Don't forget the power of WhenThen as a no-code payment logic platform. You can build automations based on the outcome of a payment.

http://3dsecure.url.com?id=payments:cc9d00ac-1c85-400f-8ad1-958100ca0e06&3ds_status=COMPLETED&decline_code=INVALID_CVC

Capture a Payment

API Reference Capture a Payment.

If you wish to control when a payment is captured then you can configure this in your payment flow by building a capture automation.

If you have created a capture automation for your payment flow, then authorisations will be captured according to your automation. By default authorisations will be captured immediately.

info icon

WhenThen's flexible approach to automation will allow endless possibilities to support any use case or payment logic.

Capture the funds of an existing Payment when its status is AUTHORISED.

You can capture a payment for the original amount, or you can provide an amount less than the original amount. Amounts should be sent in minor units. The currency from the original payment will be used.

If no amount is sent then the original payment amount is captured. If you provide an amount then this value will be captured.

Uncaptured Payments will be cancelled after approximately seven days. This can be different per PSP. You should check the rules with your given PSP.

Currently there are 3 ways to capture using an automation

  • API
  • Webhook
  • Time


API

Capturing a previous authorisation through our API is simple. Call the Capture API using the payment Id. Optionally you can provide an amount to capture, which must be less than or equal to the original amount.

  curl
  -X POST
  -H "Content-Type: application/json"
  -H "Authorization: Bearer xxxxxxx"
  -d '{
     "query": "mutation capturePayment($id: ID!, $amount: Long) {
       capturePayment(id: $id, amount: $amount) {
          id
          status
       }
     }",
     "variables":{
        "id": "cc9d00ac-1c85-400f-8ad1-958100ca0e06",
        "amount": 10000
     }
  }'
  https://api.whenthen.com/api/graphql


Time

Coming Soon - Capture after a period of time has passed

Cancel

API Reference Cancel a Payment.

A Payment can be cancelled when it has a status of AUTHORISED.

When a payment is cancelled, your PSP will not charge you any fees for the payment and payment will be refunded to the customer. This is an example of where using a delayed capture automation could be beneficial to your business.

  curl
  -X POST
  -H "Content-Type: application/json"
  -H "Authorization: Bearer xxxxxxx"
  -d '{
     "query": "mutation cancelPayment($id: ID!, $reason: String) {
       cancelPayment(id: $id, reason: $reason) {
         id
         status
        }
    }",
     "variables":{
        "id":"cc9d00ac-1c85-400f-8ad1-958100ca0e06",
        "reason":"some reason"
     }
  }'
  https://api.whenthen.com/api/graphql

Refund

API Reference Refund a Payment.

A Payment can be refunded when it has a status of SUCCEEDED . A Payment with a status of AUTHORISED should be cancelled.

Partial refunds can be done by providing the amount which must be less than or equal to the original amount. We allow you to add an optional reason for the refund for auditing purposes. Funds will be refunded to the customer's payment method.

  curl
  -X POST
  -H "Content-Type: application/json"
  -H "Authorization: Bearer xxxxxxx"
  -d '{
     "query": "mutation refundPayment($id: ID!, $amount: Long, $reason: String) {
        refundPayment(id: $id, amount: $amount, reason: $reason) {
          id
          status
       }
     }",
     "variables":{
        "id": "cc9d00ac-1c85-400f-8ad1-958100ca0e06",
        "amount": 10000,
        "reason":"some reason"
     }
  }'
  https://api.whenthen.com/api/graphql