Skip to main content

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

ParameterTypeRequiredDescription
application_profile_idstringYesThe ID of the Application Profile to update
fee_profilestringNoID of the card-not-present fee profile
card_present_fee_profilestringNoID of the card-present fee profile
risk_profilestringNoID of the risk profile
tagsobjectNoKey-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
  • 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_at reflects last modification
    • created_at never 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_at timestamp
  • 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_at timestamp

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
  • 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