import * as plugins from './bunq.plugins.js'; import { BunqAccount } from './bunq.classes.account.js'; import { BunqMonetaryAccount } from './bunq.classes.monetaryaccount.js'; import { BunqNotification, BunqWebhookHandler } from './bunq.classes.notification.js'; import { BunqCrypto } from './bunq.classes.crypto.js'; /** * Webhook management for monetary accounts */ export class BunqWebhook { private bunqAccount: BunqAccount; constructor(bunqAccount: BunqAccount) { this.bunqAccount = bunqAccount; } /** * Create a webhook for a monetary account */ public async create(monetaryAccount: BunqMonetaryAccount, url: string): Promise { await this.bunqAccount.apiContext.ensureValidSession(); const response = await this.bunqAccount.getHttpClient().post( `/v1/user/${this.bunqAccount.userId}/monetary-account/${monetaryAccount.id}/notification-filter-url`, { category: 'MUTATION', notification_target: url } ); if (response.Response && response.Response[0] && response.Response[0].Id) { return response.Response[0].Id.id; } throw new Error('Failed to create webhook'); } /** * List all webhooks for a monetary account */ public async list(monetaryAccount: BunqMonetaryAccount): Promise> { await this.bunqAccount.apiContext.ensureValidSession(); const response = await this.bunqAccount.getHttpClient().list( `/v1/user/${this.bunqAccount.userId}/monetary-account/${monetaryAccount.id}/notification-filter-url` ); const webhooks: Array<{ id: number; url: string; category: string; }> = []; if (response.Response) { for (const item of response.Response) { if (item.NotificationFilterUrl) { webhooks.push({ id: item.NotificationFilterUrl.id, url: item.NotificationFilterUrl.notification_target, category: item.NotificationFilterUrl.category }); } } } return webhooks; } /** * Get a specific webhook */ public async get(monetaryAccount: BunqMonetaryAccount, webhookId: number): Promise<{ id: number; url: string; category: string; }> { await this.bunqAccount.apiContext.ensureValidSession(); const response = await this.bunqAccount.getHttpClient().get( `/v1/user/${this.bunqAccount.userId}/monetary-account/${monetaryAccount.id}/notification-filter-url/${webhookId}` ); if (response.Response && response.Response[0] && response.Response[0].NotificationFilterUrl) { const webhook = response.Response[0].NotificationFilterUrl; return { id: webhook.id, url: webhook.notification_target, category: webhook.category }; } throw new Error('Webhook not found'); } /** * Update a webhook URL */ public async update(monetaryAccount: BunqMonetaryAccount, webhookId: number, newUrl: string): Promise { await this.bunqAccount.apiContext.ensureValidSession(); await this.bunqAccount.getHttpClient().put( `/v1/user/${this.bunqAccount.userId}/monetary-account/${monetaryAccount.id}/notification-filter-url/${webhookId}`, { notification_target: newUrl } ); } /** * Delete a webhook */ public async delete(monetaryAccount: BunqMonetaryAccount, webhookId: number): Promise { await this.bunqAccount.apiContext.ensureValidSession(); await this.bunqAccount.getHttpClient().delete( `/v1/user/${this.bunqAccount.userId}/monetary-account/${monetaryAccount.id}/notification-filter-url/${webhookId}` ); } } /** * Webhook server for receiving bunq notifications */ export class BunqWebhookServer { private bunqAccount: BunqAccount; private notification: BunqNotification; private handler: BunqWebhookHandler; private server?: any; // HTTP server instance private port: number; private path: string; private publicUrl: string; constructor( bunqAccount: BunqAccount, options: { port?: number; path?: string; publicUrl: string; } ) { this.bunqAccount = bunqAccount; this.notification = new BunqNotification(bunqAccount); this.handler = new BunqWebhookHandler(); this.port = options.port || 3000; this.path = options.path || '/webhook'; this.publicUrl = options.publicUrl; } /** * Get the webhook handler for registering event callbacks */ public getHandler(): BunqWebhookHandler { return this.handler; } /** * Start the webhook server */ public async start(): Promise { // Implementation would use an HTTP server library // For now, this is a placeholder console.log(`Webhook server would start on port ${this.port}`); } /** * Stop the webhook server */ public async stop(): Promise { if (this.server) { // Stop the server console.log('Webhook server stopped'); } } /** * Register the webhook URL with bunq */ public async register(): Promise { const webhookUrl = `${this.publicUrl}${this.path}`; // Register for all payment-related events await this.notification.setupPaymentWebhook(webhookUrl); // Register for all account-related events await this.notification.setupAccountWebhook(webhookUrl); } /** * Verify webhook signature */ public verifySignature(body: string, signature: string): boolean { const crypto = new BunqCrypto(); // In production, use bunq's server public key return true; // Placeholder } }