Lifecycle Management
Spreedly’s Lifecycle Management feature allows you to always keep your customers’ card details up-to-date. When your customers’ credit card numbers expire or are updated, Lifecycle Management protects you from the lost revenue, involuntary churn, and decreased customer satisfaction associated with outdated payment information. No additional development is required on your side since cards are updated behind the scenes.
Lifecycle Management is a feature under Advanced Vault. To access Account Updater, the organization, environments and payment methods that you are wanting to update through the service must also be enrolled in the Advanced Vault Product.
How Lifecycle Management Works
When you opt-in, Spreedly defaults to submitting all retained, non-test, Visa, MasterCard, and Discover cards in your Spreedly vault for automatic updating twice monthly in batch on the 1st and 15th of every month, with results coming back approximately 5-6 days after they were sent. Additionally, Spreedly supports real time updates for Mastercard Cards. Spreedly will subscribe cards with the real time service once they are made eligible, and process updates as they are received. The enrollment process for either service and the appearance of the updates are exactly the same, with the only distinction being the time periods when these updates are recieved.
The table below lists current regional participation by card brand:
SUPPORTED SCHEMES | MARKET COVERAGE | Model |
---|---|---|
Visa | North America: Near full participation Europe: Near full participation in UK, Ireland, Italy, Greece. High participation elsewhere, excluding Hungary and Turkey. Latin America Central Europe, Middle East, Africa: High participation | Batch |
Mastercard | North America: near full participation. Europe: Near full participation in UK, Ireland, and Italy. High participation elsewhere. Latin America: High participation Asia Pacific: High participation, excluding India. Central Europe, Middle East, Africa: High participation. | Batch and Real Time |
Discover | North America: Near full participation. | Batch |
Mastercard Real Time Updates and Batch
Beginning on October 1st 2024, Spreedly will begin leveraging the Real Time Mastercard updating service as the primary source of updates for Mastercard card types.
MCABU is a service in which cards are subscribed, and updates are received from the service as they are submitted by the issuer. Spreedly tracks a state on every MC card of subscribed
, indicating that the card has been successfully subscribed to receive updates. If a MC card is not subscribed, we will continue sending it to the batch service to ensure the entire eligible vault is available for update, however if it is subscribed, it will be filtered out from being sent to the batch service to prevent duplicating updates or fees.
Handling Brand Swaps
A Brand Swap is a scenario where the issuer swaps from the one Network to another (eg, Visa to Mastercard). Spreedly's lifecycle management service supports this scenario, and will return as a normal replacepaymentmethod
event. This scenario is only supported via the batch service however. If a brand swap occurs on a Mastercard card, the update from the Real Time Mastercard service will be a closepaymentmethod
result. To continue supporting the brand swap use case, Spreedly will recognize a closepaymentmethod
result from Mastercard Real Time, indicated by updatingservice
MC_ABU
in the Account Updater Reporting Module, and allow it in those cases to go to the batch service to check for a brand swap. If the result is a replacepaymentmethod
it will be replaced with the details and continue being sent to batch for future updates. If the result is once again closepaymentmethod
, then the card will automatically be unenrolled for Lifecycle Management. Please note that different services can be subject to different pass through fees.
Lifecycle Management control levels
The below steps outline the enablement of account updater underneath Advanced Vault. However, as noted above, Advanced Vault must also be enabled fully for a payment method to be eligible for Account Updater. Please refer to this section of the guide for Advanced Vault enablement. The order in which you enable AV and LCM is up to the user, however both must be enabled before LCM will begin processing.
Organizational-level controls
Opting in to Lifecycle Management happens at the organization level - all environments will be affected. By enabling the Lifecycle Management feature, all eligible cards will be sent for update, but you will only be charged for those cards that are identified to be updated. Turning Lifecycle Management off at the organizational level will not affect an individual card’s eligibility status.
Environment-level controls
For more granular control, you can opt for specific environments to have their cards sent to Lifecycle Management while excluding other environments from card updates. In order to enable Lifecycle Management at the environment level, it must first be enabled for an organization.
Managing Environments for Lifecycle Management
Given Lifecycle Management is enabled for the organization, toggle “Allow Account Updater at Environment Level” in the Organization Settings. This setting can be toggled in the Spreedly App once you are logged in. Once this is enabled, only environments specifically toggled in the UI or are marked as au_enabled will be sent to Account Updater.
You may now enable individual environments via the UI under each environment by toggling the setting “Environment Level Account Updater Enabled” (the property on the Environment model is au_enabled). Alternatively, environments can be enabled via the environment create and update endpoints by passing the field au_enabled: true in the body.
This setting is disabled by default for all environments. Thus, if only “Allow Account Updater at Environment Level” is enabled in the Organization Settings, none of the environments will participate in the Lifecycle Management process until they are specifically enabled.
Card-Level Controls
You can optionally exclude individual cards from the Lifecycle Management service via our API. For example, you may want to exclude a card if your customer has paused their subscription. Payment methods include an eligible_for_card_updater
field that when set to false will result in Spreedly excluding the associated card from subsequent submissions to the Lifecycle Managementr service. You can set this field to true to resume submitting the given card at any time.
Note: Payment methods that have the eligible_for_card_updater
field set to false
will continue to be excluded from being updated by Account Updater regardless of the Environment level Lifecycle Management enablement settings.
Configuration Matrix
ORG AU | ALLOW AU AT ENVIRONMENT LEVEL | AU_ENABLED (ENVIRONMENT) | ELIGIBLE_FOR_CARD_UPDATER (PAYMENT METHOD) | EXPECTED RESULTS |
---|---|---|---|---|
Off | N/A | N/A | True | Card is eligible but not sent to AU because AU is Off for the Organization |
On | Off | N/A | True | All cards in the organization with eligible_for_card_updater: true are sent to AU |
On | On | False | True | AU is On at the environment level but the specific environment is not au_enabled . No cards are sent from that environment regardless of eligibility |
On | On | True | True | All environments with au_enabled: true or “Environment Level Account Updater Enabled” toggled on will have all eligible cards sent to AU |
On | On/Off | True/False | False | Cards with eligible_for_card_updater: false will not be sent to AU |
Analyze Results
Dashboard
Results of Lifecycle Management submissions can be tracked in your Spreedly dashboard, where you can view summary statistics by month for a selected time period, see detailed per-card results and download a CSV report for a given period right from the dashboard. The status for each card is shown:
ReplacePaymentMethod
(billable) - The number and/or expiration date has been updated. See the section on Fields.
InvalidReplacePaymentMethod
(not billed) - We received either a new card number or expiration date that was invalid. The payment method was not updated, and there is no charge. Please reach out to support if you find a problematic payment method receiving this response with high frequency.
ContactCardHolder
(billable) - The card network identified this account needs to be updated but the issuer did not provide the updated values to the service. Contact the cardholder for a new number and/or expiration date. Spreedly will automatically unenroll the card from LCM after 2 sequential ContactCardHolder
responses because data shows there is virtually no chance of an update after 2 sequential responses (no ROI for the fees).
ClosePaymentMethod
(billable) - The account is no longer open and should no longer be used. The payment method will remain available, but Spreedly’s Lifecycle Management will no longer attempt to update it.
Custom Analytics
Spreedly also provides Custom Analytics that allows the customer to build their own dashboard and visualizations that best suits their needs. For more details on implementing, please see the Custom Analytics for Dashboard
Callbacks
As an alternative to viewing results in the Spreedly dashboard, callbacks are provided that will push Lifecycle Management results to a destination of your choosing. These notifications are delivered via an HTTPS POST to a public-facing URL on your server. This should be a URL to your system that is able to receive a POST request with a list of transactions whose state has been updated.
Since Lifecycle Management operates in a batch manner and card updates may result in a large number of transactions, Spreedly only delivers callbacks every few minutes. A single callback may contain up to 150 transactions with a maximum delivery of approximately 500 callbacks within a 24 hour period period per environment when using an environment based callback URL or per URL when using an override.
The incoming callback POST requests will be structured as follows:
{
"transactions": \[
{
"token": "S6cl5f11LqdVLe9m1TtQGMSMUuz",
"created_at": "2019-02-13T13:40:43Z",
"updated_at": "2019-02-13T13:42:48Z",
"succeeded": true,
"transaction_type": "ReplacePaymentMethod",
"state": "succeeded",
"account_key": "2H2HmVvjh171NvjCzr37D7jWG6c",
"environment_key": "DDB58wpfgxHA1qD7p0LkqCLBnZw",
"message_key": "messages.transaction_succeeded",
"message": "Succeeded!",
"payment_method": {
"token": "EjpBzUVNHWnF1Y0MNaefuNpXwyR",
"created_at": "2019-02-13T13:27:53Z",
"updated_at": "2019-02-13T13:40:43Z",
"email": "[[email protected]](mailto:[email protected])",
"data": null,
"storage_state": "retained",
"test": false,
"metadata": null,
"callback_url": "<https://7fba2acd.ngrok.io">,
"last_four_digits": "0003",
"first_six_digits": "511201",
"card_type": "master",
"first_name": "Mighty",
"last_name": "Mouse",
"month": 1,
"year": 2050,
"address1": null,
"address2": null,
"city": null,
"state": null,
"zip": null,
"country": null,
"phone_number": null,
"company": null,
"full_name": "Mighty Mouse",
"eligible_for_card_updater": true,
"shipping_address1": null,
"shipping_address2": null,
"shipping_city": null,
"shipping_state": null,
"shipping_zip": null,
"shipping_country": null,
"shipping_phone_number": null,
"payment_method_type": "credit_card",
"errors": \[],
"fingerprint": "84fd610e28258201fffea68dc0f9e7c66859",
"verification_value": "",
"number": "XXXX-XXXX-XXXX-0003"
},
"signed": {
"signature": "03268a0a7ccb7a1e18cd99f60513ec9814f9d240",
"fields": "token created_at updated_at succeeded transaction_type state",
"algorithm": "sha1"
}
},
{
"token": "I5kuefCHe8Tvm9HypLRLIKYHCmm",
"created_at": "2019-02-13T13:40:40Z",
"updated_at": "2019-02-13T13:42:48Z",
"succeeded": true,
"transaction_type": "ClosePaymentMethod",
"state": "succeeded",
"account_key": "2H2HmVvjh171NvjCzr37D7jWG6c",
"environment_key": "DDB58wpfgxHA1qD7p0LkqCLBnZw",
"message_key": "messages.transaction_succeeded",
"message": "Succeeded!",
"payment_method": {
"token": "7xHGM9h7a8OoUboXPNHvY5pihgv",
"created_at": "2019-02-13T13:27:56Z",
"updated_at": "2019-02-13T13:40:40Z",
"email": "[[email protected]](mailto:[email protected])",
"data": null,
"storage_state": "retained",
"test": false,
"metadata": null,
"callback_url": "<https://7fba2acd.ngrok.io">,
"last_four_digits": "0002",
"first_six_digits": "601101",
"card_type": "discover",
"first_name": "Mighty",
"last_name": "Mouse",
"month": 8,
"year": 1950,
"address1": null,
"address2": null,
"city": null,
"state": null,
"zip": null,
"country": null,
"phone_number": null,
"company": null,
"full_name": "Mighty Mouse",
"eligible_for_card_updater": false,
"shipping_address1": null,
"shipping_address2": null,
"shipping_city": null,
"shipping_state": null,
"shipping_zip": null,
"shipping_country": null,
"shipping_phone_number": null,
"payment_method_type": "credit_card",
"errors": \[],
"fingerprint": "2b4184e42067002e39fb3f5a7e9275f34b17",
"verification_value": "",
"number": "XXXX-XXXX-XXXX-0002"
},
"signed": {
"signature": "808eada381675ff34c3d0b67b010dda965445451",
"fields": "token created_at updated_at succeeded transaction_type state",
"algorithm": "sha1"
}
}
]
}
Note that each transaction contained in a callback is signed; this allows you to process the results of the callback without having to round trip back to Spreedly (though you certainly can round trip if you’d like - see below). Since an attacker could call your callback url with a valid looking transaction, the signature allows you to verify that the information in each transaction is really coming from Spreedly. In the example callback request shown above, the signatures were created using the following signing secret:
4ziASKWGGV1zdrUbSN6vq2CjjDPw2hzJSvsGLhxces1aORBKKsRyJwb8DfGQ6J3q
Here is an example of ruby code you could use to verify the signatures in the above callback request (with most of the fields omitted for brevity):
require 'openssl'
def signature_for(secret, transaction)
algorithm = transaction['signed']['algorithm']
fields = transaction['signed']['fields'].split(' ')
values = fields.collect { |field| transaction[field] }
# Note that Boolean values in Ruby are cast to `true` or `false` as strings.
# This may work differently in other languages and will have an impact on computing the signature.
signature_data = values.join("|")
signature = OpenSSL::HMAC.hexdigest(
OpenSSL::Digest.new(algorithm),
secret,
signature_data
)
end
document = JSON.parse(
%(
{
"transactions": [
{
"token": "S6cl5f11LqdVLe9m1TtQGMSMUuz",
"created_at": "2019-02-13T13:40:43Z",
"updated_at": "2019-02-13T13:42:48Z",
"succeeded": true,
"transaction_type": "ReplacePaymentMethod",
"state": "succeeded",
"signed": {
"signature": "03268a0a7ccb7a1e18cd99f60513ec9814f9d240",
"fields": "token created_at updated_at succeeded transaction_type state",
"algorithm": "sha1"
}
},
{
"token": "I5kuefCHe8Tvm9HypLRLIKYHCmm",
"created_at": "2019-02-13T13:40:40Z",
"updated_at": "2019-02-13T13:42:48Z",
"succeeded": true,
"transaction_type": "ClosePaymentMethod",
"state": "succeeded",
"signed": {
"signature": "808eada381675ff34c3d0b67b010dda965445451",
"fields": "token created_at updated_at succeeded transaction_type state",
"algorithm": "sha1"
}
}
]
}
)
)
document['transactions'].each do |transaction|
puts signature_for(
"4ziASKWGGV1zdrUbSN6vq2CjjDPw2hzJSvsGLhxces1aORBKKsRyJwb8DfGQ6J3q",
transaction
)
end
"03268a0a7ccb7a1e18cd99f60513ec9814f9d240"
"808eada381675ff34c3d0b67b010dda965445451"
You can find more details about signed requests in our signing reference.
We recognize that some customers are not interested in going through the trouble of writing code to validate the signature of the callback response. In this case, you can use the tokens of the transactions you receive in the callback and then make an authenticated API call to retrieve the details of each transaction. Because that call is authenticated and you’re making the request, there’s no need to verify where the information is coming from.
Callback Response
You should respond back with a 200 OK response within 5 seconds. If Spreedly does not receive back a 200 response within this time, it will retry the callback again at least 4 times at ever-increasing intervals. If you need to do potentially time-consuming operations when a callback is received, we recommend doing them asynchronously to avoid being timed out. Additionally, callbacks should be treated as idempotent since they may be sent more than once.
If you are not receiving callbacks, ensure that the callback URL provided utilizes HTTPS with standard port 443.
Getting started with callbacks
To get started with callbacks on Lifecycle Management, a callback URL must be added to your Spreedly environment. Log in, select the environment you wish configure, and add a callback URL. If you store payment methods in multiple environments, a callback URL must be configured for each environment.
Additionally, Spreedly provides the ability to override the per-environment level callback URL with a payment method specific callback URL. This override is useful in situations where card update notifications are to be delivered to a location different from the environment level callback URL. To override the environment level callback URL, both the create payment method and update payment method API calls include a callback_url property
that can be set. Once set, any update notifications related to this payment method will be delivered to the callback_url set on the payment method instead of the environment. By default, the callback_url
property on a payment method is null and will only take precedence over the environment level setting when set. Spreedly does not update all of your payment methods when the environment level setting is present.
We don't currently support testing callbacks specifically for Lifecycle Management on the Spreedly test platform. You can stub our example responses.
Fields
The following fields on a payment method can be changed by the Account Updater service with data directly from the card schemes:
number:
The obscured new credit card number returned by Account Updater
month:
The new expiration month returned by Account Updater
year:
The new expiration year returned by Account Updater
The following fields on a payment method can be changed by Spreedly based on data from the card schemes:
fingerprint:
The fingerprint is a randomly generated identifer to cards that share the same number (PAN). If the PAN changed, Spreedly will generate a new identifier for the number. See our fingerprinting guide for more information.
card_type:
Spreedly will detect and update the card_type field if the PAN changed. Note: if a payment method’s card_type changes, any stored credentials stored on that payment method are considered invalid and deleted. See our stored credentials guide for more information.
last_four_digits:
Spreedly will update the last_four_digits of the credit card number if the PAN changed.
first_six_digits:
Spreedly will update the first_six_digits of the credit card number if the PAN changed.
Note that Spreedly does not retain any of the previously updated field values from the payment method. Once an update is made the old values are overwritten.
The following field can be changed by Spreedly's Advanced Vault Automations as a result of updates received
eligible_for_account_updater:
After a single ClosePaymentMethod
response or two successive ContactCardHolder
responses, the value in this field will be changed from true
to false
.
Email Notifications
We will send two e-mail notifications when your cards are updated. Notifications will be sent to all active users associated with the organization. The first email is notice that the card update process has started. Example:
The second email is notice that card updates have completed and contains aggregate information about the updates that were performed. Example:
Please visit the Help Center for a detailed walkthrough on pricing, opting-in, and opting-out.
Updated 25 days ago