Sticky Recovery Integration Guide (Recover Endpoint)
The guide provides a detailed roadmap for integrating Sticky Recovery solution.

π Introduction
Welcome to the integration guide for the Recover API Endpoint, part of sticky.ioβs payment recovery suite. This endpoint allows you to fully automate the process of retrying failed transactions. Built on the same machine learning engine behind the Smart Dunning service, the Recover endpoint is a fully managed solution: you submit the failed payment, and we take care of the rest.
π Summary
The Recover endpoint simplifies payment recovery by automatically resubmitting declined transactions to your connected gateway profiles. This guide provides the technical requirements and step-by-step instructions to help you integrate the Recover API, ensuring seamless recovery of failed payments with no need to build retry logic on your end. Youβll also learn how to configure webhook notifications to stay informed of recovery attempts and outcomes in real time.
βοΈ How It Works
- You submit a failed transaction via the Recover API.
- Sticky manages the retry attempts based on the dunning profile.
- All retry attempts are executed using your connected payment gateway.
- You receive webhook updates for every failed retry and final outcome.
- No scheduling or logic required β it's set-it-and-forget-it.
β
Prerequisites
Before integrating the Recover endpoint, ensure the following:
- Obtain an API Key: Your API key will be provided by sticky.io during onboarding. This key is required to authenticate all requests to the Recover API. The key can also be found under the developer section.
- Gateway Profile Connected: At least one payment gateway must be connected through the Sticky.io platform.
- Failed Transaction Data: You must submit relevant data from the original failed transaction (e.g., amount, currency, decline reason, gateway transaction ID).
- (Optional but recommended) Include the Decline Reason and BIN to improve the recovery strategy.
- Webhook URLs Configured (Optional but Recommended): To receive updates throughout the recovery lifecycle, configure webhook endpoints via Developer > Webhooks in the UI.
π¬ Submitting a Recovery Request
π API Reference: Recover Endpoint
Required Parameters
- paymentProfileId
- initiatedBy
- isRecurring
- paymentMethod
- originalTransaction
- id
- amount (To override, use paymentMethod.amount)
- currency (To override, use paymentMethod.currency)
- declineReason
Not Required but Highly Recommended Parameters
- originalTransaction
- bin
- mitReferenceTransactionId
Gateway Specific Fields
Rocket Gate:
- customer.customerId (Required): Required by the gateway when submitting a payment with the gateway token.
- Rocket Gate: MERCHANT_CUSTOMER_ID
- paymentMethod.token.id (Required)
- Rocket Gate: CARD_HASH
- customer.firstName
- customer.lastName
- customer.email
- billingAddress.address1
- billingAddress.city
- billingAddress.zip
- billingAddress.state
- billingAddress.country
- β οΈWhen providing the billing country, supply the country code in ISO 3166-1 alpha-2 format (e.g., "US", "CA", "GB", "AU"). RocketGate strictly enforces this format and will reject requests that pass full country names (e.g., "United States", "Canada", "United Kingdom"). Rocket Gate Documentation
β Correct example:
"billingAddress.country": "US"
β Incorrect example:
"billingAddress.country": "United States"
- β οΈWhen providing the billing country, supply the country code in ISO 3166-1 alpha-2 format (e.g., "US", "CA", "GB", "AU"). RocketGate strictly enforces this format and will reject requests that pass full country names (e.g., "United States", "Canada", "United Kingdom"). Rocket Gate Documentation
- externalId
- Rocket Gate: MERCHANT_INVOICE_ID
- mitReferenceTransactionId
- Rocket Gate: REFERENCE_SCHEME_TRANSACTION_ID
- mitReferenceSettlementDate (Conditionally Required)
- Rocket Gate: REFERENCE_SCHEME_SETTLEMENT_DATE
- This field is required when
mitReferenceTransactionId
is provided, and the transaction involves a MasterCard.
Authorize.Net:
- customer.customerId (Required)
- Authorize.Net: customerProfileId
- paymentMethod.token.id (Required)
- Authorize.Net: paymentProfile.paymentProfileId
- mitReferenceTransactionId
- Authorize.Net: subsequentAuthInformation.originalNetworkTransId
When Should You Call the Recover Endpoint?
Merchants should call the Recover API as soon as a payment is declined to maximize the chances of recovery. The goal is to get failed transactions into the recovery system promptly so retries can begin without delay.
This can be triggered in a variety of ways, depending on your tech stack and data flow β for example:
- When receiving a decline webhook from your payment gateway
- When a recurring billing engine flags a failed renewal attempt
- From within your internal payment orchestration logic
- Any time a failed transaction is detected in real time
π‘ Best Practice:
The faster you trigger the Recover API after a decline, the higher the probability of a successful retry. Submitting failed payments promptly enables the recovery engine to take over without requiring manual scheduling or delay.
β Canceling a Recovery Session
π API Reference: Cancel Recovery Endpoint
In some cases, merchants may want to halt an active recovery session β for example, if a customer updates their payment method externally or cancels their subscription.
The Cancel Recovery endpoint allows merchants to immediately stop a recovery cycle.
Key Requirements:
- Submit the
stickyTransactionId
associated with the active recovery session. - Choose the appropriate cancellation reason.
- CANCELED: The merchant or customer ends the service, stopping all future payment attempts, regardless of the dunning stage.
- DEFERRED: Subscription has been temporarily paused, or when a subscriber chooses to skip a payment cycle.
- RESOLVED: Previously outstanding payment issue have been successfully addressed and rectified through alternative means or manual intervention external to the standard dunning process.
- Once canceled, no further retry attempts will be scheduled.
-
π‘ Webhooks (Optional)
Webhooks let you receive real-time updates on the progress and outcome of Sticky Recovery sessions. This enables immediate downstream actions, such as internal logging, customer notifications, or dashboard updates, without needing to poll the API.
Configuring Webhook Endpoints

