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

# Balance and Pricing

> Overview of pricing models, balance lifecycle, and billing states.

This page gives a high-level view of TAMradar billing and lifecycle behavior.

For model-specific implementation details:

* [Monthly Subscription Billing](/guides/balance-monthly-subscription)
* [Update-Based Billing](/guides/balance-update-based)

## Overview

TAMradar uses a **USD credit balance** system to bill for radar usage. Two pricing models exist, and which one applies to a radar depends on your account configuration per radar type.

***

## Pricing Models

### Monthly Subscription

* **Charge at creation** — balance is deducted when the radar is first created.
* **Recurring charge** — deducted automatically every 30 days while the radar is active. `next_charge_at` in the API response shows the next billing date.
* **Refund on setup failure** — if the radar fails during initial setup (missing prerequisites, source inaccessible), the creation charge is automatically reversed and you receive a `radar_failure` webhook with `refund_amount_usd > 0`.
* **User cancellation** — radar transitions to `inactive`. For monthly subscription, service can continue until the current billing period ends.

### Update-Based

* **No charge at creation** — `next_charge_at` is `null`. Nothing is deducted when the radar is set up.
* **Charged per update found** — balance is deducted each time TAMradar finds and approves a new update for your radar (a new hire, job change, funding round, etc.).
* **No refund on setup failure** — if the radar fails during setup, you receive a `radar_failure` webhook with `refund_amount_usd: 0` (nothing was charged, so nothing to refund).
* **Auto-reactivation on top-up** — if a radar was deactivated due to insufficient funds, it automatically reactivates when a new payment is added to your account. No manual action needed.

***

## Radar States

`radar_status` in public API responses is intentionally simplified to two values:

| Public `radar_status` | Meaning                                                                                        |
| --------------------- | ---------------------------------------------------------------------------------------------- |
| `active`              | Running normally. Balance is deducted per the pricing model.                                   |
| `inactive`            | Any non-active lifecycle state (cancelled, failed, insufficient funds, or grace-period state). |

Internal lifecycle enums are implementation details and are not part of the public API contract.
For external handling, use:

* `radar_status` (`active` / `inactive`)
* `radar_failure` payload fields: `code`, `message`, and `refund_amount_usd`

***

## Monitoring Balance Events

### Webhook Notifications

Your application receives `radar_failure` webhook events whenever a radar is deactivated due to a billing or setup issue.

**Monthly subscription — insufficient funds during renewal**

Radar is deactivated when the 30-day charge cannot be covered. No refund (the original creation charge was for time already used).

```json theme={null}
{
  "update_id": "550e8400-e29b-41d4-a716-446655440000",
  "update_type": "radar_failure",
  "record_id": null,
  "discovered_at": "2025-03-20T14:10:38Z",
  "completed_at": "2025-03-20T14:10:38Z",
  "data": {
    "radar_id": "54e32291-25a4-459f-8bd6-4f79489ea931",
    "radar_type": "company_new_hires",
    "domain": "example.com",
    "next_charge_at": null,
    "custom_fields": {}
  },
  "status": "error",
  "code": 402,
  "message": "Your radar was deactivated due to insufficient funds. Please add more credits to reactivate.",
  "errors": [{ "field": "radar", "reason": "insufficient_funds" }],
  "refund_amount_usd": 0,
  "timestamp": "2025-03-20T14:10:38Z",
  "error_id": "550e8400-e29b-41d4-a716-446655440000"
}
```

**Monthly subscription — setup failure (with refund)**

Radar failed during initial setup. Creation charge is reversed automatically.

```json theme={null}
{
  "update_id": "41991828-ed31-4bd9-98d2-44b2763f9f35",
  "update_type": "radar_failure",
  "record_id": null,
  "discovered_at": "2025-03-20T08:30:00Z",
  "completed_at": "2025-03-20T08:30:00Z",
  "data": {
    "radar_id": "c70813b3-7e87-4ca7-90fd-8c64574d911b",
    "radar_type": "industry_job_openings",
    "domain": null,
    "next_charge_at": null,
    "custom_fields": {}
  },
  "status": "error",
  "code": 400,
  "message": "Radar creation failed: missing prerequisites.",
  "errors": [{ "field": "radar", "reason": "missing_prerequisites" }],
  "refund_amount_usd": 0.10,
  "timestamp": "2025-03-20T08:30:00Z",
  "error_id": "41991828-ed31-4bd9-98d2-44b2763f9f35"
}
```

**Update-based — setup failure (no refund)**

Same webhook shape, but `refund_amount_usd` is always `0` because nothing was charged at creation.

```json theme={null}
{
  "update_id": "72bc9a00-1234-4abc-b000-aabbccddeeff",
  "update_type": "radar_failure",
  "record_id": null,
  "discovered_at": "2025-03-21T10:00:00Z",
  "completed_at": "2025-03-21T10:00:00Z",
  "data": {
    "radar_id": "a1b2c3d4-0000-0000-0000-000000000001",
    "radar_type": "contact_job_changes",
    "domain": "example.com",
    "next_charge_at": null,
    "custom_fields": {}
  },
  "status": "error",
  "code": 400,
  "message": "Radar creation failed: missing prerequisites.",
  "errors": [{ "field": "radar", "reason": "missing_prerequisites" }],
  "refund_amount_usd": 0,
  "timestamp": "2025-03-21T10:00:00Z",
  "error_id": "72bc9a00-1234-4abc-b000-aabbccddeeff"
}
```

### Failure Reasons

Failure type is identified by `code` and `message` in the `radar_failure` payload.

| Failure type          | `code` | Description                                                              | Refund                              |
| --------------------- | ------ | ------------------------------------------------------------------------ | ----------------------------------- |
| Missing prerequisites | 400    | Required public data not found (e.g. no LinkedIn profile, no public RSS) | Monthly sub: yes. Update-based: no. |
| Source inaccessible   | 400    | Data source exists but cannot be accessed                                | Monthly sub: yes. Update-based: no. |
| Setup failure         | 400    | Generic failure during radar initialisation                              | Monthly sub: yes. Update-based: no. |
| Insufficient funds    | 402    | Radar deactivated — balance too low for renewal charge                   | No refund                           |

***

## Bulk Endpoint — Async Outcomes

`POST /v1/radars/bulk` is asynchronous. The submission endpoint returns `202` with `bulk_id`, and item outcomes are emitted later.

For balance-related failures in bulk:

* the affected item ends in a failure state during async processing
* the failure appears in:
  * `GET /v1/radars/bulk/:bulk_id` item results, and
  * webhook delivery (`radar_failure` for item-level failures, plus final `bulk_completed`)

Treat bulk as a queued workflow rather than a synchronous per-item response.

***

## Best Practices

1. **Monitor balance** — poll `GET /v1/account` for `balance_remaining_usd` and alert before it hits zero.
2. **Handle `radar_failure` webhooks** — persist `code`, `message`, and `refund_amount_usd` for reconciliation.
3. **Update-based: top up proactively** — radars auto-reactivate on top-up, but there's a gap while they're inactive. Schedule automatic top-ups to avoid missed updates.
4. **Monthly subscription: budget for renewals** — check `next_charge_at` on your active radars and ensure balance covers the next 30 days.
5. **Bulk retries are workflow-based** — top up balance, then resubmit the failed items from your async bulk status/webhook outcomes.
