Update 3DS Contact Information
Overview
Use this endpoint to update a cardholder's contact information for 3D Secure authentication. This includes updating the mobile number, email address, date of birth, address, country, and security questions. All updated information will be used for OTP delivery and verification during 3DS transactions.
NOTE: This API is offered on a client-by-client approval basis. Speak to your account manager to check eligibility.
Resource Access
Production (api.ahrvo.network)
POST https://api.ahrvo.network/card/issuance/api/issuing/cardholders/v2/update
Staging (gateway.ahrvo.network)
POST https://gateway.ahrvo.network/card/issuance/api/issuing/cardholders/v2/update
Request Headers
| Header | Value | Required | Description |
|---|---|---|---|
Accept | application/json | Yes | Content type for the response |
Authorization | Bearer {access_token} | Yes | Bearer token for authentication |
x-api-key | API Key | Yes | API key for authentication |
Content-Type | application/json | Yes | Request body content type |
Request Body
The request body should contain a JSON object with the following structure:
{
"cardholder_id": "471041678120300545",
"call_prefix": "+1",
"mobile": "2125551234",
"email": "emma.johnson.updated@example.com",
"date_of_birth": "1996-10-31",
"state": "Illinois",
"city": "Chicago",
"address_line": "789 Oak Street",
"post_code": "60601",
"country_code": "US",
"security_index": "2",
"security_answer": "Smith"
}
Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
cardholder_id | string | Yes | A unique ID of the cardholder to update |
call_prefix | string | Yes | Country code of the mobile. Supported: +61, +1, +44, +852, +81, +82, +65, +90, +86, +33 |
mobile | string | Yes | Mobile number of the cardholder, without country code |
email | string | Yes | Email of the cardholder |
date_of_birth | string | Yes | Date of birth of the cardholder (YYYY-MM-DD) |
address_line | string | Yes | Address of the cardholder |
city | string | Yes | City of the cardholder |
state | string | Yes | State of the cardholder |
post_code | string | Yes | Post code of the cardholder |
country_code | string | Yes | Country of the cardholder in ISO 3166 format (e.g., US) |
security_index | string | Yes | Index of security question (1-5) |
security_answer | string | Yes | Answer to the security question |
Security Questions
The security_index field corresponds to the following questions:
| Index | Security Question |
|---|---|
1 | What was your first pet's name? |
2 | What is your maternal grandmother's maiden name? |
3 | What is the name of your favourite childhood friend? |
4 | What was the make of your first car? |
5 | In what city or town did your mother and father meet? |
Supported Country Codes (call_prefix)
+1- United States, Canada+33- France+44- United Kingdom+61- Australia+65- Singapore+81- Japan+82- South Korea+86- China+90- Turkey+852- Hong Kong
Response
Success Response (200 OK)
{
"code": "SUCCESS"
}
Response Fields
| Field | Type | Description |
|---|---|---|
code | string | Status string indicating the result. "SUCCESS" refers to successful update |
Error Responses
- 400 Bad Request: Invalid input data, missing required fields, or invalid email/mobile format
- 401 Unauthorized: Invalid or missing authentication token
- 403 Forbidden: 3DS feature not enabled for this account
- 404 Not Found: Cardholder does not exist
Code Examples
cURL
curl -X POST \
'https://gateway.ahrvo.network/card/issuance/api/issuing/cardholders/v2/update' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"cardholder_id": "471041678120300545",
"call_prefix": "+1",
"mobile": "2125551234",
"email": "emma.johnson.updated@example.com",
"date_of_birth": "1996-10-31",
"state": "Illinois",
"city": "Chicago",
"address_line": "789 Oak Street",
"post_code": "60601",
"country_code": "US",
"security_index": "2",
"security_answer": "Smith"
}'
Python
import requests
url = "https://gateway.ahrvo.network/card/issuance/api/issuing/cardholders/v2/update"
headers = {
"Accept": "application/json",
"Authorization": "Bearer YOUR_ACCESS_TOKEN",
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json"
}
data = {
"cardholder_id": "471041678120300545",
"call_prefix": "+1",
"mobile": "2125551234",
"email": "emma.johnson.updated@example.com",
"date_of_birth": "1996-10-31",
"state": "Illinois",
"city": "Chicago",
"address_line": "789 Oak Street",
"post_code": "60601",
"country_code": "US",
"security_index": "2",
"security_answer": "Smith"
}
response = requests.post(url, headers=headers, json=data)
print(response.json())
JavaScript (Node.js)
const axios = require('axios');
const url = 'https://gateway.ahrvo.network/card/issuance/api/issuing/cardholders/v2/update';
const headers = {
'Accept': 'application/json',
'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
};
const data = {
cardholder_id: '471041678120300545',
call_prefix: '+1',
mobile: '2125551234',
email: 'emma.johnson.updated@example.com',
date_of_birth: '1996-10-31',
state: 'Illinois',
city: 'Chicago',
address_line: '789 Oak Street',
post_code: '60601',
country_code: 'US',
security_index: '2',
security_answer: 'Smith'
};
axios.post(url, data, { headers })
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error.response.data);
});
Usage Notes
- All Fields Required: This endpoint requires all fields to be provided, even if only updating one field
- Complete Replacement: All values will be replaced with the new data provided in the request
- Email & Mobile Critical: These fields are used for OTP delivery during 3DS transactions
- Immediate Effect: Changes take effect immediately for all enrolled cards
- Validation: Email and mobile number formats are validated before update
- Security Question: You can change both the security question and answer
Common Use Cases
Update Email Address
When a cardholder changes their email:
def update_cardholder_email(cardholder_id, new_email):
# First, get current cardholder details
current_data = query_cardholder_details(cardholder_id)
# Update only the email, keep other fields the same
update_data = {
"cardholder_id": cardholder_id,
"email": new_email,
"call_prefix": current_data['call_prefix'],
"mobile": current_data['mobile'],
"date_of_birth": current_data['date_of_birth'],
"state": current_data['state'],
"city": current_data['city'],
"address_line": current_data['address_line'],
"post_code": current_data['post_code'],
"country_code": current_data['country_code'],
"security_index": current_data['security_index'],
"security_answer": current_data['security_answer']
}
response = update_3ds_contact(update_data)
return response
Update Mobile Number
When a cardholder gets a new phone number:
async function updateCardholderMobile(cardholderId, newCallPrefix, newMobile) {
// Get current cardholder data
const currentData = await queryCardholderDetails(cardholderId);
// Update mobile fields
const updateData = {
cardholder_id: cardholderId,
call_prefix: newCallPrefix,
mobile: newMobile,
email: currentData.email,
date_of_birth: currentData.date_of_birth,
state: currentData.state,
city: currentData.city,
address_line: currentData.address_line,
post_code: currentData.post_code,
country_code: currentData.country_code,
security_index: currentData.security_index,
security_answer: currentData.security_answer
};
return await update3DSContact(updateData);
}
Update Address Information
When a cardholder moves to a new address:
async function updateCardholderAddress(cardholderId, newAddress) {
const currentData = await queryCardholderDetails(cardholderId);
const updateData = {
cardholder_id: cardholderId,
address_line: newAddress.address_line,
city: newAddress.city,
state: newAddress.state,
post_code: newAddress.post_code,
country_code: newAddress.country_code,
// Keep existing contact info
call_prefix: currentData.call_prefix,
mobile: currentData.mobile,
email: currentData.email,
date_of_birth: currentData.date_of_birth,
security_index: currentData.security_index,
security_answer: currentData.security_answer
};
return await update3DSContact(updateData);
}
Update Security Question
When a cardholder wants to change their security question:
def update_security_question(cardholder_id, new_security_index, new_security_answer):
current_data = query_cardholder_details(cardholder_id)
update_data = {
"cardholder_id": cardholder_id,
"security_index": new_security_index,
"security_answer": new_security_answer,
# Keep all other fields the same
"call_prefix": current_data['call_prefix'],
"mobile": current_data['mobile'],
"email": current_data['email'],
"date_of_birth": current_data['date_of_birth'],
"state": current_data['state'],
"city": current_data['city'],
"address_line": current_data['address_line'],
"post_code": current_data['post_code'],
"country_code": current_data['country_code']
}
return update_3ds_contact(update_data)
Bulk Update with Validation
Update multiple cardholders with proper validation:
def bulk_update_cardholders(updates):
results = {
'success': [],
'failed': []
}
for update in updates:
try:
# Validate email format
if not is_valid_email(update['email']):
raise ValueError(f"Invalid email format: {update['email']}")
# Validate mobile number
if not is_valid_mobile(update['call_prefix'], update['mobile']):
raise ValueError(f"Invalid mobile number")
# Perform update
response = update_3ds_contact(update)
if response['code'] == 'SUCCESS':
results['success'].append(update['cardholder_id'])
else:
results['failed'].append({
'cardholder_id': update['cardholder_id'],
'error': response.get('message', 'Unknown error')
})
except Exception as e:
results['failed'].append({
'cardholder_id': update['cardholder_id'],
'error': str(e)
})
return results
Best Practices
- Retrieve First: Always query current cardholder details before updating to avoid data loss
- Validate Input: Validate email and mobile formats before sending the update request
- Notify Cardholder: Inform the cardholder when their contact information is updated
- Verify Update: Query the cardholder details after update to confirm changes
- Audit Trail: Log all updates for compliance and security purposes
- User Confirmation: Require user confirmation before updating critical fields like email and mobile
Update Workflow
Standard Update Process
- Query Current Data: Retrieve existing cardholder information
- Modify Fields: Change only the fields that need updating
- Validate Changes: Ensure all data is valid before submission
- Submit Update: Send the update request with all required fields
- Verify Success: Confirm the update was successful
- Notify User: Inform the cardholder of the changes
Self-Service Update Portal
async function handleCardholderUpdate(cardholderId, updatedFields) {
try {
// Step 1: Get current data
const currentData = await queryCardholderDetails(cardholderId);
// Step 2: Merge with updates
const updatePayload = {
cardholder_id: cardholderId,
...currentData.data,
...updatedFields
};
// Step 3: Validate critical fields
if (updatedFields.email && !validateEmail(updatedFields.email)) {
throw new Error('Invalid email format');
}
if (updatedFields.mobile && !validateMobile(updatedFields.mobile)) {
throw new Error('Invalid mobile number');
}
// Step 4: Update
const response = await update3DSContact(updatePayload);
// Step 5: Verify
if (response.code === 'SUCCESS') {
const verifyData = await queryCardholderDetails(cardholderId);
console.log('Update verified:', verifyData);
// Step 6: Notify
await sendUpdateNotification(cardholderId, updatedFields);
}
return response;
} catch (error) {
console.error('Update failed:', error);
throw error;
}
}
Data Validation
Email Validation
function validateEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
Mobile Validation
function validateMobile(callPrefix, mobile) {
const validPrefixes = ['+1', '+33', '+44', '+61', '+65', '+81', '+82', '+86', '+90', '+852'];
if (!validPrefixes.includes(callPrefix)) {
return false;
}
// Mobile should be digits only
const mobileRegex = /^\d+$/;
return mobileRegex.test(mobile) && mobile.length >= 7 && mobile.length <= 15;
}
Date Validation
from datetime import datetime
def validate_date_of_birth(date_str):
try:
dob = datetime.strptime(date_str, '%Y-%m-%d')
# Check if date is in the past and person is at least 18 years old
today = datetime.now()
age = today.year - dob.year - ((today.month, today.day) < (dob.month, dob.day))
return age >= 18
except ValueError:
return False
Related Endpoints
- Create Cardholder 3DS Contact - Create new cardholder profiles
- Query 3DS Contact Details - Retrieve cardholder information
- Query 3DS Enrollment Details - Check enrollment status by card
- Enroll Card for 3DS - Link cardholder to a card
Troubleshooting
Cardholder Not Found (404)
- Cause: Invalid
cardholder_idor cardholder doesn't exist - Solution: Verify the
cardholder_idis correct and the cardholder exists in your system
Invalid Email Format (400)
- Cause: Email format validation failed
- Solution: Ensure email follows standard format (user@domain.com)
Invalid Mobile Number (400)
- Cause: Mobile number format or country code is invalid
- Solution:
- Verify
call_prefixis one of the supported country codes - Ensure
mobilecontains only digits without country code - Check mobile number length is appropriate
- Verify
Missing Required Fields (400)
- Cause: One or more required fields are missing
- Solution: Ensure all 12 required fields are included in the request
Update Not Reflecting (200 but no change)
- Cause: Cached data or verification issue
- Solution: Query the cardholder details again to verify the update
Security Considerations
- Authentication Required: All update requests must include valid Bearer token and API key
- Data Encryption: All communication uses HTTPS encryption
- Sensitive Data: Security answers are stored and can be updated - handle with care
- Access Control: Implement proper authorization checks before allowing updates
- Audit Logging: Log all update operations for security and compliance
- Rate Limiting: Implement rate limiting to prevent abuse