Skip to main content

List Webhooks

Overview

Retrieve a list of all Webhooks configured for your account. View webhook URLs, enabled events, and authentication settings.

Resource Access

  • User Permissions: Admin users only
  • Endpoint: GET /webhooks

Arguments

ParameterTypeRequiredDescription
limitintegerNoNumber of results per page (default: 10, max: 100)

Example Request

curl -X GET \
'https://api.ahrvo.network/payments/na/webhooks?limit=20' \
-u username:password

Example Response

{
"_embedded": {
"webhooks": [
{
"id": "WHwebhook123",
"created_at": "2023-12-10T20:00:00Z",
"updated_at": "2023-12-10T20:00:00Z",
"url": "https://api.yourcompany.com/webhooks/finix",
"enabled": true,
"authentication": {
"type": "BEARER",
"bearer": {
"token": "your-secret-bearer-token"
}
},
"enabled_events": [
{
"entity": "transfer",
"types": ["succeeded", "failed"]
}
],
"secret_signing_key": null,
"_links": {
"self": {
"href": "https://api.ahrvo.network/payments/na/webhooks/WHwebhook123"
}
}
},
{
"id": "WHwebhook124",
"created_at": "2023-12-09T15:30:00Z",
"updated_at": "2023-12-11T10:00:00Z",
"url": "https://api.yourcompany.com/webhooks/settlements",
"enabled": false,
"authentication": {
"type": "BASIC",
"basic": {
"username": "webhook_user",
"password": "secure_password"
}
},
"enabled_events": [
{
"entity": "settlement",
"types": ["funding_transfer.succeeded", "funding_transfer.failed"]
}
],
"secret_signing_key": null,
"_links": {
"self": {
"href": "https://api.ahrvo.network/payments/na/webhooks/WHwebhook124"
}
}
},
{
"id": "WHwebhook125",
"created_at": "2023-12-08T10:00:00Z",
"updated_at": "2023-12-08T10:00:00Z",
"url": "https://webhook.site/test-url",
"enabled": true,
"authentication": {
"type": "NONE"
},
"enabled_events": [],
"secret_signing_key": null,
"_links": {
"self": {
"href": "https://api.ahrvo.network/payments/na/webhooks/WHwebhook125"
}
}
}
]
},
"_links": {
"self": {
"href": "https://api.ahrvo.network/payments/na/webhooks?limit=20"
}
},
"page": {
"limit": 20,
"offset": 0,
"count": 3
}
}

Additional Information

  • No Signing Key: Not returned in list
    • secret_signing_key is always null
    • Only returned on creation
    • Cannot retrieve after creation
    • Security measure
    • Must store on creation
  • Enabled Status: Active webhooks
    • true: Webhook sends events
    • false: Webhook disabled, no events sent
    • Use to pause temporarily
    • Update via PUT /webhooks/{id}
  • URL: Webhook endpoint
    • Your server URL
    • Must be HTTPS
    • Where events are sent
    • Can be updated
  • Authentication: Endpoint security
    • NONE: No authentication
    • BASIC: HTTP Basic Auth (username/password shown)
    • BEARER: Bearer token (token shown)
    • Credentials visible in list (secure your API access)
  • Enabled Events: Event filters
    • Empty array = all events
    • Specific entities/types = filtered
    • Reduces noise
    • Shows what events this webhook receives
  • Created/Updated: Timestamps
    • ISO 8601 format
    • UTC timezone
    • created_at: Never changes
    • updated_at: Last modification
  • Multiple Webhooks: Allowed
    • Different URLs for different purposes
    • Separate dev/staging/production
    • Event-specific webhooks
    • Redundancy/failover
  • No Pagination Needed: Usually
    • Most accounts have few webhooks
    • Typically < 10 webhooks
    • Pagination available if needed

Use Cases

Audit Active Webhooks

# List all webhooks to see what's configured
curl -X GET \
'https://api.ahrvo.network/payments/na/webhooks' \
-u username:password
  • See all webhook endpoints
  • Verify URLs are correct
  • Check which are enabled
  • Review event subscriptions

Find Disabled Webhooks

// List webhooks and find disabled ones
async function findDisabledWebhooks() {
const response = await listWebhooks({ limit: 100 });
const webhooks = response._embedded.webhooks;

const disabled = webhooks.filter(w => !w.enabled);

console.log(`Disabled webhooks: ${disabled.length}`);
disabled.forEach(w => {
console.log(`- ${w.id}: ${w.url}`);
console.log(` Disabled on: ${w.updated_at}`);
console.log(` Events: ${JSON.stringify(w.enabled_events)}`);
});

return disabled;
}

