Skip to main content
The Billing Intent webhook is sent to banks when merchants want to establish billing agreements with their customers. This webhook notifies the bank that a merchant is requesting permission to bill a customer.

When This Webhook is Sent

Trigger Event

Sent to banks when a merchant calls POST /v1/billing/intent to request billing permission from a customer.
Webhook Type: billing.intent Recipient: Banks Frequency: Real-time (immediate)

Webhook Payload Structure

Headers

POST /your-webhook-endpoint
Content-Type: application/json
X-Peere-Signature: sha256=<signature>
User-Agent: Peere-Webhooks/1.0

Payload Schema

{
  "entityId": "bank_456",
  "entityType": "bank",
  "webhookType": "billing.intent",
  "timestamp": "2024-01-15T10:30:00.000Z",
  "batchId": "batch_intent_123",
  "data": [
    {
      "customerId": "customer_123",
      "customerEmail": "john.doe@example.com",
      "lookupPhrase": "customer-lookup-phrase",
      "agreementPhrase": "customer-agreement-phrase",
      "currency": "NGN",
      "merchant": {
        "id": "merchant_001",
        "name": "Netflix Nigeria",
        "icon": "https://example.com/icons/netflix.png",
        "email": "support@netflix.com",
        "website": "https://netflix.com"
      },
      "description": "Netflix Premium subscription - monthly billing authorization",
      "reference": "intent_ref_abc123",
      "dueDate": "2024-01-16T10:30:00.000Z"
    }
  ],
  "itemCount": 1,
  "signature": "webhook_signature_hash"
}

Field Descriptions

  • entityId: Your bank’s unique identifier - entityType: Always “bank” for bank webhooks - webhookType: Always “billing.intent” for this webhook - timestamp: ISO 8601 timestamp when webhook was sent - batchId: Unique identifier for this webhook batch - itemCount: Number of billing intents in this webhook
  • customerId: Your internal customer identifier - customerEmail: Customer’s email address - lookupPhrase: Phrase used by merchant to find customer - agreementPhrase: Phrase to be used for future billing (if approved)
  • merchant.id: Merchant’s unique identifier in Peere Network - merchant.name: Business name displayed to customer - merchant.icon: Logo URL for customer recognition - merchant.email: Merchant contact email - merchant.website: Merchant website URL
  • currency: Currency code for billing (e.g., “NGN”) - description: Merchant’s description of billing purpose - reference: Unique reference for this billing intent - dueDate: When customer decision is expected

Implementation Guide

1. Webhook Endpoint Setup

const express = require('express');
const crypto = require('crypto');
const app = express();

app.use(express.json());

app.post('/webhooks/peere/billing-intent', (req, res) => {
try {
// Verify webhook signature
const signature = req.headers['x-peere-signature'];
if (!verifySignature(req.body, signature)) {
return res.status(401).send('Invalid signature');
}

    const { webhookType, data } = req.body;

    if (webhookType === 'billing.intent') {
      handleBillingIntent(data);
    }

    res.status(200).send('OK');

} catch (error) {
console.error('Webhook processing error:', error);
res.status(500).send('Internal Server Error');
}
});

function handleBillingIntent(intentData) {
intentData.forEach(intent => {
// Notify customer about merchant billing request
notifyCustomer(intent.customerId, {
type: 'billing_intent',
merchant: intent.merchant,
description: intent.description,
currency: intent.currency,
reference: intent.reference
});

    // Log the intent for customer review
    logBillingIntent(intent);

});
}

function verifySignature(payload, signature) {
const expectedSignature = crypto
.createHmac('sha256', process.env.PEERE_WEBHOOK_SECRET)
.update(JSON.stringify(payload))
.digest('hex');

return crypto.timingSafeEqual(
Buffer.from(signature.replace('sha256=', '')),
Buffer.from(expectedSignature)
);
}

2. Customer Notification Implementation

const admin = require('firebase-admin');

