Skip to main content

DNO Custom Provider Guide

PBXware's DNO (Do Not Originate) service validates caller IDs against a DNO list before allowing calls to go out. Out of the box it integrates with the Somos registry, but the Custom provider option lets you connect it to any DNO list provider by placing a middleware application between dno-service and your provider.


How It Works

Your middleware sits between dno-service and your DNO provider. For every validation request, dno-service calls your middleware, which translates the request into whatever format your provider expects, performs the lookup, and maps the result back to one of the three statuses dno-service understands.

PBXware → dno-service → [Your Middleware] → Your DNO Provider
  1. Configure dno-service - set the provider to custom and point api_endpoint at your middleware
  2. Receive the lookup request - dno-service POSTs a JSON body with the E.164-normalised number and service type
  3. Perform the lookup - forward the request to your provider in their required format
  4. Return the result - respond with one of the three recognised DNO status values

Prerequisites

  • A middleware application with an HTTP endpoint reachable from the dno-service host
  • Access to the PBXware administration interface or dno-service API to configure the DNO settings

Configure dno-service

Via the PBXware Admin Interface

Navigate to Settings → DNO → Configuration.

FieldDescription
Enable DNOSet to Yes to enable DNO caller ID validation
DNO ProviderSelect Custom to use your own middleware
API EndpointFull URL of your middleware endpoint - dno-service POSTs lookup requests here
API KeyOptional. When set, dno-service sends it as a Bearer token in the Authorization header
Cache TTL (minutes)How long to cache lookup results. Set to 0 to disable caching. failed_dno_lookup results are never cached
Enable NotificationsEnables or disables email notifications for DNO events
Notification EmailOne or more comma-separated email addresses to receive notifications
Notification Interval (minutes)Minimum time between notifications of the same type

Click Save. Changes take effect immediately on the next validation request - no restart required.


Via the API

PUT /api/system/v2/dno/configuration
Content-Type: application/json
{
"enabled": true,
"provider": "custom",
"api_endpoint": "https://your-middleware.example.com/validate",
"api_key": "your-api-key",
"cache_ttl": 5,
"notifications_enabled": true,
"notifications_email": ["admin@example.com", "user@example.com"],
"notifications_interval": 60
}
FieldDescription
enabledSet to true to enable DNO caller ID validation
providerSet to "custom" to use your own middleware
api_endpointFull URL of your middleware endpoint - dno-service POSTs lookup requests here
api_keyOptional. When set, dno-service sends it as a Bearer token in the Authorization header
cache_ttlHow long to cache lookup results, in minutes. Set to 0 to disable caching. failed_dno_lookup results are never cached
notifications_enabledEnables or disables email notifications for DNO events
notifications_emailArray of email addresses to receive notifications
notifications_intervalMinimum time between notifications of the same type, in minutes

Changes take effect immediately on the next validation request - no restart required.


API Reference

Request: dno-service → Middleware

dno-service sends a POST to your api_endpoint:

POST {api_endpoint}
Content-Type: application/json
Accept: application/json
Authorization: Bearer {api_key}

The Authorization header is only included when api_key is configured.

{
"number": "+12408052400",
"type": "voice"
}
FieldDescription
numberE.164-normalised phone number to look up
type"voice" or "text". Defaults to "voice" if the original request did not include a type

Response: Middleware → dno-service

Your middleware must respond with HTTP 200 and a JSON body:

{
"status": "not_on_dno_list"
}

The status field must be exactly one of:

statusMeaning
not_on_dno_listNumber is not found on the DNO list - allow the call
found_on_dno_listNumber is on the DNO list - block the call
failed_dno_lookupLookup could not be completed - allow the call

Any unrecognised status value causes dno-service to treat the response as a provider error and return a 502 response to PBXware.


Error Responses

If your middleware cannot process the request, respond with the appropriate HTTP status and a JSON error body:

{
"error": "description of what went wrong"
}
HTTP StatusWhen to useEffect on dno-service
400 Bad RequestThe request was malformed or missing required fieldsdno-service returns a 502 to its caller
401 UnauthorizedThe Authorization header is missing or invaliddno-service returns a 502 to its caller

Any status other than 200, 400, or 401 is treated as an unexpected provider error and also results in a 502.


Middleware Examples

The examples below show a minimal middleware that receives a lookup request from dno-service, performs a placeholder provider call, and returns the mapped result.

Install: npm install express

import express from 'express';

const API_KEY = process.env.API_KEY ?? '';

const app = express();
app.use(express.json());

async function lookupWithProvider(number, type) {
// Replace with your actual provider integration.
// Return one of: 'not_on_dno_list', 'found_on_dno_list', 'failed_dno_lookup'
console.log(`Looking up ${number} (${type}) with provider`);
return 'not_on_dno_list';
}

app.post('/validate', async (req, res) => {
try {
if (API_KEY) {
const authHeader = req.headers['authorization'] ?? '';
if (authHeader !== `Bearer ${API_KEY}`) {
return res.status(401).json({ error: 'Unauthorized' });
}
}

const { number, type } = req.body;
if (!number) {
return res.status(400).json({ error: 'number is required' });
}

const status = await lookupWithProvider(number, type ?? 'voice');
res.json({ status });
} catch (e) {
console.error(e);
res.status(500).json({ error: e.message });
}
});

app.listen(8080, () => console.log('Middleware running on http://localhost:8080'));

Running the Middleware

Save as server.mjs (or .js with "type": "module" in package.json), then:

API_KEY=your-api-key node server.mjs

Once your middleware is running and dno-service is configured to point at it, validation requests will flow through your middleware automatically. Set api_endpoint to the full URL of your /validate route (e.g. https://your-middleware.example.com/validate) and set api_key to the same value as your API_KEY environment variable.