Editor's note, 3 October 2026. This post covers an earlier namespace. It still runs on the same API. Anlyon's product today is shared limits and receipts for AI agent actions.
When an agent decides something, more than one system usually needs to hear about it: the CRM, the ledger, the audit sink, the customer's webhook. Writing that fan-out by hand means four calls, four retry policies, and four ways to half-fail. A URL Group lets the agent publish once, and each endpoint receives it independently with its own retry logic and delivery tracking.
What Are URL Groups?
URL Groups let you define a collection of endpoints and publish messages to all of them with a single API call. Each endpoint receives the message independently, with its own retry logic and delivery tracking.
Use cases:
- Broadcasting events to multiple microservices
- Sending webhooks to multiple third-party services
- Notifying multiple systems of state changes
- Implementing pub/sub patterns
Creating a URL Group
Basic Setup
import { Client } from '@anlyonhq/sdk';
const client = new Client({
apiKey: process.env.ANLYON_API_KEY!,
});
// Create a URL group with multiple endpoints
const group = await client.urlGroups.create({
name: 'Production Webhooks',
endpoints: [
{
url: 'https://service1.example.com/webhook',
name: 'User Service',
},
{
url: 'https://service2.example.com/webhook',
name: 'Notification Service',
},
{
url: 'https://service3.example.com/webhook',
name: 'Analytics Service',
},
],
});
console.log(`Created group: ${group.data.id}`);
Custom Retry Configuration
Each endpoint can have its own retry configuration:
const group = await client.urlGroups.create({
name: 'Critical Services',
endpoints: [
{
url: 'https://critical-service.com/webhook',
name: 'Critical Service',
retryCount: 10, // More retries for critical services
},
{
url: 'https://optional-service.com/webhook',
name: 'Optional Service',
retryCount: 3, // Fewer retries for optional services
},
],
});
Publishing to a Group
Basic Broadcast
// Publish to all endpoints in the group
const result = await client.urlGroups.publish(group.data.id, {
method: 'POST',
body: {
event: 'user.created',
userId: '123',
timestamp: new Date().toISOString(),
},
});
console.log(`Published to ${result.data.total} endpoints`);
console.log(`Successful: ${result.data.successful}`);
console.log(`Failed: ${result.data.failed}`);
Scheduling a broadcast
You can also broadcast at a future time. executeAt is a Unix timestamp in
seconds, so "in a minute" is the current time plus 60:
await client.urlGroups.publish(group.data.id, {
method: 'POST',
body: { event: 'order.processed', orderId: '456' },
executeAt: Math.floor(Date.now() / 1000) + 60,
});
Managing Groups
List All Groups
const groups = await client.urlGroups.list();
groups.data.forEach(group => {
console.log(`${group.name}: ${group.id}`);
});
Get Group Details
const group = await client.urlGroups.get('group-id');
console.log(`Group: ${group.data.name}`);
console.log(`Endpoints: ${group.data.endpoints.length}`);
group.data.endpoints.forEach(endpoint => {
console.log(` - ${endpoint.name}: ${endpoint.url}`);
});
Add Endpoints
Dynamically add endpoints to an existing group:
await client.urlGroups.addEndpoint('group-id', {
url: 'https://new-service.com/webhook',
name: 'New Service',
retryCount: 5,
});
Remove Endpoints
await client.urlGroups.removeEndpoint('group-id', 'endpoint-id');
Update Group Name
await client.urlGroups.update('group-id', {
name: 'Updated Group Name',
});
Delete a Group
await client.urlGroups.delete('group-id');
Real-World Examples
Event-Driven Architecture
In a microservices architecture, URL Groups make it easy to broadcast events:
// When a user signs up, notify multiple services
const userCreatedGroup = await client.urlGroups.get('user-events-group');
await client.urlGroups.publish(userCreatedGroup.data.id, {
method: 'POST',
body: {
event: 'user.created',
userId: newUser.id,
email: newUser.email,
timestamp: new Date().toISOString(),
},
});
// This automatically notifies:
// - Email service (send welcome email)
// - Analytics service (track signup)
// - Notification service (send push notification)
// - CRM service (create contact)
Third-Party Webhook Broadcasting
Broadcast webhooks to multiple third-party services:
// Create a group for payment webhooks
const paymentGroup = await client.urlGroups.create({
name: 'Payment Webhooks',
endpoints: [
{ url: 'https://stripe.com/webhook', name: 'Stripe' },
{ url: 'https://paypal.com/webhook', name: 'PayPal' },
{ url: 'https://internal-api.com/payments', name: 'Internal API' },
],
});
// Broadcast payment event
await client.urlGroups.publish(paymentGroup.data.id, {
method: 'POST',
body: {
event: 'payment.completed',
amount: 99.99,
currency: 'USD',
transactionId: 'txn_123',
},
});
Multi-Region Deployment
Notify services across multiple regions:
const multiRegionGroup = await client.urlGroups.create({
name: 'Multi-Region Services',
endpoints: [
{ url: 'https://us-east.api.example.com/webhook', name: 'US East' },
{ url: 'https://eu-west.api.example.com/webhook', name: 'EU West' },
{ url: 'https://asia-pac.api.example.com/webhook', name: 'Asia Pacific' },
],
});
// Broadcast configuration update
await client.urlGroups.publish(multiRegionGroup.data.id, {
method: 'POST',
body: {
event: 'config.updated',
config: { featureFlag: true },
},
});
Best Practices
- Group by purpose: Create groups based on event types or service categories
- Use descriptive names: Make it easy to identify groups in your dashboard
- Set appropriate retries: Critical services need more retries than optional ones
- Monitor delivery: Track success rates for each endpoint
- Handle failures gracefully: Some endpoints may fail while others succeed
- Limit group size: Keep groups under 50 endpoints for optimal performance
- Use idempotent endpoints: Ensure your webhooks can handle duplicate deliveries
Error Handling
When publishing to a group, some endpoints may succeed while others fail:
const result = await client.urlGroups.publish('group-id', {
body: { event: 'test' },
});
if (result.data.failed > 0) {
console.warn(`${result.data.failed} endpoints failed to receive the message`);
// Check individual endpoint status
result.data.results.forEach(endpointResult => {
if (!endpointResult.success) {
console.error(`Failed: ${endpointResult.endpointUrl} - ${endpointResult.error}`);
}
});
}
Performance Considerations
- Parallel delivery: All endpoints receive messages in parallel
- Independent retries: Each endpoint retries independently
- Non-blocking: Failed endpoints don't block successful ones
- Scalable: Groups can handle high message volumes
Comparison: URL Groups vs Individual Messages
Without URL Groups (Manual)
// Publish to each endpoint individually
const endpoints = [
'https://service1.com/webhook',
'https://service2.com/webhook',
'https://service3.com/webhook',
];
for (const url of endpoints) {
await client.messages.publish({
url,
body: { event: 'test' },
});
}
// Problems:
// - More API calls
// - Harder to manage
// - No aggregate tracking
With URL Groups (Recommended)
// Single API call broadcasts to all
await client.urlGroups.publish('group-id', {
body: { event: 'test' },
});
// Benefits:
// - Single API call
// - Centralized management
// - Aggregate tracking
// - Independent retries
Next Steps
- Learn about CRON scheduling
- Explore Dead Letter Queue management
- Check out our TypeScript SDK guide
Start broadcasting with URL Groups today! 📡