async function notifyCustomer(customerId, intentData) {
try {
const customer = await getCustomer(customerId);

    if (customer.notificationToken) {
      const message = {
        token: customer.notificationToken,
        notification: {
          title: `${intentData.merchant.name} wants to bill you`,
          body: intentData.description
        },
        data: {
          type: 'billing_intent',
          merchantId: intentData.merchant.id,
          reference: intentData.reference,
          action_url: `/billing-intents/${intentData.reference}`
        }
      };

      await admin.messaging().send(message);
    }

} catch (error) {
console.error('FCM notification failed:', error);
}
}

3. Customer Response Handling

After receiving the billing intent webhook, you need to collect the customer’s decision and respond:
// Banking app route for customer decision
app.post('/billing-intents/:reference/respond', async (req, res) => {
  try {
    const { reference } = req.params;
    const { customerId, decision, spendingLimits } = req.body;
    
    // Validate customer decision
    const validDecisions = ['approve_once', 'approve_recurring', 'deny', 'suspended'];
    if (!validDecisions.includes(decision)) {
      return res.status(400).json({ error: 'Invalid decision' });
    }
    
    // Get the original intent
    const intent = await getBillingIntent(reference);
    
    // Send response to Peere Network
    const response = await axios.post(
      'https://api.peere.network/v1/billing/intent-response',
      {
        customerId: customerId,
        entityId: intent.merchant.id,
        lookupPhrase: intent.lookupPhrase,
        customerDecision: decision,
        spendingLimits: spendingLimits,
        reference: reference
      },
      {
        headers: {
          'Authorization': `Bearer ${process.env.PEERE_API_KEY}`,
          'Content-Type': 'application/json'
        }
      }
    );
    
    // Update local records
    await updateBillingIntentStatus(reference, decision);
    
    res.json({ success: true, decision: decision });
    
  } catch (error) {
    console.error('Decision processing error:', error);
    res.status(500).json({ error: 'Failed to process decision' });
  }
});

Testing Your Implementation

1. Webhook Testing

curl -X POST "https://your-domain.com/webhooks/peere/billing-intent" \
  -H "Content-Type: application/json" \
  -H "X-Peere-Signature: sha256=test_signature" \
  -d '{
    "entityId": "bank_test_123",
    "entityType": "bank",
    "webhookType": "billing.intent",
    "timestamp": "2024-01-15T10:30:00.000Z",
    "batchId": "test_batch_123",
    "data": [
      {
        "customerId": "test_customer_123",
        "customerEmail": "test@example.com",
        "lookupPhrase": "test-lookup-phrase",
        "agreementPhrase": "test-agreement-phrase",
        "currency": "NGN",
        "merchant": {
          "id": "test_merchant_123",
          "name": "Test Merchant",
          "icon": "https://example.com/icon.png"
        },
        "description": "Test billing authorization",
        "reference": "test_ref_123",
        "dueDate": "2024-01-16T10:30:00.000Z"
      }
    ],
    "itemCount": 1
  }'

2. Integration Testing

1

Webhook Delivery

Verify your endpoint receives and processes billing intent webhooks correctly
2

Customer Notification

Test that customers receive notifications via your chosen channels (FCM, email, in-app)
3

Decision Collection

Ensure customers can review and respond to billing intents in your banking app
4

Response Sending

Verify that customer decisions are properly sent back to Peere Network

Best Practices

Security

  • Always verify webhook signatures - Use HTTPS for webhook endpoints - Implement rate limiting - Log security events

Reliability

  • Handle webhook retries gracefully - Implement idempotency checks - Use database transactions - Monitor webhook processing

User Experience

  • Send timely notifications - Provide clear merchant information - Make decision process simple - Show spending limit options

Monitoring

  • Track webhook delivery rates - Monitor customer response times - Log processing errors - Set up alerting for failures

Next Steps

Bank Response Webhook

Handle customer responses to billing requests

Intent Response Webhook

Process customer decisions on billing intents

Webhook Security

Learn advanced webhook security practices

API Reference

Explore bank API endpoints