Update Application Profile
Overview
Update an existing Application Profile to modify fee profile associations, risk profile settings, or metadata tags. Configure pricing and risk management for merchant onboarding.
Resource Access
- User Permissions: Admin users only
- Endpoint:
PUT /application_profiles/\{application_profile_id}
Arguments
| Parameter | Type | Required | Description |
|---|---|---|---|
| application_profile_id | string | Yes | The ID of the Application Profile to update |
| fee_profile | string | No | ID of the card-not-present fee profile |
| card_present_fee_profile | string | No | ID of the card-present fee profile |
| risk_profile | string | No | ID of the risk profile |
| tags | object | No | Key-value metadata (up to 50 pairs, max 40 chars for keys, max 500 chars for values) |
Example Requests
Update Fee Profile
curl -X PUT \
'https://api.ahrvo.network/payments/na/application_profiles/PPqCt5m7AFobHUQsKxqkCEyT' \
-u username:password \
-H 'Content-Type: application/json' \
-d '{
"fee_profile": "FP9Z8XYC45rUuS1fLTOoS6Rh"
}'
Add Card-Present Fee Profile
curl -X PUT \
'https://api.ahrvo.network/payments/na/application_profiles/PPqCt5m7AFobHUQsKxqkCEyT' \
-u username:password \
-H 'Content-Type: application/json' \
-d '{
"card_present_fee_profile": "CP4Y2GMB34qTtQ0eKSNnR5Qg"
}'
Update Risk Profile
curl -X PUT \
'https://api.ahrvo.network/payments/na/application_profiles/PPqCt5m7AFobHUQsKxqkCEyT' \
-u username:password \
-H 'Content-Type: application/json' \
-d '{
"risk_profile": "RP2W7VXB23pSsP8cIQLoP3Pf"
}'
Update Tags
curl -X PUT \
'https://api.ahrvo.network/payments/na/application_profiles/PPqCt5m7AFobHUQsKxqkCEyT' \
-u username:password \
-H 'Content-Type: application/json' \
-d '{
"tags": {
"environment": "production",
"region": "us-west",
"merchant_type": "retail",
"updated_by": "admin"
}
}'
Update Multiple Fields
curl -X PUT \
'https://api.ahrvo.network/payments/na/application_profiles/PPqCt5m7AFobHUQsKxqkCEyT' \
-u username:password \
-H 'Content-Type: application/json' \
-d '{
"fee_profile": "FP9Z8XYC45rUuS1fLTOoS6Rh",
"card_present_fee_profile": "CP4Y2GMB34qTtQ0eKSNnR5Qg",
"risk_profile": "RP2W7VXB23pSsP8cIQLoP3Pf",
"tags": {
"environment": "production",
"region": "us-west",
"merchant_type": "retail"
}
}'
Example Response
{
"id": "PPqCt5m7AFobHUQsKxqkCEyT",
"created_at": "2024-11-14T22:25:06.78Z",
"updated_at": "2024-12-10T15:30:00.00Z",
"application": "APc9vhYcPsRuTSpKD9KpMtPe",
"card_present_fee_profile": "CP4Y2GMB34qTtQ0eKSNnR5Qg",
"fee_profile": "FP9Z8XYC45rUuS1fLTOoS6Rh",
"risk_profile": "RP2W7VXB23pSsP8cIQLoP3Pf",
"tags": {
"environment": "production",
"region": "us-west",
"merchant_type": "retail"
},
"_links": {
"self": {
"href": "https://api.ahrvo.network/payments/na/application_profiles/PPqCt5m7AFobHUQsKxqkCEyT"
},
"application": {
"href": "https://api.ahrvo.network/payments/na/applications/APc9vhYcPsRuTSpKD9KpMtPe"
},
"risk_profile": {
"href": "https://api.ahrvo.network/payments/na/risk_profiles/RP2W7VXB23pSsP8cIQLoP3Pf"
},
"fee_profile": {
"href": "https://api.ahrvo.network/payments/na/fee_profiles/FP9Z8XYC45rUuS1fLTOoS6Rh"
},
"card_present_fee_profile": {
"href": "https://api.ahrvo.network/payments/na/fee_profiles/CP4Y2GMB34qTtQ0eKSNnR5Qg"
}
}
}
Additional Information
-
Partial Updates: Only send what changes
- Send only fields to update
- Other fields remain unchanged
- More efficient than full replacement
- Reduces errors
-
Application ID: Read-only
- Cannot change application association
- Set only on creation
- Profile permanently linked to application
- Create new profile to change application
-
Fee Profiles: Pricing configuration
- fee_profile: Card-not-present (CNP) pricing
- Online payments
- Mobile payments
- Phone orders
- card_present_fee_profile: Card-present (CP) pricing
- In-person card swipes
- POS terminals
- Chip card reads
- Can update either or both
- Affects all merchants using this profile
- fee_profile: Card-not-present (CNP) pricing
-
Risk Profile: Risk management
- Controls transaction limits
- Defines velocity rules
- Sets review thresholds
- Required field
- Cannot be null
- Update to change risk settings
-
Tags: Metadata management
- Replaces entire tags object (not merged)
- Must send all tags you want to keep
- Omitted tags are removed
- Up to 50 key-value pairs
- Keys: max 40 characters
- Values: max 500 characters
- Use for organization and filtering
-
Updated Timestamp: Changes on update
updated_atreflects last modificationcreated_atnever changes- ISO 8601 format
- UTC timezone
- Track configuration changes
-
Impact on Merchants: Immediate effect
- All merchants using this profile affected
- New pricing applies to new transactions
- Risk rules apply immediately
- Test changes carefully
- Consider creating new profile instead
Use Cases
Change Pricing Structure
// Update fee profile to change merchant pricing
async function updatePricing(profileId, newFeeProfileId) {
console.log('Updating pricing structure...');
// Get current config
const current = await fetchProfile(profileId);
console.log(`Current CNP fee profile: ${current.fee_profile}`);
// Update to new fee profile
const response = await fetch(
`https://api.ahrvo.network/payments/na/application_profiles/${profileId}`,
{
method: 'PUT',
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
},
body: JSON.stringify({
fee_profile: newFeeProfileId
})
}
);
const updated = await response.json();
console.log(`✓ Updated to fee profile: ${updated.fee_profile}`);
console.log('Note: All merchants using this profile will have new pricing');
return updated;
}
Add Card-Present Support
// Enable card-present transactions for profile
async function enableCardPresent(profileId, cpFeeProfileId) {
const response = await fetch(
`https://api.ahrvo.network/payments/na/application_profiles/${profileId}`,
{
method: 'PUT',
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
},
body: JSON.stringify({
card_present_fee_profile: cpFeeProfileId
})
}
);
const updated = await response.json();
console.log('✓ Card-present fee profile added');
console.log(`CNP Fee: ${updated.fee_profile}`);
console.log(`CP Fee: ${updated.card_present_fee_profile}`);
console.log('Merchants can now process card-present transactions');
return updated;
}
Update Risk Settings
// Change risk profile to adjust limits
async function updateRiskSettings(profileId, newRiskProfileId) {
console.log('Updating risk profile...');
const response = await fetch(
`https://api.ahrvo.network/payments/na/application_profiles/${profileId}`,
{
method: 'PUT',
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
},
body: JSON.stringify({
risk_profile: newRiskProfileId
})
}
);
const updated = await response.json();
console.log(`✓ Risk profile updated to: ${updated.risk_profile}`);
console.log('Note: New risk rules apply immediately to all merchants');
return updated;
}
Add Organization Tags
// Add tags without losing existing ones
async function addTags(profileId, newTags) {
// Get current tags
const current = await fetchProfile(profileId);
// Merge with new tags
const mergedTags = {
...current.tags,
...newTags
};
const response = await fetch(
`https://api.ahrvo.network/payments/na/application_profiles/${profileId}`,
{
method: 'PUT',
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
},
body: JSON.stringify({
tags: mergedTags
})
}
);
const updated = await response.json();
console.log('✓ Tags updated');
console.log('Current tags:', updated.tags);
return updated;
}
// Usage
await addTags('PPqCt5m7AFobHUQsKxqkCEyT', {
updated_by: 'admin',
last_review: '2024-12-10'
});
Remove Card-Present Fee Profile
// Remove card-present fee profile
async function removeCardPresent(profileId) {
console.warn('Removing card-present fee profile...');
const response = await fetch(
`https://api.ahrvo.network/payments/na/application_profiles/${profileId}`,
{
method: 'PUT',
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
},
body: JSON.stringify({
card_present_fee_profile: null
})
}
);
const updated = await response.json();
console.log('✓ Card-present fee profile removed');
console.log('Merchants using this profile can no longer process card-present transactions');
return updated;
}
Migrate Profile Configuration
// Migrate from one fee/risk profile to another
async function migrateProfileConfig(profileId, newFeeProfile, newRiskProfile) {
console.log('Migrating profile configuration...');
// Get current config
const current = await fetchProfile(profileId);
console.log('Current configuration:');
console.log(` CNP Fee: ${current.fee_profile}`);
console.log(` CP Fee: ${current.card_present_fee_profile || 'None'}`);
console.log(` Risk: ${current.risk_profile}`);
// Update to new config
const response = await fetch(
`https://api.ahrvo.network/payments/na/application_profiles/${profileId}`,
{
method: 'PUT',
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
},
body: JSON.stringify({
fee_profile: newFeeProfile,
risk_profile: newRiskProfile,
tags: {
...current.tags,
migrated_at: new Date().toISOString(),
previous_fee_profile: current.fee_profile,
previous_risk_profile: current.risk_profile
}
})
}
);
const updated = await response.json();
console.log('\n✓ Migration complete');
console.log('New configuration:');
console.log(` CNP Fee: ${updated.fee_profile}`);
console.log(` Risk: ${updated.risk_profile}`);
console.log('Migration tracked in tags');
return updated;
}
Update Multiple Profiles
// Bulk update multiple profiles
async function bulkUpdateProfiles(profileIds, changes) {
console.log(`Updating ${profileIds.length} profiles...`);
const results = await Promise.all(
profileIds.map(async (id) => {
const response = await fetch(
`https://api.ahrvo.network/payments/na/application_profiles/${id}`,
{
method: 'PUT',
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
},
body: JSON.stringify(changes)
}
);
return response.json();
})
);
console.log(`✓ Updated ${results.length} profiles`);
return results;
}
// Example: Update risk profile for all retail profiles
const retailProfiles = ['PP123', 'PP456', 'PP789'];
await bulkUpdateProfiles(retailProfiles, {
risk_profile: 'RP_RETAIL_STANDARD'
});
Best Practices
-
Fetch Before Update: Verify current state
async function safeUpdate(profileId, changes) {
// Get current state
const current = await fetchProfile(profileId);
console.log('Current state:', current);
console.log('Proposed changes:', changes);
// Verify changes make sense
if (changes.risk_profile === null) {
console.error('✗ Cannot remove risk profile (required)');
return null;
}
// Apply update
const response = await fetch(
`https://api.ahrvo.network/payments/na/application_profiles/${profileId}`,
{
method: 'PUT',
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
},
body: JSON.stringify(changes)
}
);
return response.json();
} -
Tags Management: Preserve existing tags
// Good - merge tags
const current = await fetchProfile(profileId);
await updateProfile(profileId, {
tags: {
...current.tags, // Keep existing
new_tag: 'value' // Add new
}
});
// Bad - lose existing tags
await updateProfile(profileId, {
tags: {
new_tag: 'value' // All other tags lost!
}
}); -
Verify After Update: Confirm changes applied
async function verifyUpdate(profileId, expectedChanges) {
const updated = await fetchProfile(profileId);
Object.entries(expectedChanges).forEach(([key, value]) => {
if (JSON.stringify(updated[key]) !== JSON.stringify(value)) {
console.error(`✗ ${key} did not update correctly`);
} else {
console.log(`✓ ${key} updated successfully`);
}
});
} -
Impact Assessment: Consider affected merchants
- How many merchants use this profile?
- What changes for them?
- Test in staging first
- Notify merchants if needed
- Have rollback plan
-
Document Changes: Track modifications
async function documentedUpdate(profileId, changes, reason) {
const current = await fetchProfile(profileId);
// Add audit trail to tags
const updatedTags = {
...current.tags,
last_updated: new Date().toISOString(),
update_reason: reason
};
const response = await fetch(
`https://api.ahrvo.network/payments/na/application_profiles/${profileId}`,
{
method: 'PUT',
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
},
body: JSON.stringify({
...changes,
tags: updatedTags
})
}
);
console.log('Update documented in tags');
return response.json();
} -
Gradual Changes: Update incrementally
- Don't change fee and risk profiles simultaneously
- Update one setting at a time
- Verify each change
- Easier to troubleshoot
Common Workflows
Pricing Update Workflow
// Safely update pricing with verification
async function updatePricingWorkflow(profileId, newFeeProfileId) {
console.log('=== Pricing Update Workflow ===\n');
// Step 1: Get current config
console.log('Step 1: Fetching current configuration...');
const current = await fetchProfile(profileId);
console.log(`Current fee profile: ${current.fee_profile}`);
// Step 2: Verify new fee profile exists
console.log('\nStep 2: Verifying new fee profile...');
const feeProfileResponse = await fetch(
`https://api.ahrvo.network/payments/na/fee_profiles/${newFeeProfileId}`,
{
headers: {
'Authorization': 'Basic ' + btoa('username:password')
}
}
);
if (!feeProfileResponse.ok) {
console.error('✗ New fee profile not found');
return null;
}
console.log('✓ New fee profile exists');
// Step 3: Update profile
console.log('\nStep 3: Updating profile...');
const response = await fetch(
`https://api.ahrvo.network/payments/na/application_profiles/${profileId}`,
{
method: 'PUT',
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
},
body: JSON.stringify({
fee_profile: newFeeProfileId,
tags: {
...current.tags,
pricing_updated: new Date().toISOString(),
previous_fee_profile: current.fee_profile
}
})
}
);
const updated = await response.json();
console.log('✓ Profile updated');
// Step 4: Verify update
console.log('\nStep 4: Verifying update...');
const verified = await fetchProfile(profileId);
if (verified.fee_profile === newFeeProfileId) {
console.log('✓ Update verified successfully');
} else {
console.error('✗ Update verification failed');
}
console.log('\n=== Update Complete ===');
return updated;
}
Tag Cleanup Workflow
// Clean up and organize tags
async function cleanupTags(profileId) {
const current = await fetchProfile(profileId);
console.log('Current tags:', current.tags);
// Define allowed tags
const allowedTagKeys = [
'environment',
'region',
'merchant_type',
'created_by',
'updated_by',
'last_review'
];
// Filter to allowed tags only
const cleanedTags = {};
Object.entries(current.tags).forEach(([key, value]) => {
if (allowedTagKeys.includes(key)) {
cleanedTags[key] = value;
} else {
console.log(`Removing tag: ${key}`);
}
});
const response = await fetch(
`https://api.ahrvo.network/payments/na/application_profiles/${profileId}`,
{
method: 'PUT',
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
},
body: JSON.stringify({
tags: cleanedTags
})
}
);
const updated = await response.json();
console.log('Cleaned tags:', updated.tags);
return updated;
}
Profile Standardization
// Standardize all profiles to use same risk profile
async function standardizeRiskProfile(targetRiskProfileId) {
// Get all profiles
const listResponse = await fetch(
'https://api.ahrvo.network/payments/na/application_profiles?limit=100',
{
headers: {
'Authorization': 'Basic ' + btoa('username:password')
}
}
);
const data = await listResponse.json();
const profiles = data._embedded.application_profiles;
// Find profiles with different risk profile
const toUpdate = profiles.filter(p =>
p.risk_profile !== targetRiskProfileId
);
console.log(`Found ${toUpdate.length} profiles to standardize`);
// Update each profile
for (const profile of toUpdate) {
console.log(`Updating ${profile.id}...`);
await fetch(
`https://api.ahrvo.network/payments/na/application_profiles/${profile.id}`,
{
method: 'PUT',
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
},
body: JSON.stringify({
risk_profile: targetRiskProfileId,
tags: {
...profile.tags,
risk_profile_standardized: new Date().toISOString()
}
})
}
);
console.log(`✓ Updated ${profile.id}`);
}
console.log('✓ All profiles standardized');
}
Security Considerations
-
Impact Assessment: Major changes
- Profile updates affect ALL merchants using it
- Fee profile changes alter merchant pricing
- Risk profile changes modify transaction limits
- Test thoroughly before updating production
-
Audit Trail: Track changes
- Use tags to document updates
- Log who made changes
- Track previous values
- Monitor
updated_attimestamp
-
Permissions: Restrict access
- Only admin users can update
- Audit who has access
- Monitor update activity
- Review changes regularly
-
Rollback Plan: Prepare for issues
- Store previous configuration
- Can update back if needed
- Test in staging first
- Have emergency contacts
-
Risk Profile: Cannot be null
- Required field
- Cannot remove risk profile
- Must always have valid risk settings
- Update will fail if set to null
Error Responses
Profile Not Found
{
"status": 404,
"message": "Application Profile not found"
}
- Invalid profile ID
- Profile was deleted
- Wrong environment
Invalid Fee Profile
{
"status": 400,
"message": "Invalid fee profile",
"details": "Fee profile FPinvalid does not exist"
}
- Fee profile ID doesn't exist
- Check fee profile is valid
- Verify environment
Invalid Risk Profile
{
"status": 400,
"message": "Invalid risk profile",
"details": "Risk profile cannot be null"
}
- Risk profile is required
- Cannot set to null
- Must provide valid risk profile ID
Invalid Tags
{
"status": 400,
"message": "Invalid tags",
"details": "Tag key exceeds 40 character limit"
}
- Tag key too long (max 40 chars)
- Tag value too long (max 500 chars)
- Too many tags (max 50 pairs)
- Invalid tag format
Unprocessable Entity
{
"status": 422,
"message": "Update failed",
"details": "Cannot update profile in use by active merchants"
}
- Profile locked
- May have business rule preventing update
- Contact support
Troubleshooting
Update Not Applied
- Check response for errors
- Verify profile ID correct
- Fetch profile to confirm
- Check
updated_attimestamp
Tags Disappeared
- Tags are replaced, not merged
- Must send all tags you want to keep
- Fetch current tags first
- Merge with new tags before updating
Can't Change Application
- Application is read-only
- Cannot change after creation
- Create new profile if needed
- Link to different application
Risk Profile Required Error
- Cannot set risk_profile to null
- Must always have risk profile
- Provide valid risk profile ID
- Required for all profiles
Related Endpoints
- GET /application_profiles: List all profiles
- GET /application_profiles/{id}: Fetch profile details
- GET /fee_profiles: List fee profiles
- GET /risk_profiles: List risk profiles
- GET /applications: List applications