Verify Production Webhooks

// Check production webhooks are active
async function verifyProductionWebhooks() {
const response = await listWebhooks({ limit: 100 });
const webhooks = response._embedded.webhooks;

const production = webhooks.filter(w =>
w.url.includes('api.yourcompany.com') ||
w.url.includes('production')
);

console.log('Production Webhooks:');
production.forEach(w => {
const status = w.enabled ? '✓' : '✗';
console.log(`${status} ${w.url}`);
console.log(` Enabled: ${w.enabled}`);
console.log(` Auth: ${w.authentication.type}`);
console.log(` Events: ${w.enabled_events.length > 0 ? 'Filtered' : 'All'}`);
});

// Alert if any production webhook is disabled
const disabledProd = production.filter(w => !w.enabled);
if (disabledProd.length > 0) {
console.error(`${disabledProd.length} production webhooks disabled!`);
}
}

Export Webhook Configuration

// Export all webhook configs for documentation
async function exportWebhookConfig() {
const response = await listWebhooks({ limit: 100 });
const webhooks = response._embedded.webhooks;

const config = webhooks.map(w => ({
id: w.id,
url: w.url,
enabled: w.enabled,
authentication: w.authentication.type,
events: w.enabled_events.length === 0
? 'All events'
: w.enabled_events.map(e => `${e.entity}:${e.types.join(',')}`).join('; '),
created: w.created_at
}));

// Export to CSV
const csv = [
'ID,URL,Enabled,Auth Type,Events,Created',
...config.map(c =>
`${c.id},"${c.url}",${c.enabled},${c.authentication},"${c.events}",${c.created}`
)
].join('\n');

return csv;
}

Find Test Webhooks

// Find webhooks pointing to test services
async function findTestWebhooks() {
const response = await listWebhooks({ limit: 100 });
const webhooks = response._embedded.webhooks;

const testUrls = [
'webhook.site',
'requestbin',
'ngrok',
'localhost',
'test',
'staging'
];

const testWebhooks = webhooks.filter(w =>
testUrls.some(test => w.url.includes(test))
);

console.log(`Test webhooks found: ${testWebhooks.length}`);
testWebhooks.forEach(w => {
console.log(`- ${w.id}: ${w.url}`);
});

return testWebhooks;
}

Group by Event Type

// See which events have webhook coverage
async function groupWebhooksByEvents() {
const response = await listWebhooks({ limit: 100 });
const webhooks = response._embedded.webhooks.filter(w => w.enabled);

const eventCoverage = {};

webhooks.forEach(webhook => {
if (webhook.enabled_events.length === 0) {
console.log(`${webhook.id}: Receives ALL events`);
} else {
webhook.enabled_events.forEach(event => {
event.types.forEach(type => {
const key = `${event.entity}.${type}`;
if (!eventCoverage[key]) {
eventCoverage[key] = [];
}
eventCoverage[key].push(webhook.url);
});
});
}
});

console.log('\nEvent Coverage:');
Object.entries(eventCoverage).forEach(([event, urls]) => {
console.log(`${event}:`);
urls.forEach(url => console.log(` - ${url}`));
});
}

Best Practices

  • Regular Audits: Review periodically

    • Monthly reviews recommended
    • Check for old/unused webhooks
    • Verify URLs still valid
    • Confirm authentication secure
    • Remove test webhooks from production
  • Document Webhooks: Keep inventory

    • What each webhook is for
    • Who owns each webhook
    • When created and why
    • Environment (dev/staging/prod)
    • Update documentation when changes made
  • Security Check: Verify authentication

    // Check all webhooks have authentication
    async function securityAudit() {
    const response = await listWebhooks({ limit: 100 });
    const webhooks = response._embedded.webhooks;

    const noAuth = webhooks.filter(w =>
    w.authentication.type === 'NONE'
    );

    if (noAuth.length > 0) {
    console.warn(`${noAuth.length} webhooks without authentication!`);
    noAuth.forEach(w => {
    console.log(` - ${w.url}`);
    });
    } else {
    console.log('✓ All webhooks have authentication');
    }
    }
  • Cleanup: Remove unused webhooks

    • Delete old test webhooks
    • Remove disabled webhooks (if no longer needed)
    • Consolidate similar webhooks
    • Reduces clutter
  • Monitoring: Track webhook status

    • Alert if production webhook disabled
    • Monitor enabled count
    • Track authentication changes
    • Audit log reviews

Common Workflows

