> ## Documentation Index
> Fetch the complete documentation index at: https://dynamo-csms.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Billing Rules API — Conditional and Time-Based Pricing

> Create conditional billing rules that apply discounts, override prices, or grant free sessions based on time of day, user type, or day of week.

Billing rules let you define conditional logic that modifies how sessions are priced. A rule is made up of **conditions** — criteria that must be true for the rule to fire — and **actions** — the pricing modifications to apply when they do.

Rules are evaluated at session close. When multiple rules match a session, they are applied in priority order (lowest number = highest priority).

## Conditions

| Condition        | Description                                                            |
| ---------------- | ---------------------------------------------------------------------- |
| `time_of_day`    | Matches sessions that started between two times (e.g. `07:00`–`09:00`) |
| `day_of_week`    | Matches sessions on specific days (e.g. `["sat", "sun"]`)              |
| `user_type`      | Matches sessions where the driver belongs to a named user type         |
| `charger_id`     | Matches sessions on a specific charger                                 |
| `site_id`        | Matches sessions at a specific site                                    |
| `min_energy_kwh` | Matches sessions delivering at least N kWh                             |
| `max_energy_kwh` | Matches sessions delivering at most N kWh                              |

## Actions

| Action             | Description                                                  |
| ------------------ | ------------------------------------------------------------ |
| `apply_discount`   | Reduce the total cost by a percentage                        |
| `override_price`   | Replace the per-kWh rate with a fixed value                  |
| `free_session`     | Set the total cost to zero                                   |
| `add_flat_fee`     | Add a fixed amount to the total                              |
| `remove_component` | Remove a specific tariff component (e.g. remove parking fee) |

***

## Create a billing rule

`POST /api/v1/billing/rules`

<ParamField body="name" type="string" required>
  Display name for the rule.
</ParamField>

<ParamField body="priority" type="number" required>
  Evaluation order. Lower numbers are evaluated first. Must be a positive integer.
</ParamField>

<ParamField body="conditions" type="object[]" required>
  Array of condition objects. All conditions must match for the rule to fire.

  <Expandable title="condition properties">
    <ParamField body="type" type="string" required>
      Condition type. See condition table above.
    </ParamField>

    <ParamField body="value" type="any" required>
      The value to match against. Type varies by condition: string, string array, or number.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="actions" type="object[]" required>
  Array of action objects to apply when conditions are met.

  <Expandable title="action properties">
    <ParamField body="type" type="string" required>
      Action type. See action table above.
    </ParamField>

    <ParamField body="value" type="any">
      Action parameter. For `apply_discount`, this is the percentage (e.g. `10` for 10%). For `override_price`, this is the new price per kWh. Omit for `free_session`.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="active" type="boolean" default="true">
  Whether the rule is active. Inactive rules are stored but never evaluated.
</ParamField>

```bash theme={null}
curl -X POST "https://api.dynamo-csms.com/api/v1/billing/rules" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Weekend off-peak discount",
    "priority": 10,
    "active": true,
    "conditions": [
      {
        "type": "day_of_week",
        "value": ["sat", "sun"]
      },
      {
        "type": "time_of_day",
        "value": { "start": "21:00", "end": "07:00" }
      }
    ],
    "actions": [
      {
        "type": "apply_discount",
        "value": 25
      }
    ]
  }'
```

```json theme={null}
{
  "rule_id": "rule_8MXQP",
  "name": "Weekend off-peak discount",
  "priority": 10,
  "active": true,
  "conditions": [
    { "type": "day_of_week", "value": ["sat", "sun"] },
    { "type": "time_of_day", "value": { "start": "21:00", "end": "07:00" } }
  ],
  "actions": [
    { "type": "apply_discount", "value": 25 }
  ],
  "created_at": "2024-06-01T12:00:00Z"
}
```

<ResponseField name="rule_id" type="string">
  Unique identifier for the created rule.
</ResponseField>

<ResponseField name="priority" type="number">
  Evaluation order for this rule.
</ResponseField>

<ResponseField name="active" type="boolean">
  Whether the rule is currently being evaluated.
</ResponseField>

***

## List billing rules

`GET /api/v1/billing/rules`

Returns all billing rules for your organisation, ordered by priority.

<ParamField query="active" type="boolean">
  Filter by active status. Set to `true` to return only active rules.
</ParamField>

```bash theme={null}
curl "https://api.dynamo-csms.com/api/v1/billing/rules" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

```json theme={null}
{
  "rules": [
    {
      "rule_id": "rule_8MXQP",
      "name": "Weekend off-peak discount",
      "priority": 10,
      "active": true,
      "conditions": [
        { "type": "day_of_week", "value": ["sat", "sun"] }
      ],
      "actions": [
        { "type": "apply_discount", "value": 25 }
      ],
      "created_at": "2024-06-01T12:00:00Z"
    },
    {
      "rule_id": "rule_3KLPN",
      "name": "Free sessions for staff",
      "priority": 1,
      "active": true,
      "conditions": [
        { "type": "user_type", "value": "staff" }
      ],
      "actions": [
        { "type": "free_session" }
      ],
      "created_at": "2024-06-01T11:00:00Z"
    }
  ],
  "total": 2
}
```

***

## Get a billing rule

`GET /api/v1/billing/rules/{rule_id}`

<ParamField path="rule_id" type="string" required>
  The unique identifier of the billing rule.
</ParamField>

```bash theme={null}
curl "https://api.dynamo-csms.com/api/v1/billing/rules/rule_8MXQP" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

