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

# Enroll Voice Clones from Calls

> Train a custom TTS voice from a recorded enrollment call (or an uploaded sample), with consent attestations, cloning credits, and synthetic-voice watermarking — then use the clone for hear-what-your-customers-hear QA and voice-agent rollout.

# Enroll Voice Clones from Calls

A voice clone is a custom TTS voice your organization trains from real audio.
The most common source is an **enrollment call**: a recorded call in your
account where the speaker you want to clone gave their blessing to be
recorded. You can also clone from an audio sample you host yourself, or —
when there is no real person's voice involved — design a fully synthetic
voice from a text description.

This guide covers the consent gates, how clones are priced, how to track a
clone through its lifecycle, and how to mark synthesized output with a
watermark. Open the working surface at **Voice → Voice clones**
(`/voice/voice-clones`), or drive the same lifecycle over the API.

The endpoint paths below are relative. Send them against
`https://api.orbit.devotel.io/api/v1`.

## Why enroll from a call

Use a phone-enrolled clone to hear exactly what your customers will hear
before you roll a new voice into production:

* **QA a new IVR or agent voice.** Check pronunciation, pacing, and tone of
  *your* brand voice against a script before it answers a single call.
* **Audition agent voices end to end.** Pair a clone with the
  [AI agent rollout pipeline](/guides/ai-agent-rollout-pipeline): roll the
  voice behind the same offline comparison, canary, and regression stages
  that gate prompt and model changes.
* **Keep the brand voice consistent** across IVR, outbound dialer, and agent
  surfaces by pointing them all at one trained clone.

## 1. Enrollment-call provenance (`source_call_id`)

Every clone records *where its training audio came from* in
`source_call_id`:

* A clone trained from a recorded call stores that call's ID. The clone
  traces back to a specific recording — enough to answer "which call did
  this voice come from?" during a review.
* A clone trained from an uploaded sample, or designed from a text prompt,
  has no source call — it stores the sample URL or prompt as its provenance
  instead.

To enroll from a call, the call must already exist with a usable recording.
Prerequisites:

1. **A recorded enrollment call.** Record the call with `record: true` at
   call creation (see [Record a call](/sdks/node#record-a-call)), then use
   the call's ID as `call_id`. A short, clean enrollment recording — one
   speaker, minimal background noise, a minute or three of speech — trains
   a markedly better clone than a noisy hour.
2. **Recording consent on that call.** The source call must carry an
   active recording-consent receipt (`consent_state='granted'`, not
   revoked). Without it, the create call is refused with
   `VOICE_CLONE_CONSENT_REQUIRED` — recording consent is the floor for the
   audio existing at all. Cloning is a *separate* consent surface on top of
   it.
3. **A voice-owner attestation** (below).

Create the clone:

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/voice/clones \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "agent-aria",
    "call_id": "call_abc123",
    "voice_owner_relationship": "employee",
    "voice_owner_consent_text": "Ari S. (staff) signed a voice-release on 2026-08-10 covering IVR and agent synthesis use",
    "biometric_consent_acknowledged": true
  }'
```

Or from the [Node SDK](/sdks/node):

```typescript theme={null}
const clone = await orbit.voice.clones.create({
  name: 'agent-aria',
  call_id: 'call_abc123',
});
```

The API prefix is `https://api.orbit.devotel.io/api/v1`; the SDK sends the
full consent fields — pass the same attestation fields shown in the curl
example for enrollments that are not self-recorded.

### Upload a sample instead

No recorded call yet? Host a short audio sample (picked from a voice-actor
session or narrator recording) behind an `https://` URL you control and
clone from it directly:

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/voice/clones/upload \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "narrator",
    "audio_sample_url": "https://media.example.com/samples/narrator.mp3",
    "voice_owner_relationship": "actor_with_release",
    "voice_owner_consent_evidence_url": "https://media.example.com/consent/narrator-release.pdf",
    "biometric_consent_acknowledged": true
  }'
```

Orbit fetches the sample server-side — the URL must be publicly reachable
and the file under 25 MB. Uploaded-sample clones carry the same consent bar
as call-enrolled clones; they simply skip the recording-consent receipt
because no call exists.

### Design a synthetic voice instead

`POST /voice/clones/design` mints a brand-new synthetic voice from a text
prompt (for example, "a warm, mid-30s British woman with a calm,
professional tone"). There is no real person's voice to consent to, so the
recording-consent and attestation gates do not apply — designed voices list
alongside your clones the same way.

## 2. Watermarking and consent posture

Cloning a real person's voice implicates biometric-privacy law (BIPA in
Illinois, CUBI in Texas, and the EU AI Act's Article 50 transparency duty).
Devotel Orbit gates every biometric clone on controls that live in your
account, so the consent trail you build is yours:

* **Recording-consent receipt on the source call** — active, not revoked,
  and no older than one year. Recollect consent before cloning from an old
  recording.

* **A voice-owner attestation you supply at create time.** Either a
  `voice_owner_consent_evidence_url` (an `https://` link to a consent record
  you store — a signed release, an envelope, an in-app form) or a
  `voice_owner_consent_text` (at least 50 characters, stored verbatim),
  plus:

  * `voice_owner_relationship` — one of `self`, `employee`,
    `actor_with_release`, `customer_with_written_consent`, or `other`.
  * `biometric_consent_acknowledged: true` — your explicit acknowledgement
    of biometric-voiceprint obligations.

  The attestation text travels with the voice to the synthesis provider and
  is mirrored into your [Audit Log](/guides/audit-log), so the legal basis
  for each clone is one query away.

