Skip to main content

Webhook Configuration

Webhooks allow your application to receive real-time HTTP POST notifications when events occur in your ONE project -- transactions confirmed, trades executed, payments completed, and more. You can configure webhooks through the dashboard or programmatically with the OneEngineClient.

Client Setup

import { OneEngineClient } from '@one_deploy/sdk';

const engine = new OneEngineClient({
baseUrl: process.env.ONE_ENGINE_URL!,
clientId: process.env.ONE_CLIENT_ID!,
secretKey: process.env.ONE_SECRET_KEY!,
});

Methods

MethodDescription
createWebhook(input)Create a new webhook subscription.
getWebhooks(projectId)List all webhooks for a project.
getWebhook(webhookId)Get a single webhook by ID.
updateWebhook(webhookId, updates)Update an existing webhook.
deleteWebhook(webhookId)Delete a webhook subscription.
testWebhook(webhookId)Send a test event to the webhook endpoint.
getWebhookDeliveries(webhookId, options?)Retrieve delivery logs for a webhook.

WebhookEventType

The WebhookEventType enum defines all events you can subscribe to.

enum WebhookEventType {
// Transaction events
TRANSACTION_CONFIRMED = 'transaction.confirmed',
TRANSACTION_FAILED = 'transaction.failed',
TRANSACTION_PENDING = 'transaction.pending',

// Wallet events
WALLET_CREATED = 'wallet.created',
WALLET_BALANCE_CHANGE = 'wallet.balance_change',

// Payment events
ONRAMP_COMPLETED = 'onramp.completed',
ONRAMP_FAILED = 'onramp.failed',
OFFRAMP_COMPLETED = 'offramp.completed',
OFFRAMP_FAILED = 'offramp.failed',
SWAP_COMPLETED = 'swap.completed',
SWAP_FAILED = 'swap.failed',

// AI Trading events
TRADE_OPENED = 'trade.opened',
TRADE_CLOSED = 'trade.closed',
TRADE_PROFIT_TAKEN = 'trade.profit_taken',
TRADE_STOP_LOSS = 'trade.stop_loss',
STRATEGY_ACTIVATED = 'strategy.activated',
STRATEGY_PAUSED = 'strategy.paused',

// Forex events
FOREX_POSITION_OPENED = 'forex.position_opened',
FOREX_POSITION_CLOSED = 'forex.position_closed',
FOREX_POOL_UPDATED = 'forex.pool_updated',

// Contract events
CONTRACT_DEPLOYED = 'contract.deployed',
CONTRACT_EVENT = 'contract.event',

// Project events
PROJECT_QUOTA_WARNING = 'project.quota_warning',
PROJECT_QUOTA_REACHED = 'project.quota_reached',
}

Creating a Webhook

CreateWebhookInput

interface CreateWebhookInput {
projectId: string;
url: string; // HTTPS endpoint that receives POST requests
events: WebhookEventType[]; // Events to subscribe to
description?: string; // Human-readable label
secret?: string; // Shared secret for HMAC signature verification
active?: boolean; // Defaults to true
headers?: Record<string, string>; // Custom headers sent with every delivery
}

Basic Setup

const res = await engine.createWebhook({
projectId: 'proj_abc123',
url: 'https://api.myapp.com/webhooks/one',
events: [
WebhookEventType.TRANSACTION_CONFIRMED,
WebhookEventType.SWAP_COMPLETED,
WebhookEventType.TRADE_CLOSED,
],
description: 'Production transaction notifications',
secret: 'whsec_my_signing_secret',
});

if (res.success) {
console.log('Webhook ID:', res.data.id);
console.log('URL:', res.data.url);
console.log('Events:', res.data.events);
}

Webhook Response Type

interface Webhook {
id: string;
projectId: string;
url: string;
events: WebhookEventType[];
description?: string;
secret: string;
active: boolean;
headers?: Record<string, string>;
createdAt: string; // ISO-8601
updatedAt: string; // ISO-8601
}

Listing Webhooks

const res = await engine.getWebhooks('proj_abc123');

if (res.success) {
for (const webhook of res.data) {
console.log(`[${webhook.id}] ${webhook.url} -- ${webhook.active ? 'active' : 'paused'}`);
console.log(' Events:', webhook.events.join(', '));
}
}

Updating a Webhook

Pass only the fields you want to change. Omitted fields keep their current value.

const res = await engine.updateWebhook('whk_abc123', {
events: [
WebhookEventType.TRADE_OPENED,
WebhookEventType.TRADE_CLOSED,
WebhookEventType.TRADE_STOP_LOSS,
],
active: true,
});

if (res.success) {
console.log('Updated events:', res.data.events);
}

Testing a Webhook

Send a synthetic test event to your endpoint to verify connectivity and payload handling.

const res = await engine.testWebhook('whk_abc123');

if (res.success) {
console.log('Test delivery ID:', res.data.deliveryId);
console.log('Status code:', res.data.statusCode);
console.log('Response time:', res.data.durationMs, 'ms');

if (res.data.statusCode === 200) {
console.log('Webhook endpoint is responding correctly.');
} else {
console.warn('Endpoint returned non-200 status.');
}
}

The test event payload looks like this:

{
"id": "evt_test_123",
"type": "webhook.test",
"projectId": "proj_abc123",
"timestamp": "2025-01-15T12:00:00Z",
"data": {
"message": "This is a test webhook delivery."
}
}