***

## Update a billing rule

`PUT /api/v1/billing/rules/{rule_id}`

Replaces all fields on a billing rule. Changes apply to sessions closed after the update.

<ParamField path="rule_id" type="string" required>
  The unique identifier of the billing rule.
</ParamField>

<ParamField body="name" type="string" required>
  Updated rule name.
</ParamField>

<ParamField body="priority" type="number" required>
  Updated priority.
</ParamField>

<ParamField body="conditions" type="object[]" required>
  Full replacement condition set.
</ParamField>

<ParamField body="actions" type="object[]" required>
  Full replacement action set.
</ParamField>

<ParamField body="active" type="boolean" required>
  Active status.
</ParamField>

```bash theme={null}
curl -X PUT "https://api.dynamo-csms.com/api/v1/billing/rules/rule_8MXQP" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Weekend off-peak discount",
    "priority": 10,
    "active": false,
    "conditions": [
      { "type": "day_of_week", "value": ["sat", "sun"] }
    ],
    "actions": [
      { "type": "apply_discount", "value": 25 }
    ]
  }'
```

***

## Delete a billing rule

`DELETE /api/v1/billing/rules/{rule_id}`

<ParamField path="rule_id" type="string" required>
  The unique identifier of the billing rule to delete.
</ParamField>

```bash theme={null}
curl -X DELETE "https://api.dynamo-csms.com/api/v1/billing/rules/rule_8MXQP" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

Returns `204 No Content` on success.

***

## Test a billing rule

`POST /api/v1/billing/rules/{rule_id}/test`

Evaluates a rule against a hypothetical session without creating any real charges. Use this to verify that your conditions and actions behave as expected before activating a rule.

<ParamField path="rule_id" type="string" required>
  The rule to test.
</ParamField>

<ParamField body="session" type="object" required>
  Hypothetical session data to test against.

  <Expandable title="session properties">
    <ParamField body="started_at" type="string" required>ISO 8601 session start time.</ParamField>
    <ParamField body="ended_at" type="string" required>ISO 8601 session end time.</ParamField>
    <ParamField body="energy_kwh" type="number" required>Energy delivered in kWh.</ParamField>
    <ParamField body="charge_point_id" type="string">Charger the session was on.</ParamField>
    <ParamField body="site_id" type="string">Site the session was at.</ParamField>
    <ParamField body="user_type" type="string">User type of the driver.</ParamField>
    <ParamField body="base_cost" type="number" required>Starting cost before any rules are applied.</ParamField>
    <ParamField body="currency" type="string" required>Currency code.</ParamField>
  </Expandable>
</ParamField>

```bash theme={null}
curl -X POST "https://api.dynamo-csms.com/api/v1/billing/rules/rule_8MXQP/test" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "session": {
      "started_at": "2024-06-15T22:30:00Z",
      "ended_at": "2024-06-16T00:15:00Z",
      "energy_kwh": 12.8,
      "charge_point_id": "CP-001",
      "site_id": "site_01HZ4K8XVPQR3TY5N6M",
      "user_type": "public",
      "base_cost": 4.48,
      "currency": "GBP"
    }
  }'
```

```json theme={null}
{
  "rule_id": "rule_8MXQP",
  "rule_name": "Weekend off-peak discount",
  "matched": true,
  "conditions_evaluated": [
    { "type": "day_of_week", "value": ["sat", "sun"], "result": true },
    { "type": "time_of_day", "value": { "start": "21:00", "end": "07:00" }, "result": true }
  ],
  "actions_applied": [
    { "type": "apply_discount", "value": 25, "description": "25% discount applied" }
  ],
  "base_cost": 4.48,
  "adjusted_cost": 3.36,
  "savings": 1.12,
  "currency": "GBP"
}
```

<ResponseField name="matched" type="boolean">
  Whether all conditions matched the hypothetical session.
</ResponseField>

<ResponseField name="conditions_evaluated" type="object[]">
  Each condition and whether it matched.
</ResponseField>

<ResponseField name="actions_applied" type="object[]">
  Actions that were applied and a description of the effect.
</ResponseField>

<ResponseField name="base_cost" type="number">
  Cost before the rule was applied.
</ResponseField>

<ResponseField name="adjusted_cost" type="number">
  Cost after the rule was applied.
</ResponseField>

<ResponseField name="savings" type="number">
  Difference between base cost and adjusted cost.
</ResponseField>