To start receiving webhooks:
1οΈβ£ Go to Developer > Webhooks in the Sticky Recovery UI.
2οΈβ£ Add the URL(s) where you want events to be sent.
3οΈβ£ Select one or more of the following supported event types.
Supported Webhook Events
Webhook Event | Description |
---|---|
recovery_started | Triggered when a recovery session is created. |
recovery_attempt_failed | Fired when a retry attempt fails. |
recovery_successful | Fired when a retry attempt results in a successful payment. |
recovery_unsuccessful | Sent when the recovery session ends without success (max retries or cancel). |
Webhook Encryption Key Phrase
To secure webhook delivery, Sticky encrypts all payloads using a symmetric encryption key that you must configure in advance. This key is referred to as the webhook encryption key phrase.
Requirements:
- Must be exactly 32 characters
- Alphanumeric only (letters A-Z, numbers 0-9)
- Case-sensitive (e.g., A β a)
Sending Test event

To help validate your integration setup, Sticky provides a Send Test Event feature within the Developer > Webhooks UI. This sends a mock webhook payload to your configured endpoint to confirm delivery and decryption.
The test payload will be delivered encrypted using your configured webhook secret and will decode to the following JSON:
{
"message": "Congrats! You successfully received the webhook.",
"reference": "See the integration guide for more information on handling webhook responses.",
"URL": "https://sticky.readme.io/docs/sticky-recovery-integration-guide-recover#-webhooks-optional"
}
This response confirms that:
- Your webhook URL is reachable and responsive.
- Your decryption key is correctly implemented.
- Sticky can deliver events securely to your endpoint.
Decryption Code Snippets
public String decrypt(String key, String ciphertext) {
byte[] cipherbytes = Base64.getDecoder().decode(ciphertext);
byte[] initVector = Arrays.copyOfRange(cipherbytes,0,16);
byte[] messagebytes = Arrays.copyOfRange(cipherbytes,16,cipherbytes.length);
IvParameterSpec iv = new IvParameterSpec(initVector);
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] byte_array = cipher.doFinal(messagebytes);
return new String(byte_array, StandardCharsets.UTF_8);
}
from Crypto.Cipher import AES
import base64
import sys
import os
# AES 'pad' byte array to multiple of BLOCK_SIZE bytes
def pad(byte_array):
BLOCK_SIZE = 16
pad_len = BLOCK_SIZE - len(byte_array) % BLOCK_SIZE
return byte_array + (bytes([pad_len]) * pad_len)
# Remove padding at end of byte array
def unpad(byte_array):
last_byte = byte_array[-1]
return byte_array[0:-last_byte]
def encrypt(key, message):
"""
Input String, return base64 encoded encrypted String
"""
byte_array = message.encode("UTF-8")
padded = pad(byte_array)
# generate a random iv and prepend that to the encrypted result.
# The recipient then needs to unpack the iv and use it.
iv = os.urandom(AES.block_size)
cipher = AES.new( key.encode("UTF-8"), AES.MODE_CBC, iv )
encrypted = cipher.encrypt(padded)
# Note we PREPEND the unencrypted iv to the encrypted message
return base64.b64encode(iv+encrypted).decode("UTF-8")
def decrypt(key, message):
"""
Input encrypted bytes, return decrypted bytes, using iv and key
"""
byte_array = base64.b64decode(message)
iv = byte_array[0:16] # extract the 16-byte initialization vector
messagebytes = byte_array[16:] # encrypted message is the bit after the iv
cipher = AES.new(key.encode("UTF-8"), AES.MODE_CBC, iv )
decrypted_padded = cipher.decrypt(messagebytes)
decrypted = unpad(decrypted_padded)
return decrypted.decode("UTF-8");
def main():
key = 'YOUR_KEY_HERE'
message = 'YOUR_ENCRYPTED_MESSAGE'
print(decrypt(key,message))
main()
Decrypted JSON Encoded Payloads
recovery_started
{
"clientAppKey": "7bebb0d5-ea45-44aa-9122-fb522eb12314",
"type": "recovery.started",
"time": "2025-05-23T19:48:17.097Z",
"data": {
"stickyTransactionId": "249fa7da9125b036011e97d24719586f7442d97405125801f9",
"gatewayProfileId": "1568",
"dunningProfileId": "297",
"dunningSessionId": "2025060518423881610"
}
}
recovery_attempt_failed
{
"clientAppKey": "7bebb0d5-ea45-44aa-9122-fb522eb12314",
"type": "recovery.attempt_failed",
"time": "2025-05-23T19:48:17.097Z",
"data": {
"stickyTransactionId": "054440bf260fd6a205f20b83dea7e16401d440f70d844d9399",
"gatewayTransactionId": "100019740BA5CBB",
"amount": 50000,
"currency": "USD",
"gatewayProfileName": "RocketGate",
"gatewayProfile": "RocketGate",
"gatewayProfileId": "12345",
"dunningProfileId": "297",
"dunningSessionId": "2025060518423881610",
"attemptNumber": 1,
"gatewayResponse": {
//GATEWAY RESPONSE
}
}
}
recovery_successful
{
"clientAppKey": "7bebb0d5-ea45-44aa-9122-fb522eb12314",
"type": "recovery.successful",
"time": "2025-05-23T19:48:17.097Z",
"data": {
"stickyTransactionId": "054440bf260fd6a205f20b83dea7e16401d440f70d844d9399",
"gatewayTransactionId": "100019740BA5CBB",
"dunningSessionId": "2025060518423881610",
"dunningProfileId": "297",
"amount": 50000,
"currency": "USD",
"gatewayProfileName": "RocketGate",
"gatewayProfile": "RocketGate",
"gatewayProfileId": "12345",
"gatewayResponse": {
//GATEWAY RESPONSE
}
}
}
recovery_unsuccessful
{
"clientAppKey": "7bebb0d5-ea45-44aa-9122-fb522eb12314",
"type": "recovery.unsuccessful",
"time": "2025-05-23T19:48:17.097Z",
"data": {
"stickyTransactionId": "054440bf260fd6a205f20b83dea7e16401d440f70d844d9399",
"dunningSessionId": "2025060518423881610",
}
}
Webhook Retries
Sticky automatically retries webhook delivery if your endpoint:
- Times out
- Returns an HTTP status between 500 and 503
- 500 - Internal Server Error: A generic error from the server when no specific message is available. Usually indicates an unexpected failure.
- 501 - Not Implemented: The server doesn't support the functionality required to fulfill the request. Rare in webhook contexts.
- 502 - Bad Gateway: The server (often a reverse proxy or gateway) received an invalid response from an upstream server.
- 503 - Service Unavailable: The server is temporarily unable to handle the request. Often due to overload or maintenance.
Retry Policy:
- 5 attempts total per failed delivery.
- Interval: Every 6 hours, controlled via cron (runs 4 times daily).
π§ͺ Testing
To validate your Sticky Recovery integration end-to-end:
Connect a Gateway Profile
Ensure at least one payment gateway is configured and active under your Sticky account.
Submit a Simulated Declined Transaction
Call the recover endpoint using test data that mimics a failed transaction.
Verify API Response
Confirm the response includes a valid stickyTransactionId
, which indicates a recovery session was successfully created.
Confirm Recovery Activity
Use the Recovery Activity UI to validate that the session appears and that retry attempts are being scheduled.
Monitor Webhook Events (Optional)
If webhooks are configured, validate that your endpoint is receiving event notifications like recovery_started and recovery_successful.
Cancel the Recovery Session
Use the Cancel Recovery endpoint to terminate the recovery session:
- Call the endpoint using the stickyTransactionId from the previous step.
- Confirm that the session status updates to "Unrecovered" in the Recovery Activity dashboard.
- (If applicable) Check that the recovery_unsuccessful webhook fires as expected.
ποΈβπ¨οΈ Transaction Query APIs
Sticky Recovery supports read-only GET APIs for querying transaction data. These endpoints allow merchants to retrieve payment activity for reporting, analytics, operational monitoring, and payment reconciliation. These endpoints are read-only and do not modify any recovery sessions or trigger retries.
Below are the supported GET APIs for retrieving transactions. You can find sample payloads at the following link.
Get Gateway Transaction (API)
- Retrieve the details of a specific gateway-level transaction attempt.
- Useful for support teams reviewing specific declines, approvals, or chargebacks.
Get Transaction History (API)
- Fetch the full history of a Sticky Recovery transaction, including retries, refunds, and final statuses.
- The stickyTransactionId is returned in responses when submitting to the Recover API.
Get List of Transactions (API)
- Retrieve a paginated list of transactions for reporting and analytics.
πΉοΈ Diagrams
Sequence

Dupe Prevention

Updated 5 days ago