# Security and data

What Sphoro Voice holds, what separates your account from anybody else's, how long each kind of thing is kept, and what is never stored at all.

## What isolates one account from another

Every request carries a credential, and the credential — not a parameter in the request — decides which account's data it can reach. There is no request shape that reaches across accounts, which is why an id from another account reads as "not found" rather than "forbidden": the object is not merely refused, it is not visible.

|  |  |
| --- | --- |
| Agents, calls, transcripts, recordings, analytics | Scoped to the account the key belongs to. |
| Knowledge bases | Held in a separate service, under a credential minted for your account alone. A fault in this platform cannot reach another account's documents, because the credential it holds cannot. |
| Projects | **Not** an isolation boundary. A cost label inside one account. See [projects](https://voice.sphoro.com/docs/projects). |

You can see that for yourself: ask for an object that is not yours and the answer is `404`, not `403`.

**Shell**

```bash
# What this key can actually do.
curl -s https://voice.sphoro.com/v1/agents \
  -H "Authorization: Bearer $SPHORO_API_KEY"

# An id from somewhere else: not found, rather than forbidden.
curl -s -o /dev/null -w '%{http_code}\n' https://voice.sphoro.com/v1/agents/agt_000000000000000 \
  -H "Authorization: Bearer $SPHORO_API_KEY"
```

## Credentials

| Credential | Lives | Belongs |
| --- | --- | --- |
| API key | Until you revoke it, or its expiry | On your server, in a secret store. **Never** in a page, an app bundle, or a repository. |
| Call token | Minutes, scoped to one call | In a browser. This is the only credential that should ever reach one. |
| Webhook signing secret | Until rotated | On your server, used to verify what we send you. |

> **A key in a browser is a key in the hands of every visitor.** Anyone can read it out of the page and place calls on your account until you notice. The whole purpose of `POST /v1/realtime/tokens` is to make shipping a key unnecessary — see [talk from a browser](https://voice.sphoro.com/docs/browser).

Keys carry **scopes**, and the right key for a job is the narrowest one that does it: a dashboard that reads calls does not need to be able to create agents. See [get an API key](https://voice.sphoro.com/docs/api-keys).

## In transit

- Every API request is HTTPS. There is no plaintext endpoint.
- Webhook endpoints must be `https` — an `http` URL is refused, because delivering a call transcript over it would put a conversation on the wire in the clear.
- Every request the platform makes on your behalf — a knowledge-base crawl, a journey's API node, a webhook delivery — goes through a guard that validates the resolved address immediately before connecting. A URL you supply is input, and it does not get to name a private address.

## What is kept, and for how long

| Data | Kept |
| --- | --- |
| Call records — times, numbers, direction, end reason, cost | For the life of the account. |
| Transcripts | With the call record. |
| Summaries and extractions | With the call record. |
| Audio recordings | Only if `record_calls` is on, and then for the retention window agreed with your account. |
| Knowledge-base documents | Until you delete them. |
| Suppression list and consent records | Indefinitely — deleting a do-not-call entry is not a thing you want to happen automatically. |
| API keys | Stored hashed. The key itself is shown once, at creation, and cannot be retrieved afterwards. |

Retention is set per account rather than per agent, because it is a policy rather than a setting. [Tell us](https://voice.sphoro.com/docs/support) what your obligations are and it is configured to them.

## What is never stored

- **Audio, unless you asked for it.** With `record_calls` off, the audio of a call passes through and is not written down. The transcript is, because transcription is how the agent hears the caller at all.
- **The audio of a bridged call, ever.** On a `webrtc` agent the media runs directly between the two clients and does not reach this deployment. See [the realtime protocol](https://voice.sphoro.com/docs/realtime).
- **Anything on a `simple` agent's call.** A person holds that call from their browser; no recogniser, model or synthesiser is opened for it, and there is no transcript because nothing on this side heard it.
- **Your API key in readable form.**

## Where calls are processed

Your account runs in one region, and the speech and language vendors behind it are part of that picture — a model call leaves the platform even when the call does not leave the region. If data residency is a requirement rather than a preference, two things are worth knowing:

- The model chain speaks the OpenAI wire format, and several presets are **self-hosted runtimes**. A deployment that must keep transcripts inside its own network can point the model at one. See [vendors](https://voice.sphoro.com/docs/providers).
- Dedicated and in-region deployments are available. [Talk to us](https://voice.sphoro.com/docs/support) before you build, not after.

## Recording, consent and the law

> **Recording is a legal decision before it is a technical one.** Most jurisdictions require the caller to be told and several require consent. Put the notice in the greeting. This is also why an [agent group](https://voice.sphoro.com/docs/agent-groups) can never switch recording on for the members it already has — it must be adopted per line, by somebody who knows the consent position for that line.

Outbound calling has its own rules, and they are enforced rather than documented: the suppression list, consent records, and calling hours in the timezone the number actually belongs to. See [compliance](https://voice.sphoro.com/docs/compliance).

## If something goes wrong

If you believe a credential has leaked, revoke it in [the portal](https://voice.sphoro.com/portal) first and tell us second — revocation is immediate and does not need us. If you have found a vulnerability, [get in touch](https://voice.sphoro.com/docs/support) before disclosing it anywhere else.
