Account Updater Enterprise
Basis Theory supports merchants who leverage card-on-file transactions or subscription billing models by allowing payment card data to be collected and securely vaulted for future transactions. However, vaulted card details can become outdated when cards are re-issued due to card expiration, account closures, lost or stolen cards, or fraud prevention. This can result in failed transactions and billing disruptions, leading to involuntary customer churn or lost revenue. Account Updater enables you to keep vaulted card tokens up to date with the latest information from the card networks, improving transaction success rates.
Each request to update a batch of cards is referred to as an Account Updater Job. Job requests and results are transmitted using CSV-formatted flat files containing Basis Theory tokens. Jobs are submitted in a 2-step process - first, create an account updater job and receive an upload URL in the response, then upload your request CSV file directly through the upload URL. Once all updates have been received from the card networks and the job has been completed, you will receive a webhook reporting the overall job status. If successful, the job's result details can be downloaded in CSV format, which you can use to update token id references in your system.
Basis Theory currently supports updating card
tokens against the Visa, Mastercard, American Express, and Discover networks.
Create Account Updater Job
Creates an Account Updater Job to update a batch of card
tokens. Responds with an Account Updater Job including an upload_url
to submit a request CSV file for processing.
Permissions
account-updater:job:create
Expiration
You have one hour to upload a request file, at which time the job and upload url will expire and the job will be removed. Attempting to retrieve an expired job will result in a 404
status code. If a job expires, simply start the process again by creating a new job.
Request
- cURL
curl "https://api.basistheory.com/account-updater/jobs" \
-X POST \
-H 'Content-Type: application/json' \
-H 'BT-API-KEY: ...'
Response
{
"id": "93f3da5e-7887-408c-88ed-b10a5fdb423a",
"tenant_id": "9a63ab82-1d11-59a0-93ab-4e1ec98b9fdd",
"status": "pending",
"created_by": "2c8f4156-4ac6-5e71-9e03-8811fd6bc514",
"created_at": "2024-04-09T13:56:37.864Z",
"expires_at": "2024-04-09T14:56:37.864Z",
"upload_url": "https://bt-prod-us-east-2-account-updater-data.s3.us-east-2.amazonaws.com/..."
}
Job Timing
The following table outlines the typical completion times from jobs:
Tenant Type | Job Completion Time |
---|---|
Test | Near real-time |
Production | Up to 7 days |
Upload Request File
Once you have created a Request CSV File, you can use the upload_url
for the Job to submit your file for processing. You can use the upload_url
to upload your file using any usage patterns supported by S3 pre-signed URLs.
- cURL
- JavaScript
curl -X PUT -T "/local/path/to/file" "https://bt-prod-us-east-2-account-updater-data.s3.us-east-2.amazonaws.com/..."
const fileName = `.data/${jobId}/request.csv`; // create your csv request file here
const fileStats = fs.statSync(fileName);
const response = await fetch(uploadUrl, {
method: 'PUT',
headers: {
'Content-Type': 'text/csv',
'Content-Length': fileStats.size,
},
body: fs.createReadStream(fileName),
duplex: 'half',
});
Get Account Updater Job
Retrieves an Account Updater Job. This endpoint can be used to poll for job failure or completion if webhook callbacks are not desired.
Permissions
account-updater:job:read
Request
- cURL
curl "https://api.basistheory.com/account-updater/jobs/93f3da5e-7887-408c-88ed-b10a5fdb423a" \
-H 'BT-API-KEY: ...'
Response
{
"id": "93f3da5e-7887-408c-88ed-b10a5fdb423a",
"tenant_id": "9a63ab82-1d11-59a0-93ab-4e1ec98b9fdd",
"status": "pending",
"created_by": "2c8f4156-4ac6-5e71-9e03-8811fd6bc514",
"created_at": "2024-04-09T13:56:37.864Z",
"expires_at": "2024-04-09T14:56:37.864Z",
"upload_url": "https://bt-prod-us-east-2-account-updater-data.s3.us-east-2.amazonaws.com/..."
}
List Account Updater Jobs
Return a list of all Account Updater Jobs created for the tenant.
Permissions
account-updater:job:read
Request
- cURL
curl "https://api.basistheory.com/account-updater/jobs" \
-H 'BT-API-KEY: ...'
Sort Order
This endpoint returns newest jobs first.
Query Params
Param | Description |
---|---|
size | The maximum number of jobs to return in the response. Defaults to 20. |
start | The cursor at which the result set should start. This is the value of the next cursor returned in the previous response. |
Response
{
"pagination": {
"next": "Q1JFQVRFRF9BVCMyMDI0LTA0LTI1VDE2OjU4OjA3LjgyMVo=",
"page_size": 20
},
"data": [
{
"id": "93f3da5e-7887-408c-88ed-b10a5fdb423a",
"tenant_id": "9a63ab82-1d11-59a0-93ab-4e1ec98b9fdd",
"status": "pending",
"created_by": "2c8f4156-4ac6-5e71-9e03-8811fd6bc514",
"created_at": "2024-04-09T13:56:37.864Z",
"expires_at": "2024-04-09T14:56:37.864Z",
"upload_url": "https://bt-prod-us-east-2-account-updater-data.s3.us-east-2.amazonaws.com/..."
},
...
]
}
Account Updater Job Webhook
Configure a webhook to receive notifications for job status changes. You are able to subscribe to webhooks for events of type account-updater.job.created
, account-updater.job.completed
, or account-updater.job.failed
.
Webhook Payload
{
"event": {
"id": "e99b3bb9-25e4-484f-8a6d-6bc28edbbf39",
"type": "account-updater.job.completed",
"timestamp": "2024-04-09T13:56:37.864Z",
"tenant_id": "869d5b1c-1ae8-4ce6-96c6-73a602b407ff",
"trace_id": "0f777425-9080-4d82-b557-799f43aefcba",
"data": {
"job": {
"id": "55256454-c9f9-4e79-bc9e-24bd38af5c21",
"status": "completed"
}
}
},
"delivered_at": "2024-04-09T13:56:42.673Z"
}
Webhook Types
account-updater.job.created
account-updater.job.completed
account-updater.job.failed
Download Result File
Once a job is in the completed
status, you can use the download_url
returned when retrieving a job to download the Result File.
- cURL
- Javascript
curl -o "output-file-name" "https://bt-prod-us-east-2-account-updater-data.s3.us-east-2.amazonaws.com/..."
await axios.get("https://bt-prod-us-east-2-account-updater-data.s3.us-east-2.amazonaws.com/...", {responseType: 'stream'})
.then(response => {
// Create a write stream to save the file
const writer = fs.createWriteStream("completed.csv");
// Pipe the response stream into the write stream
response.data.pipe(writer);
// Return a promise that resolves when the file has been downloaded
return new Promise((resolve, reject) => {
writer.on('finish', resolve);
writer.on('error', reject);
});
})
File Format Specifications
Request File Format
Account Updater request CSV files must use the following format:
token,expiration_year,expiration_month,merchant_id
d2cbc1b4-5c3a-45a3-9ee2-392a1c475ab4,,,
f32bc1b4-5c3a-45a3-9ee2-392a1c475d53,30,02,
Properties
Property | Definition | Required |
---|---|---|
token | A card token to be updated. The expiration date in this token is optional, and if present, will be sent to the networks when requesting updates. | true |
expiration_year | (Optional) The 2-digit expiration year of the account number. This is not required if the card token has expiration_year stored. | false |
expiration_month | (Optional) The 2-digit expiration month of the account number. This is not required if the card token has expiration_month stored. | false |
merchant_id | (Optional) The merchant identifier (if provided by Basis Theory) under which this update request is submitted | false |
Certain Account Updater configurations may require a merchant_id
to be submitted in the request file.
During Account Updater onboarding, Basis Theory will identify whether a merchant_id
is required for your tenant. If required, Basis Theory will provide these values to you during onboarding.
If you wish to test Account Updater within a test tenant, you can submit a request file containing a merchant_id
value of SANDBOX
or leave the value empty.
Result File Format
The result file is used to communicate any tokens created as a result of an updated account number or expiration date. This file only includes rows that resulted in a successful update, a warning, or an error (see Result Codes for details). Rows that did not result in any updates are omitted from the result file.
Account Updater result CSV files will use the following format:
token,expiration_year,expiration_month,new_token,new_expiration_year,new_expiration_month,result_code
d2cbc1b4-5c3a-45a3-9ee2-392a1c475ab4,,,b2cbc1b4-5c3a-45a3-9ee2-392a1c475ab4,,,UPD_PAN
f32bc1b4-5c3a-45a3-9ee2-392a1c475d53,30,02,,,,WRN_CLOSED_ACCOUNT
Properties
Property | Definition | Always Returned |
---|---|---|
token | The card token to be updated, as sent in the request file | true |
expiration_month | The expiration_month that was sent in the request file. | false |
expiration_year | The expiration year that was originally sent. | false |
new_token | The new card token created with updated card details. Update any references to this token in your systems. | false (only on successful update) |
new_expiration_month | The new expiration month returned from the update. | false |
new_expiration_year | The new expiration year returned from the update. | false |
result_code | Code summarizing the processing status of the row. See Result Codes below for details. | true |
Result Codes
Code Prefixes
Prefix | Description |
---|---|
UPD | A update was received from the network; update your records with the updated token. |
WRN | The token was correctly processed, although it did not result in an update. Action is potentially required. |
ERR | An error occurred while processing the file or token, requiring action. |
Result Codes
Result Code | Description | Action |
---|---|---|
UPD_PAN | The issuer updated the account number, or account number and expiration date. | A new token has been created. Update your records. |
UPD_EXP_DATE | The issuer updated the expiration date. | A new token has been created. Update your records. |
UPD_BRAND_CONV | The card brand has changed but the issuer remains the same. The account number or expiration may or may not be changed. | If a new token has been created, update your records. |
UPD_CORRECTED | The issuer corrected a previous update. | A new token has been created. Update your records. |
WRN_CLOSED_ACCOUNT | The issuer closed the account holder’s account. | Exclude the token from future account updater requests. |
WRN_CONTACT_CARDHOLDER | The merchant should contact the account holder for additional information on the account. | No Update - Reach out |
WRN_ISSUER_NOT_ENROLLED | The issuer for the requested card number does not participate in the Account Updater program. | No update - consider removing this token from future requests. |
WRN_ISSUER_NO_DATA | The issuer provided no information regarding the specific card number requested. | No update - consider removing this token from future requests. |
WRN_OPT_OUT | The cardholder has opted out of the account updater service. | No update - consider removing this token from future requests. |
WRN_UNSUPPORTED_NETWORK | The card number corresponds to a card network that does not participate in the Account Updater program. | No update - consider removing this token from future requests. |
ERR_UNDEFINED | Undefined error. | Contact support. |
ERR_INVALID_PAN | The card number is invalid. | Check that this token contains a valid card number for one of the supported networks (Visa, Mastercard, American Express, or Discover). Omit from future requests. |
ERR_INVALID_TOKEN | Token not found. | Check that the token is of type card and that the token exists in this tenant. |
ERR_INVALID_EXP_DATE | The expiration date was invalid. | Check expiration month and year exist on the token or in the row's expiration_month and expiration_year fields |
ERR_INVALID_CONFIG | Invalid Account Updater configuration. | Verify that the merchant_id matches the one given to you during onboarding. If your merchant_id matches, contact support. |
Testing
Basis Theory provides an Account Updater sandbox that provides stubbed responses without forwarding your requests to the card networks for updates. Test tenants are automatically configured to use the Account Updater sandbox, and you can use the test cards defined below to simulate scenarios that result in an expected Result Code.
Test Cards
PAN | Exp. Month | Exp. Year | Result Code | Update Details |
---|---|---|---|---|
4111111111111111 | 12 | 2023 | UPD_PAN | 4166676667666746 |
6011690151507086 | 12 | 2023 | UPD_EXP_DATE | 12/2026 |
6011760519541711 | 12 | 2023 | UPD_BRAND_CONV | N/A |
6011490740263725 | 12 | 2023 | UPD_CORRECTED | N/A |
5461310156953048 | 12 | 2023 | WRN_CLOSED_ACCOUNT | N/A |
4929980395567582 | 12 | 2023 | WRN_CONTACT_CARDHOLDER | N/A |
4916725297925395 | 12 | 2023 | WRN_ISSUER_NO_DATA | N/A |
5580422612666704 | 12 | 2023 | WRN_ISSUER_NOT_ENROLLED | N/A |
4035501000000008 | 12 | 2023 | WRN_OPT_OUT | N/A |
201400000000009 | 12 | 2023 | WRN_UNSUPPORTED_NETWORK | N/A |
6011178332216017 | 12 | 2023 | ERR_UNDEFINED | N/A |
6011648103759866 | 12 | 2023 | ERR_INVALID_EXP_DATE | N/A |
378025849667382 | 12 | 2023 | ERR_INVALID_PAN | N/A |
370000000000002 | 12 | 2023 | ERR_INVALID_CONFIG | N/A |
4711358892785746 | 12 | 2023 | (No change and not returned in file) | N/A |
Code Sample to generate test card tokens
Since Account Updater request files accept a card
token as input, you will first need to tokenize the Test Cards defined above.
You can use the following snippet to quickly generate test card tokens for use in your test requests.
#You will need an API Key with `token:create`
curl --location 'api.flock-dev.com/tokenize' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'BT-API-KEY: <BT API KEY>' \
--data '[
{
"type": "card",
"data": {
"number": 4111111111111111,
"expiration_month": "12",
"expiration_year": "2023"
}
},
{
"type": "card",
"data": {
"number": 6011690151507086,
"expiration_month": "12",
"expiration_year": "2023"
}
},
{
"type": "card",
"data": {
"number": 6011760519541711,
"expiration_month": "12",
"expiration_year": "2023"
}
},
{
"type": "card",
"data": {
"number": 6011490740263725,
"expiration_month": "12",
"expiration_year": "2023"
}
},
{
"type": "card",
"data": {
"number": 5461310156953048,
"expiration_month": "12",
"expiration_year": "2023"
}
},
{
"type": "card",
"data": {
"number": 4929980395567582,
"expiration_month": "12",
"expiration_year": "2023"
}
},
{
"type": "card",
"data": {
"number": 4916725297925395,
"expiration_month": "12",
"expiration_year": "2023"
}
},
{
"type": "card",
"data": {
"number": 5580422612666704,
"expiration_month": "12",
"expiration_year": "2023"
}
},
{
"type": "card",
"data": {
"number": 4035501000000008,
"expiration_month": "12",
"expiration_year": "2023"
}
},
{
"type": "card",
"data": {
"number": 4711358892785746,
"expiration_month": "12",
"expiration_year": "2023"
}
},
{
"type": "card",
"data": {
"number": 6011178332216017,
"expiration_month": "12",
"expiration_year": "2023"
}
},
{
"type": "card",
"data": {
"number": 6011648103759866,
"expiration_month": "12",
"expiration_year": "2023"
}
},
{
"type": "card",
"data": {
"number": 378025849667382,
"expiration_month": "12",
"expiration_year": "2023"
}
},
{
"type": "card",
"data": {
"number": 370000000000002,
"expiration_month": "12",
"expiration_year": "2023"
}
},
{
"type": "card",
"data": {
"number": 201400000000009,
"expiration_month": "12",
"expiration_year": "2023"
}
}
]
'
Resources
Account Updater Job
Property | Type | Description |
---|---|---|
id | string | Identifier for the account updater job |
tenant_id | uuid | The tenant this job is associated with |
status | string | The job status, values include: failed , completed , pending , processing |
expires_at | datetime | Time the upload URL will expire. This property is only returned while the job is in the pending status. |
created_by | uuid | The id of the application used to create the job |
created_at | datetime | Timestamp when this job was created |
upload_url | string | The URL to which the Request File should be uploaded. This will only be returned when the job is in the pending status. |
errors | array<string> | An array of error messages encountered when attempting to process the job |
download_url | string | The URL to download the Result File. This will only be returned when the job is in the completed status. |