Production Webhook Verification

  1. List all webhooks
  2. Filter for production URLs
  3. Verify all are enabled
  4. Check authentication is BEARER or BASIC
  5. Confirm event filters are correct
  6. Alert if any issues found

Cleanup Workflow

async function cleanupWebhooks() {
const response = await listWebhooks({ limit: 100 });
const webhooks = response._embedded.webhooks;

// Find test webhooks
const testWebhooks = webhooks.filter(w =>
w.url.includes('webhook.site') ||
w.url.includes('ngrok') ||
w.url.includes('localhost')
);

console.log(`Found ${testWebhooks.length} test webhooks`);

// Find disabled webhooks older than 30 days
const thirtyDaysAgo = new Date();
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);

const oldDisabled = webhooks.filter(w => {
return !w.enabled &&
new Date(w.updated_at) < thirtyDaysAgo;
});

console.log(`Found ${oldDisabled.length} webhooks disabled >30 days`);

// Review before deletion
const toDelete = [...testWebhooks, ...oldDisabled];
console.log('\nWebhooks to delete:');
toDelete.forEach(w => {
console.log(`- ${w.id}: ${w.url} (${w.enabled ? 'enabled' : 'disabled'})`);
});

return toDelete;
}

Migration Verification

// After migrating to new webhook endpoint
async function verifyMigration(oldUrl, newUrl) {
const response = await listWebhooks({ limit: 100 });
const webhooks = response._embedded.webhooks;

const oldWebhook = webhooks.find(w => w.url === oldUrl);
const newWebhook = webhooks.find(w => w.url === newUrl);

console.log('Migration Status:');
console.log(`Old webhook (${oldUrl}):`, oldWebhook ?
`Found, ${oldWebhook.enabled ? 'enabled' : 'disabled'}` :
'Not found'
);
console.log(`New webhook (${newUrl}):`, newWebhook ?
`Found, ${newWebhook.enabled ? 'enabled' : 'disabled'}` :
'Not found'
);

// Verify new webhook is enabled
if (newWebhook && newWebhook.enabled) {
console.log('✓ New webhook is active');

// Optionally disable old webhook
if (oldWebhook && oldWebhook.enabled) {
console.log('Note: Old webhook still enabled');
}
} else {
console.error('✗ New webhook not active!');
}
}

Compare Environments

// Compare webhooks across environments
async function compareEnvironments() {
// Assume different API credentials per environment
const prodWebhooks = await listWebhooks({
credentials: prodCreds
});
const stagingWebhooks = await listWebhooks({
credentials: stagingCreds
});

console.log('Production webhooks:', prodWebhooks._embedded.webhooks.length);
console.log('Staging webhooks:', stagingWebhooks._embedded.webhooks.length);

// Compare event subscriptions
const prodEvents = new Set();
const stagingEvents = new Set();

prodWebhooks._embedded.webhooks.forEach(w => {
w.enabled_events.forEach(e => {
e.types.forEach(t => prodEvents.add(`${e.entity}.${t}`));
});
});

stagingWebhooks._embedded.webhooks.forEach(w => {
w.enabled_events.forEach(e => {
e.types.forEach(t => stagingEvents.add(`${e.entity}.${t}`));
});
});

console.log('Event coverage comparison:');
console.log('Prod events:', Array.from(prodEvents).sort());
console.log('Staging events:', Array.from(stagingEvents).sort());
}

Security Considerations

  • API Access: Limit who can list

    • Only admin users
    • Shows all webhook URLs
    • Exposes authentication credentials
    • Audit access logs
  • Credentials Visible: Be aware

    • Basic auth username/password shown
    • Bearer tokens shown
    • Anyone with API access can see
    • Use strong webhook authentication
    • Rotate credentials periodically
  • Signing Keys Not Shown: By design

    • secret_signing_key always null in list
    • Cannot retrieve after creation
    • Security feature
    • Create new webhook if lost
  • Production URLs: Protect

    • Don't expose internal URLs
    • Use API gateway if possible
    • Firewall webhook endpoints
    • Monitor for unauthorized access

Troubleshooting

No Webhooks Returned

  • Check you have created webhooks
  • Verify API credentials
  • Confirm account/environment
  • May be different Application

Missing Expected Webhook

  • Check webhook ID
  • May have been deleted
  • Verify URL/environment
  • Check different Application

Signing Key is Null

  • By design for security
  • Only shown on creation
  • Cannot retrieve later
  • Must create new webhook if lost
  • POST /webhooks: Create new webhook
  • GET /webhooks/{id}: Fetch specific webhook
  • PUT /webhooks/{id}: Update webhook (enable/disable, change URL)