> ## Documentation Index
> Fetch the complete documentation index at: https://withkazi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Call Billing, Rates, and Usage Tracking

> LaraCopilot tracks per-call costs via call detail records (CDRs) and lets you configure per-tenant rates to calculate billing automatically.

LaraCopilot records every call as a Call Detail Record (CDR) and matches it against a tenant-specific rate table to compute the cost. This gives you an auditable, per-second billing log that can drive invoicing, usage dashboards, and capacity planning without any external billing middleware.

## Call Detail Records (CDRs)

A CDR is written at the end of every call and captures the full context needed to bill the call accurately. The fields stored on each `Cdr` record are:

| Field                | Type           | Description                                                    |
| -------------------- | -------------- | -------------------------------------------------------------- |
| `tenant_id`          | integer        | Tenant that owns this call record                              |
| `extension_id`       | integer        | Extension that handled the call, if applicable                 |
| `caller_number`      | string         | The originating phone number                                   |
| `destination_number` | string         | The number that was dialled                                    |
| `direction`          | string         | `inbound` or `outbound`                                        |
| `disposition`        | string         | Outcome of the call (e.g. `ANSWERED`, `NO_ANSWER`, `BUSY`)     |
| `duration_seconds`   | integer        | Wall-clock length of the call in seconds                       |
| `bill_seconds`       | integer        | Billable seconds after applying the rate's `billing_increment` |
| `cost`               | decimal (4 dp) | Computed cost for this call                                    |
| `started_at`         | datetime       | When the call was connected                                    |
| `ended_at`           | datetime       | When the call ended                                            |

<Note>
  `duration_seconds` is the actual call length. `bill_seconds` may differ because rates apply a `billing_increment` that rounds up to the nearest increment boundary (e.g. a 6-second increment means a 7-second call bills as 12 seconds).
</Note>

## Rates

Rates define the cost of calls to a given destination for a specific tenant. LaraCopilot matches an outbound `destination_number` against the rate `prefix` table to find the correct rate, then applies it to `bill_seconds` to produce `cost`.

| Field               | Type           | Description                                                            |
| ------------------- | -------------- | ---------------------------------------------------------------------- |
| `tenant_id`         | integer        | Tenant this rate applies to                                            |
| `prefix`            | string         | Dialling prefix used to match destination numbers (e.g. `1`, `44`)     |
| `destination`       | string         | Human-readable destination name (e.g. `USA`, `UK Landline`)            |
| `cost_per_minute`   | decimal (4 dp) | Rate charged per minute of billable time                               |
| `billing_increment` | integer        | Minimum billing unit in seconds; calls are rounded up to this boundary |
| `status`            | string         | Whether the rate is active or inactive                                 |

### Cost Calculation

The formula applied to each CDR is:

```
cost = (bill_seconds / 60) × cost_per_minute
```

`bill_seconds` is already rounded up to the nearest `billing_increment` before this calculation runs, so the effective minimum charge per call is:

```
(billing_increment / 60) × cost_per_minute
```

<Tip>
  Use a `billing_increment` of `6` for modern telecom-style billing or `60` for simpler per-minute rounding. Smaller increments give callers a fairer cost at the expense of slightly more complex invoices.
</Tip>

## API Reference

### Retrieving CDRs

```
GET /api/cdrs
```

Returns all CDR records with their associated tenant and extension. Supports a `search` query parameter that filters on `caller_number`, `destination_number`, `direction`, and `disposition`.

```json Sample response theme={null}
{
  "message": "CDRs fetched successfully.",
  "data": [
    {
      "id": 501,
      "tenant_id": 7,
      "caller_number": "+14155550100",
      "destination_number": "+14085550199",
      "direction": "outbound",
      "disposition": "ANSWERED",
      "duration_seconds": 125,
      "bill_seconds": 126,
      "cost": "0.0420",
      "started_at": "2026-04-22T09:00:00Z",
      "ended_at": "2026-04-22T09:02:05Z"
    }
  ]
}
```

### Managing Rates

```
GET  /api/rates          # List all rates (supports ?search=)
POST /api/rates          # Create a new rate
GET  /api/rates/{id}     # Retrieve a single rate
PUT  /api/rates/{id}     # Update a rate
DELETE /api/rates/{id}   # Delete a rate
```

<CodeGroup>
  ```json POST /api/rates — request body theme={null}
  {
    "tenant_id": 7,
    "prefix": "1",
    "destination": "USA",
    "cost_per_minute": "0.0200",
    "billing_increment": 6,
    "status": "active"
  }
  ```

  ```json POST /api/rates — response (201) theme={null}
  {
    "message": "Rate created successfully.",
    "data": {
      "id": 42,
      "tenant_id": 7,
      "prefix": "1",
      "destination": "USA",
      "cost_per_minute": "0.0200",
      "billing_increment": 6,
      "status": "active"
    }
  }
  ```
</CodeGroup>

<Warning>
  Changing `cost_per_minute` or `billing_increment` on an existing rate does not retroactively recalculate historical CDRs. Old CDR costs are immutable once written.
</Warning>

<Tip>
  Query `GET /api/cdrs` with a `search` filter to retrieve call records for a specific number or direction and generate usage reports for individual tenants.
</Tip>
