TABLE OF CONTENTS
Introduction
The purpose of this document is to provide technical details regarding an integration to Flexpay using the scheduled Auto-Retries feature. This feature allows you to send transaction details to FlexPay via individual API calls. FlexPay then takes over the retry process by scheduling and triggering the retry attempts.
Requirements
To benefit from FlexPay’s Enterprise with Scheduler API integration, you will need the following:
- FlexPay Production account
- At least one Company configured in the account (There is a default company) Learn more
- Payment gateways configured for each Company Learn more
- FlexPay Retries configured for each Company Learn more
- Production API keys for each Company Learn more
- Ability to POST a request to the Charge endpoint Learn more
- Ability to POST a request to the Redact/Refund endpoint Learn more
- Ability to send a request to the GET Transaction List endpoint Learn more
Process Flow
- A subscription rebill is sent directly to the gateway. It declines.
- It is then rerouted & scheduled to be sent through FlexPay.
- 24 hours after the initial rebill failure, a Charge is sent to FlexPay
- FlexPay analyses the payload and determines whether to send the request to the gateway.
- FlexPay analyses the response from the gateway. If it’s a soft decline, a retry is scheduled for a future date. FlexPay continues this process until one of the following events takes place:
- The transaction approves.
- The transaction hard declines.
- A configuration limit is reached. Maximum 15 retries or 30 days, whichever is reached first.
- To determine the status of transactions in recovery, the system of record sends a request for the list of all transactions in a given time frame.
- To stop the recovery process, (for example, if a customer cancels their subscription) the system of record sends a Refund-Payment request to FlexPay.
How-To
Send a transaction to FlexPay
Before sending a transaction to FlexPay, a payment gateway must be configured under a Company. It must include the merchant account’s credentials so FlexPay can connect on your behalf.
Gateway Management API
API reference: Gateway Management API
Using the Gateway Management API is the most reliable way to create and update a gateway in our system. Once created, you can use the merchantAccountReferenceId or the gatewayToken values to send a transaction to the appropriate gateway in FlexPay. Gateways can also be created manually in the FlexPay client portal. If you only have a small number if merchant accounts, this may be the easiest way to create the payment gateways in FlexPay.
Charge
API reference: Charge Request
Sending a transaction to FlexPay’s scheduler is the same as sending a transaction using our standard Enterprise integration. The difference is in the configuration of the account in FlexPay’s admin and client portal. When you first send a Charge request, FlexPay will evaluate and process the transaction synchronously. You can expect the response to take only a few hundred milliseconds more than your usual gateway transaction time. Authorize and Capture are not supported for Enterprise with Scheduler.
Note: you are not simply sending us the transaction data for FlexPay to process asynchronously. More often than not, we will process the transaction immediately and return a response that includes the result from your gateway. It is up to you whether to ingest the result of this response or wait for the next GET Transaction List request.
Once we receive the transaction, if we return a retry date, it is now in the FlexPay scheduler and will follow the recovery process. FlexPay will determine the next retry date and trigger any future transactions. If FlexPay has decided not to retry the transaction, we will return null in the retryDate field. You can look at FlexPay’s responseCode and message to determine the reason.
Get the status of transactions
Transactions List
API reference: List Request
To know the status of a transaction, you must send a GET request to receive a single transaction or a list of transactions that were processed in a specific time period. FlexPay recommends a daily request to receive details from the previous (or current) calendar day.
There are several parameters that can be configured when requesting a list of transactions.’
Params | Description |
order | The sorting order of the returned list. The default is asc, which returns the oldest records first. To list newer records first, use desc. |
sinceTransactionId | The transaction id of the item to start from (e.g., the last transaction id received in the previous list if iterating through records) By default, unbounded lists are returned in groups of 20 items. If there are more than 20 items in the list, use pagination to retrieve the next set of 20. To enforce determinism in a real-time system, pagination is indexed based on a specific record (as opposed to just a page number as is common in many web apps). To paginate to the next page, simply pass in the transactionId of the last record in the current result set. For instance, if the transactionId of the last transaction in the initial set of twenty transactions returned is JZE57KX6PMSU7MZLAFNIBQWJEQ, use that as the sinceTransactionId parameter to get the next set of 20 starting after that gateway. |
completedOnly | Request a list of transactions that have completed the recovery process. Note: If this parameter is not provided or null, response will return all transactions (Default/Current behavior). |
responseType | Request the simplified or detailed (Default) response. |
count | The number of transactions to return. By default, returns 20, maximum allowed is 100. |
startDate | Date range start of the returned list (Format: YYYY-MM-DD) |
endDate | Date range end of the returned list (Format: YYYY-MM-DD). To receive transactions from the current day, set this value to a future date (e.g. tomorrow). |
► Simplified Response Sample
{ "transactions": [ { "transactionId": "065RCDZZ4800000G002M71YGY3M4R", "transactionDate": "2023-10-31T14:51:38.658Z", "transactionStatus": 2, "message": "'MerchantTransactionReferenceId' and 'CustomerReferenceId' Required.", "transactionType": "Refund", "retryDate": null, "amount": 1050, "initialMerchantTransactionId ": "839BA292-C385-4A84-BB49-6E58118CD1BE638342846590759466638343606986743642", "paymentMethodStorageState": "Cached", "completionStatus": "RefundUnsuccessful" }, { "transactionId": "065RCDVAM000000G002QH1E25N1JM", "transactionDate": "2023-10-31T14:51:00.64Z", "transactionStatus": 2, "message": "Original payment not found using the field 'MerchantTransactionReferenceId'.", "transactionType": "Refund", "retryDate": null, "amount": 1050, "initialMerchantTransactionId ": "839BA292-C385-4A84-BB49-6E58118CD1BE638343603538821648", "paymentMethodStorageState": "Redacted", "completionStatus": "RefundUnsuccessful" }, { "transactionId": "065RCDF07R00000G002C0PGQ8MMGC", "transactionDate": "2023-10-31T14:49:19.678Z", "transactionStatus": 2, "message": "DO NOT RETRY - System error", "transactionType": "Charge", "retryDate": null, "amount": 1050, "initialMerchantTransactionId ": "839BA292-C385-4A84-BB49-6E58118CD1BE638343603538821648", "paymentMethodStorageState": "Redacted", "completionStatus": "RecoveryUnsuccessful" }, { "transactionId": "065RCC6TM800000G002HSHS3A3FSA", "transactionDate": "2023-10-31T14:43:50.562Z", "transactionStatus": 2, "message": "Original payment not found using the field 'MerchantTransactionReferenceId'.", "transactionType": "Refund", "retryDate": null, "amount": 1050, "initialMerchantTransactionId ": "839BA292-C385-4A84-BB49-6E58118CD1BE638343600911685741", "paymentMethodStorageState": "Redacted", "completionStatus": "RecoveryCancelled" }, { "transactionId": "065RCB6TM400000G002WGPSZQHKXC", "transactionDate": "2023-10-31T14:39:28.417Z", "transactionStatus": 2, "message": "Cannot refund this payment already refunded.", "transactionType": "Refund", "retryDate": null, "amount": 1050, "initialMerchantTransactionId ": "839BA292-C385-4A84-BB49-6E58118CD1BE638343595687306493", "paymentMethodStorageState": "Redacted", "completionStatus": "RefundUnsuccessful" }, { "transactionId": "065RCB3D8R00000G002QZ6AHQM06P", "transactionDate": "2023-10-31T14:39:00.422Z", "transactionStatus": 1, "message": "Approved.", "transactionType": "Refund", "retryDate": null, "amount": 1050, "initialMerchantTransactionId ": "839BA292-C385-4A84-BB49-6E58118CD1BE638343595687306493", "paymentMethodStorageState": "Redacted", "completionStatus": "Refunded" }, { "transactionId": "065RCATCE400000G00208H9NEVSBY", "transactionDate": "2023-10-31T14:37:46.481Z", "transactionStatus": 1, "message": "Approved.", "transactionType": "Charge", "retryDate": null, "amount": 1050, "initialMerchantTransactionId ": "839BA292-C385-4A84-BB49-6E58118CD1BE638343595687306493", "paymentMethodStorageState": "Redacted", "completionStatus": "RecoverySuccessful" } }
► Detailed Response Sample
"transactions": [ { "acquirerAuthCode": null, "responseCode": "50163", "gatewayTransactionId": null, "gatewayPaymentMethodId": null, "engagedRecoveryState": 0, "currencyCode": "USD", "retryDate": null, "merchantTransactionId": "01HE3PWTYP72CATMD17R1KTMY7", "merchantAccountReferenceId": "1007", "initialTransactionId": "065REV18SR00000G0825X82M8GWT6", "customerId": "AutoRetrySandboxCustomer 02", "orderId": "392E6A9C-AFD9-6533-BE4C-EA0FB7AF6113", "paymentMethodId": "VX6L5NIPMHOEDMEOAGFYO3BI7U", "paymentMethodStorageState": "Cached", "paymentMethodType": "CreditCard", "paymentMethodMerchantAccountReferenceId": null, "errorCode": null, "errorDetail": null, "gateway": { "token": "P65TO7YCDBRUVHKRER66MWG7PQ", "gatewayType": "flexpay_sandbox", "name": "QA Flexpay Sandbox", "referenceId": "1007" }, "transactionId": "065REWJAHM00000G082YA32GF4TGG", "transactionDate": "2023-10-31T20:34:56.269Z", "transactionStatus": 2, "message": "Original payment not found using the field 'MerchantTransactionReferenceId'.", "transactionType": "Refund", "amount": 1050, "initialMerchantTransactionId ": "909BA272-C385-4A84-BB49-6E53219CD100", "completionStatus": "RefundUnsuccessful" } }
For details on pagination, please see the following article.
Payment Status
API reference: Payment Status
The “payment-status” endpoint can be used to check the status of a transaction in recovery. It will return the last transaction processed for the payment in recovery.
Payment Status Example:
{ "transactionId": "065MV5WGS800000200252K6PHRACW", "transactionDate": "2023-10-20T14:57:40.554Z", "transactionStatus": 1, "completionStatus": "RecoverySuccessful", "message": "Approved.", "transactionType": "Charge", "initialMerchantTransactionId": "802BA292-C385-4A84-BB49-6E58118CD1BE638334106606" }
The completionStatus field is included in both the detailed and simplified response to provide clarity to clients. This field describes the end-state of a payment. The list of possible values returned in this field are found in the Completion Status Value column below.
Transaction Type | Transaction Status | Payment Method Storage State | Completion Status Value |
Charge | Approved |
| RecoverySuccessful |
Refund | Approved |
| Refunded |
Charge | Declined |
| RecoveryUnsuccessful |
Refund | Declined | Redacted | RecoveryCancelled |
Refund | Declined | NOT Redacted | RefundUnsuccessful |
Reconcile with your system
The transaction list and payment status requests will return certain fields that can help with reconciliation. FlexPay recommends using the initialMerchantTransactionId for this purpose. The value of this field was provided by your system when first sending a decline to FlexPay. This will remain consistent for every attempt processed by FlexPay.
Stop the retry process
There are two ways to stop the retry process via API:
- Use the Refund-Payment endpoint. This will Redact or Refund depending on the status of the payment.
- Using Redact and Refund separately (alternative methods)
Refund-Payment Endpoint
API reference: Refund-Payment
The “refund-payment” endpoint will refund (if transaction was approved) or redact (if transaction is still in recovery) with a single request.
- The refund-payment endpoint requires both merchantTransactionId (in the URL) and customerId (in the request body).
- The merchantTransactionId sent in the URL can be the initial value sent to Flexpay or any other merchantTransactionId’s from the chain of transactions.
- The customerId is required and must be send in the request body.
- Refunds can only be processed for a Maximum of 4 months from the approval date.
- NOTE: The merchantTransactionId in the request body is not the same as the one sent in the URL. It is a unique values used to reconcile this specific request. It is not required, so the field can be empty (“”), null, or omitted.
Refund-Payment Example:
{ "transaction": { "merchantTransactionId": "order-123Avc2017-09-20T14:42:49.3003196+00:00", "customerId": "customer-123" "disableCustomerRecovery": true, "amount": 0, "customVariable1": "var1", "customVariable2": "var2", "customVariable3": "var3", "customVariable4": "var4", "customVariable5": "var5" } }
Redact Payment Method
API reference: Redact
When you send a Charge to FlexPay, we generate and return a value for the paymentMethodId in our response. This value needs to be stored and used in a new request to stop the retry process.
Using the PUT Redact Payment Method endpoint will remove a customer’s payment method from our system. This effectively blocks any further transactions done on this card. If it is attempted again, FlexPay will a 50134 Invalid payment method token response. This transaction will not be sent to the gateway.
Refund a transaction
API Reference: Refund
If a payment that was recovered by FlexPay is subsequently refunded, FlexPay will credit the merchant for any fees associated with the recovery. The simplest way to keep track of these refunds is to process them through FlexPay
Sandbox Testing
Typically, the FlexPay enablement team will create a “Sandbox” account for testing. This account has all the same functionality as a production account, so caution must be exercised when configuring the account. Within the test account, FlexPay has a Sandbox environment where you can test the FlexPay Scheduler Auto-retries feature.
The sandbox environment applies to Payment Gateways and API keys. Companies can have both Production and Sandbox API keys associated to them. When you create a Sandbox API Key, you will only be able to create & send requests to payment gateways in the Sandbox environment. Not all gateways are supported in the Sandbox. In the Sandbox Environment, there is a gateway called “FlexPay Sandbox”. This gateway must be used for the testing scenarios described below.
Please speak to the FlexPay team if you don’t see the FlexPay Sandbox payment gateway available.
Requirements
The requirements for Sandbox testing are similar to those outlined previously in this guide, with two main differences. Instead of a regular FlexPay account, you need a FlexPay Test account, and instead of a regular payment gateway, you need a FlexPay Sandbox gateway. Please work closely with your integration manager to get these provisioned for you.
Use Cases
To simulate different scenarios and ensure your integration is ready for production, validate the following use cases by using the listed retryCount and Amounts.
Use Case 1: Testing Scheduling and Approval (using Credit Card)
- retryCount = 0
- amount = 9900
- creditCardNumber = Choose from Sandbox User Guide
- Flow:
- First transaction (sent by Integration Partner) will Decline and will automatically schedule a Retry (schedule command).
- Retry will be executed automatically by the auto retry integration within 5-10 minutes.
- Second transaction (sent by FlexPay Scheduler) will also Decline and will automatically schedule a Retry (schedule command)
- Third transaction (sent by FlexPay Scheduler) will Approve and there will be no more retries that will be scheduled.
- First transaction (sent by Integration Partner) will Decline and will automatically schedule a Retry (schedule command).
Use Case 2: Testing Scheduling and Approval (using 3rd Party Token)
- retryCount = 0
- amout = 9900
- gatewayPaymentMethodId= flexpay_auto_retries_sandbox_soft
- Example: "gatewayPaymentMethodId": "flexpay_auto_retries_sandbox_soft"
- Flow:
- First transaction (sent by Integration Partner) will Decline and will automatically schedule a Retry (schedule command).
- Retry will be executed automatically by the auto retry integration within 5-10 minutes.
- Second transaction (sent by FlexPay Scheduler) will also Decline and will automatically schedule a Retry (schedule command)
- Third transaction (sent by FlexPay Scheduler) will Approve and there will be no more retries that will be scheduled.
- First transaction (sent by Integration Partner) will Decline and will automatically schedule a Retry (schedule command).
Use Case 3: Testing Scheduling and Hard Decline (using Credit Card)
- retryCount = 0
- amount = 9910
- creditCardNumber = Choose from Sandbox User Guide
- Flow:
- First transaction (sent by Integration Partner) will Decline and will automatically schedule a Retry (schedule command).
- Retry will be executed automatically by the auto retry integration within 5-10 minutes.
- Second transaction (sent by FlexPay Scheduler) will Hard Decline and there will be no more retries that will be scheduled.
- First transaction (sent by Integration Partner) will Decline and will automatically schedule a Retry (schedule command).
Use Case 4: Testing Scheduling and Hard Decline (using 3rd Party Token)
- retryCount = 0
- amount = 9100
- gatewayPaymentMethodId= flexpay_auto_retries_sandbox_hard
- Example: "gatewayPaymentMethodId": "flexpay_auto_retries_sandbox_hard"
- Flow:
- First transaction (sent by Integration Partner) will Decline and will automatically schedule a Retry (schedule command).
- Retry will be executed automatically by the auto retry integration within 5-10 minutes.
- Second transaction (sent by FlexPay Scheduler) will Hard Decline and there will be no more retries that will be scheduled.
- First transaction (sent by Integration Partner) will Decline and will automatically schedule a Retry (schedule command).
Use Case 5: Testing a Redact/Refund request for an Approval
- retryCount = 1
- amount = 100
- Payment Method:
- gatewayPaymentMethodId = cus_1234
- OR
- creditCardNumber = Choose from Sandbox User Guide
- Flow:
- Send a POST Charge request with the values listed above. This should return an approval.
- Send a POST Refund-Payment request using the merchantTransactionId and customerId from the previous transaction.
- The response should return an approved refund.
- "message": "Approved."
- "responseCode": "10000"
- NOTE: You can also test this scenario with any gateway supported in the sandbox environment. Simply use the values required by your gateway's sandbox to trigger an approval.
Use Case 6: Testing a Redact/Refund request for a Soft Decline
- retryCount = 1
- amount = 2008
- Payment Method:
- creditCardNumber = Choose from Sandbox User Guide
- NOTE: This use case only works with a credit card in the FlexPay Sandbox Gateway.
- creditCardNumber = Choose from Sandbox User Guide
- Flow:
- Send a POST Charge request with the values listed above. This should return a "Do Not Honor" soft decline.
- Send a POST Refund-Payment request using the merchantTransactionId and customerId from the previous transaction.
- The response should return a hard decline with the following response code and message:
- "message": "Original transaction has not been captured scheduled recovery has been cancelled."
- "responseCode": "30103"
- This indicates that you have successfully cancelled FlexPay's recovery process for this payment.
- NOTE: You can also test this scenario with any gateway supported in the sandbox environment. Simply use the values required by your gateway's sandbox to trigger a soft decline.
Use Case 7: Testing a GET Transaction List Request
- After sending transactions to FlexPay in the earlier use cases, send a GET Transaction List request.
- Use a date range in the parameters that covers the previous use cases.
Use Case 8: Testing GET Transaction List Pagination
- When using the GET transaction list endpoint, you may encounter queries that contain more than the maximum number of records (100). In this case, you'll need to use Pagination to retrieve the additional records.
- Follow this guide to test the Pagination feature: https://support.flexpay.io/support/solutions/articles/27000078828-pagination-in-the-flexpay-api/preview
Use Case 9: Testing hard decline response
- retryCount = 1
- amount = 3016
- Payment Method:
- gatewayPaymentMethodId = cus_1234
- OR
- creditCardNumber = Choose from Sandbox User Guide
- Run this test if you are ingesting the result of the transaction response when first sending a decline to FlexPay.
- Use the values listed above for the FlexPay Sandbox gateway, or use the values defined by your chosen gateway's Sandbox endpoint (if available), to send a hard decline request.
Use Case 10: Testing an API validation error
- Run this test if you are ingesting the result of the transaction response when first sending a decline to FlexPay.
- Trigger an API validation error by sending an invalid request to FlexPay's API. For example: send an empty string ("") or NULL value for "customerId" AND "email".