> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.voicebip.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.voicebip.com/_mcp/server.

# Best Practices

> Latency optimization, Nigerian network tips, NDPR compliance, and error handling best practices for Voicebip integrations.

Guidelines for building reliable, low-latency, and compliant integrations on the Voicebip platform.

## Webhook Response Time

For BYOM (Bring Your Own Model) integrations, keep your webhook response time **under 300ms**. Your handler's latency directly affects the caller's experience.

* **Pre-warm LLM connections.** Initialize clients at startup, not per-request. Use connection pooling.
* **Use streaming if your LLM supports it.** Return the first sentence immediately rather than waiting for the full completion.
* **Avoid database writes in the critical path.** Respond first, then log asynchronously.
* **Co-locate your server** close to Voicebip's API — EU or Africa regions are recommended for Nigerian traffic.

```javascript
// Bad: synchronous database write before responding
app.post("/webhook", async (req, res) => {
  await db.insertEvent(req.body);   // 50-100ms wasted
  const reply = await llm.complete(req.body.payload.text);
  res.json({ text: reply, end_call: false });
});

// Good: respond first, log asynchronously
app.post("/webhook", async (req, res) => {
  const reply = await llm.complete(req.body.payload.text);
  res.json({ text: reply, end_call: false });
  db.insertEvent(req.body).catch(console.error);  // fire-and-forget
});
```

> **Warning**
>
> The synchronous BYOM voice-turn webhook has a hard **5-second** timeout — responses arriving later are treated as failures (the circuit breaker records them) and the caller hears a fallback message. This is distinct from the asynchronous event-delivery webhooks (`call.completed`, `message.*`), which time out at 10 seconds and then enter the retry sequence.

## Nigerian Network Tips

Voicebip operates on NCC-licensed Nigerian carrier infrastructure. Understanding the MNO landscape helps you build more reliable voice and SMS integrations.

* **MTN is the most reliable primary trunk.** It has the highest call completion and SMS delivery rates nationwide.
* **MNO failover is automatic** with a 5-second budget. The failover chain is: MTN -> Glo -> Airtel -> 9mobile. Unknown prefixes default to MTN.
* **Test with numbers from each MNO** to ensure your application handles all carriers correctly.

| MNO     | Prefixes                                       | Notes                                       |
| ------- | ---------------------------------------------- | ------------------------------------------- |
| MTN     | 0803, 0806, 0703, 0706, 0813, 0816, 0810, 0814 | Primary trunk. Most reliable.               |
| Glo     | 0805, 0807, 0705, 0815, 0811                   | Good urban coverage. First failover.        |
| Airtel  | 0802, 0808, 0708, 0812                         | Strong in Lagos and Abuja. Second failover. |
| 9mobile | 0809, 0817, 0818, 0908, 0909                   | Limited rural coverage. Last failover.      |

> **Tip**
>
> DLR (delivery receipt) timing varies by MNO: MTN is typically under 5 seconds, while others can take up to 60 seconds. For time-sensitive notifications, prefer voice calls over SMS.

## NDPR Compliance

Voicebip operates under Nigeria's Data Protection Regulation (NDPR). Follow these practices to stay compliant.

### Recording Consent

* **Obtain consent before recording.** When `recording_enabled` is set to `true` on an agent (and recording is also enabled at the workspace level via `POST /v1/workspace/recording`), Voicebip automatically plays a consent prompt and uses a DTMF flow: press 1 to consent, press 2 to opt out. No response within the consent timeout (\~12 seconds) defaults to no recording.
* **Never disable the consent prompt without a legal basis.** The agent's `consent_required` field defaults to `true`; setting it to `false` records immediately with no prompt. Recording calls without consent violates NDPR.

### STOP Opt-Outs

* **Honor STOP opt-outs.** When a recipient sends `STOP` via SMS or WhatsApp, Voicebip automatically adds them to the workspace opt-out list. This is automatic -- subsequent message attempts return `422 OPT_OUT_ENFORCED`.

### Data Retention

* **Configure `retention_days`** on your workspace to control how long call recordings and transcripts are stored across all agents. After the retention period, recordings and transcripts are permanently deleted.

```bash
curl -X PATCH "https://api.voicebip.com/v1/workspace" \
  -H "Authorization: Bearer pk_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{"retention_days": 90}'
```

### Data Processing Agreement

* **Accept the DPA.** Under NDPR, processing Nigerian personal data requires adequate safeguards, explicit user consent, and a documented Data Protection Impact Assessment. Voicebip handles infrastructure-level safeguards; you are responsible for obtaining user consent in your application.

## Error Handling

### Check error_code in Responses

Every Voicebip API error response includes a structured error envelope. Always check `error_code` rather than parsing the `message` string.

```json
{
  "error_code": "RATE_LIMITED",
  "message": "Rate limit exceeded. Retry after 12 seconds.",
  "request_id": "req_abc123def456",
  "documentation_url": "https://docs.voicebip.com/errors/RATE_LIMITED"
}
```

### Idempotent Webhook Handlers

Every webhook event includes a unique `event_id`. Use it to deduplicate events, since Voicebip's retry mechanism (7 attempts with exponential backoff) may deliver the same event multiple times. The same `event_id` is used across all retries.

```javascript
const processedEvents = new Set(); // Use Redis in production

app.post("/webhook", (req, res) => {
  const { event_id } = req.body;

  if (processedEvents.has(event_id)) {
    // Already processed — return 200 to stop retries
    return res.json({ status: "ok" });
  }

  processedEvents.add(event_id);

  // Process the event...
  res.json({ status: "ok" });
});
```

### Handle 429 with Retry-After

When you receive an HTTP 429 response, read the `Retry-After` header and wait before retrying.

```javascript
const response = await fetch("https://api.voicebip.com/v1/calls", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${apiKey}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify(callPayload),
});

if (response.status === 429) {
  const retryAfter = parseInt(response.headers.get("Retry-After"), 10);
  console.log(`Rate limited. Retrying in ${retryAfter} seconds.`);
  await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
  // Retry the request...
}
```

## Latency Optimization

### Use Hosted AI Mode for Sub-500ms Turns

| Mode      | Turn Latency (P95)              | Best For                            |
| --------- | ------------------------------- | ----------------------------------- |
| Hosted AI | \< 500ms                        | Standard use cases, lowest latency  |
| BYOM      | 500ms + your webhook round-trip | Custom LLMs, complex business logic |

If sub-500ms turn times are critical (e.g., interactive IVR, real-time customer support), use **hosted AI mode**. Voicebip runs the AI provider inside its own infrastructure, eliminating the webhook round-trip.

### Minimize Webhook Handler Processing

For BYOM integrations, the voice pipeline is:

```
Caller speaks -> STT transcribes -> Webhook to your server -> Your LLM call ->
Response back to Voicebip -> TTS synthesizes -> Caller hears response
```

Every millisecond in your webhook handler adds to the caller's wait time. Optimize by pre-warming LLM connections, using the `conversation_history` field (Voicebip sends the last 20 turns so you do not need a database lookup), and setting aggressive timeouts on your LLM calls.

### Keep conversation_history Under 20 Turns

Voicebip automatically trims conversation history to the last 20 turns in every BYOM webhook event. This keeps payloads small and LLM context windows efficient. You do not need to manage history trimming yourself.

### Consider the Live Streaming Model for Real-Time Audio

For the absolute lowest latency, consider using Voicebip's hosted AI mode with a live streaming model. This mode streams audio bidirectionally, bypassing the traditional STT -> LLM -> TTS pipeline entirely, enabling near-real-time conversational AI. See `GET /v1/ai/models` for the available hosted models.