* **Watermarking the output.** In the dashboard, open a *ready* clone and
  choose **Watermark**; the dialog marks an audio clip with a provenance
  credential bound to the exact bytes and to your tenant. Over the API:

  * `POST /voice/clones/{id}/watermark` — supply `audio_base64` (the raw
    clip) or a pre-computed `audio_sha256` + `audio_bytes`. When raw audio
    is supplied, the mark is also embedded into the audio itself as a
    standard content credential any compatible verifier can read; when your
    AI-disclosure settings enable a spoken preamble, the configured audible
    disclaimer travels with the mark.
  * `POST /voice/clones/watermark/verify` — verify a mark, with
    audio-in-hand binding: a valid mark re-stapled onto different audio
    reports a mismatch instead of passing.

  Only a clone in `status: ready` can mark output; a clone still training
  or one that failed is refused. Whether marking satisfies a specific
  framework (EU AI Act Art 50, FCC synthetic-voice rules) depends on how
  you operate the account — the watermark is a control you own; the posture
  remains yours.

## 3. Provider tracking (`provider` + `provider_voice_id`)

Two fields connect a clone to the synthesis provider behind it:

* **`provider`** — which synthesis provider hosts the trained voice (for
  example, `elevenlabs`).
* **`provider_voice_id`** — the voice's identifier at that provider, once
  training succeeded. If you ever need to cross-reference a voice in the
  provider's own console, this is the join key.

When you delete a clone, Orbit also removes the voice at the provider
(best-effort, logged) before removing the record, so a deleted clone does
not linger as a usable voice upstream.

## 4. Pricing (`price_cents`)

The first clone per organization is free. Every clone after that costs
**500 cents (\$5.00)** from your credit wallet:

* The charged amount is stored on the clone as `price_cents` (the free
  clone stores `0`) and shown as a price badge next to the clone's name in
  the dashboard.
* If the wallet balance is too low, the create call returns `402` with
  `INSUFFICIENT_BALANCE` before any work starts.
* If provider training fails after a paid clone was charged, the credits
  are refunded automatically and the clone is marked `failed`.

## 5. List, create, and delete

| Operation                                    | API                                   | SDK                                     |
| -------------------------------------------- | ------------------------------------- | --------------------------------------- |
| List clones (newest first, cursor-paginated) | `GET /voice/clones`                   | `orbit.voice.clones.list()`             |
| Create from a recorded call                  | `POST /voice/clones`                  | `orbit.voice.clones.create()`           |
| Create from an uploaded sample               | `POST /voice/clones/upload`           | `orbit.voice.clones.uploadFromSample()` |
| Design a synthetic voice                     | `POST /voice/clones/design`           | —                                       |
| Delete                                       | `DELETE /voice/clones/{id}`           | `orbit.voice.clones.delete(id)`         |
| Watermark synthesized output                 | `POST /voice/clones/{id}/watermark`   | —                                       |
| Verify a watermark                           | `POST /voice/clones/watermark/verify` | —                                       |

In the dashboard, **Voice → Voice clones** (`/voice/voice-clones`) shows
each clone with its status, provider, creation time, price badge, a playback
sample from the source call, a **Watermark** action once ready, and delete —
the same list the API returns.

## 6. Status and failure handling

A clone moves through three statuses:

* **`processing`** — the sample was accepted and is training at the
  provider. Most clones finish shortly; the dashboard refreshes the list
  in place.
* **`ready`** — training succeeded, `provider_voice_id` is set, and the
  clone can synthesize and watermark output.
* **`failed`** — training did not complete: the provider rejected the
  sample, the sample URL could not be fetched, or the provider call failed.
  Any charged credits are refunded when this happens. The dashboard shows a
  failed badge and surfaces the underlying reason as a readable toast — the
  failure is never silent. Delete the failed clone and re-enroll from a
  cleaner sample.

### Errors you will hit and what they mean

| Error                              | Cause                                | Fix                                                                                                                                                                                                 |
| ---------------------------------- | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `422 VOICE_CLONE_CONSENT_REQUIRED` | Missing or weak consent input        | The source call lacks an active recording-consent receipt, the attestation is absent or under 50 characters, the evidence URL is not `https://`, or `biometric_consent_acknowledged` is not `true`. |
| `422 VALIDATION_ERROR`             | Source media unusable                | The call has no recording, the GCS recording URL is missing, or the uploaded sample was empty, over 25 MB, or unreachable.                                                                          |
| `402 INSUFFICIENT_BALANCE`         | Wallet below the clone price         | Top up credits, then retry.                                                                                                                                                                         |
| `404 NOT_FOUND`                    | Unknown clone ID on delete/watermark | Re-list and use a current ID.                                                                                                                                                                       |
| `503 SERVICE_UNAVAILABLE`          | Synthesis provider unavailable       | Retry later; contact support if it persists.                                                                                                                                                        |

## Next steps

* [AI agent rollout pipeline](/guides/ai-agent-rollout-pipeline) — put a new
  clone through offline comparison, canary, and regression stages before it
  answers production calls.
* [Audit Log](/guides/audit-log) — clone creation, deletion, and watermark
  events each write an audit entry with the consent basis attached.
* [Record a call](/sdks/node#record-a-call) — capture the enrollment call
  with `record: true` so it is clone-eligible.
