# Projects and budgets

A project is a cost centre inside your account: which team, client or campaign a call is billed to, and — if you want — a monthly ceiling that stops it spending more than that.

## What a project is not

> **A project is not a tenant and isolates nothing.** Two projects in one account can share agents, numbers and knowledge bases, and a key scoped to your account can read across all of them. If you need one customer's data unreachable from another's, that is separate accounts, not separate projects.

Nor is it an agent group. A [group](https://voice.sphoro.com/docs/agent-groups) shares *configuration*; a project attributes *cost*. An agent belongs to at most one of each, and they do not interact.

## Creating one

`POST /v1/projects`

**Shell**

```bash
curl -s -X POST https://voice.sphoro.com/v1/projects \
  -H "Authorization: Bearer $SPHORO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Clinic",
    "monthly_budget": 50000,
    "over_budget": "refuse"
  }'
```

| Field | Type | Description |
| --- | --- | --- |
| `name` required | string | What you call it. |
| `description` optional | string | Yours. |
| `monthly_budget` optional | number | The ceiling for a calendar month. Omit for no ceiling — attribution without a limit, which is what most projects want. |
| `over_budget` optional | string | What happens past the ceiling. Refusing new calls is the safe default; the alternative is to keep dialling and let the overrun be visible in [analytics](https://voice.sphoro.com/docs/analytics). |
| `metadata` optional | object | Yours. |

## Attributing work to it

Set `project_id` on the agent, and every call that agent takes or places is attributed there. A knowledge base can carry one too, so ingestion is billed with the work it serves.

**Shell**

```bash
curl -s -X PATCH https://voice.sphoro.com/v1/agents/$AGENT_ID \
  -H "Authorization: Bearer $SPHORO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"project_id": "prj_6e2f90c1a4b73d85"}'
```

## Going over budget

A call refused because its project is over budget ends with `end_reason: over_budget` — and inbound callers hear the busy line rather than silence.

> **A budget stops inbound calls too.** That surprises people: a project that runs out mid-month stops *answering the phone*, not just stops dialling. On a support line that is usually not what anybody wanted. Either leave the budget off and watch analytics, or put the inbound line in its own project.

## The endpoints

| Endpoint | Does |
| --- | --- |
| `POST /v1/projects` | Create one. |
| `GET /v1/projects` | List them, with spend against budget. |
| `GET /v1/projects/{id}` | Read one. |
| `PATCH /v1/projects/{id}` | Change the budget or the name. |
| `DELETE /v1/projects/{id}` | Remove it. Finished calls keep their attribution. |

**Shell**

```bash
curl -s https://voice.sphoro.com/v1/projects \
  -H "Authorization: Bearer $SPHORO_API_KEY"
```

## Slicing analytics by project

Every analytics query takes a project, which is the point of the whole feature: what did this client cost us this month, and how does that compare to last.

`GET /v1/analytics/overview`

**Shell**

```bash
curl -s "https://voice.sphoro.com/v1/analytics/overview?project_id=$PROJECT_ID&from=2026-09-01&to=2026-09-30" \
  -H "Authorization: Bearer $SPHORO_API_KEY"
```

See [analytics](https://voice.sphoro.com/docs/analytics).

## How to divide them up

| If you are | A project per |
| --- | --- |
| An agency running calls for clients | Client. This is the case the feature exists for. |
| Running campaigns against your own list | Campaign, so a month's spend is attributable to the thing that caused it. |
| One product with a support line | Probably nothing — one project, no budget, and watch analytics. |