Webhook Delivery Logs

Track delivery attempts, response codes, and retry status for each webhook.

getWebhookDeliveries

interface GetWebhookDeliveriesOptions {
page?: number; // 1-based (default: 1)
limit?: number; // Items per page (default: 20, max: 100)
status?: 'success' | 'failed' | 'pending';
}

interface WebhookDelivery {
id: string;
webhookId: string;
eventType: WebhookEventType;
url: string;
statusCode: number | null; // null if the request failed to connect
requestBody: string; // JSON payload sent
responseBody?: string; // Response from your endpoint
durationMs: number;
attempt: number; // 1 = first attempt, 2+ = retries
maxAttempts: number;
status: 'success' | 'failed' | 'pending';
createdAt: string; // ISO-8601
nextRetryAt?: string; // ISO-8601, present if status is 'pending'
}

Querying Deliveries

const res = await engine.getWebhookDeliveries('whk_abc123', {
page: 1,
limit: 25,
status: 'failed',
});

if (res.success) {
for (const delivery of res.data) {
console.log(
`[${delivery.id}] ${delivery.eventType} -- ` +
`${delivery.status} (attempt ${delivery.attempt}/${delivery.maxAttempts})`
);
if (delivery.statusCode) {
console.log(` Status: ${delivery.statusCode}`);
}
if (delivery.nextRetryAt) {
console.log(` Next retry: ${delivery.nextRetryAt}`);
}
}
}

Retry Behaviour

When a webhook delivery fails (non-2xx response or connection error), the ONE Engine retries with exponential backoff:

AttemptDelay after failure
1st retry30 seconds
2nd retry2 minutes
3rd retry15 minutes
4th retry1 hour
5th retry4 hours

After 5 failed retry attempts (6 total attempts including the original), the delivery is marked as permanently failed. You can inspect failed deliveries in the dashboard or via getWebhookDeliveries.

warning

If a webhook endpoint fails consistently for 24 hours, the webhook is automatically paused to prevent unnecessary load. Re-enable it from the dashboard or by calling updateWebhook(webhookId, { active: true }) after fixing the endpoint.

Verifying Webhook Signatures

Every delivery includes an X-One-Signature header containing an HMAC-SHA256 signature of the request body, signed with your webhook secret. Always verify this signature to ensure the payload was sent by the ONE Engine.

server/webhook-handler.ts
import crypto from 'crypto';

function verifyWebhookSignature(
body: string,
signature: string,
secret: string
): boolean {
const expected = crypto
.createHmac('sha256', secret)
.update(body, 'utf8')
.digest('hex');

return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}

// Express example
app.post('/webhooks/one', (req, res) => {
const signature = req.headers['x-one-signature'] as string;
const body = JSON.stringify(req.body);

if (!verifyWebhookSignature(body, signature, process.env.WEBHOOK_SECRET!)) {
return res.status(401).send('Invalid signature');
}

const event = req.body;
console.log('Received event:', event.type);
console.log('Data:', event.data);

// Process the event...
res.status(200).send('OK');
});

Complete Webhook Setup Flow

The following example demonstrates the full lifecycle: create a webhook, test it, verify deliveries, and clean up.

webhook-setup.ts
import { OneEngineClient, WebhookEventType } from '@one_deploy/sdk';

const engine = new OneEngineClient({
baseUrl: process.env.ONE_ENGINE_URL!,
clientId: process.env.ONE_CLIENT_ID!,
secretKey: process.env.ONE_SECRET_KEY!,
});

async function setupWebhooks() {
// 1. Create a webhook
const createRes = await engine.createWebhook({
projectId: 'proj_abc123',
url: 'https://api.myapp.com/webhooks/one',
events: [
WebhookEventType.TRANSACTION_CONFIRMED,
WebhookEventType.TRANSACTION_FAILED,
WebhookEventType.SWAP_COMPLETED,
WebhookEventType.TRADE_OPENED,
WebhookEventType.TRADE_CLOSED,
WebhookEventType.FOREX_POSITION_OPENED,
WebhookEventType.FOREX_POSITION_CLOSED,
WebhookEventType.PROJECT_QUOTA_WARNING,
],
description: 'Main production webhook',
secret: 'whsec_production_secret_value',
});

if (!createRes.success) {
console.error('Failed to create webhook:', createRes.error);
return;
}

const webhookId = createRes.data.id;
console.log('Created webhook:', webhookId);

// 2. Test the endpoint
const testRes = await engine.testWebhook(webhookId);

if (testRes.success && testRes.data.statusCode === 200) {
console.log('Test delivery successful.');
} else {
console.warn('Test delivery issue. Check your endpoint.');
}

// 3. Check delivery logs
const deliveries = await engine.getWebhookDeliveries(webhookId, { limit: 5 });

if (deliveries.success) {
console.log(`Recent deliveries: ${deliveries.data.length}`);
for (const d of deliveries.data) {
console.log(` ${d.eventType} -- ${d.status} (${d.statusCode})`);
}
}

// 4. List all webhooks for the project
const allWebhooks = await engine.getWebhooks('proj_abc123');

if (allWebhooks.success) {
console.log(`Total webhooks: ${allWebhooks.data.length}`);
}
}

setupWebhooks();

Next Steps