Delete a voice
curl --request DELETE \
--url https://fi.production.flamapis.com/flam-voice-svc/api/v1/public/voices/{id} \
--header 'X-API-Key: <api-key>'import requests
url = "https://fi.production.flamapis.com/flam-voice-svc/api/v1/public/voices/{id}"
headers = {"X-API-Key": "<api-key>"}
response = requests.delete(url, headers=headers)
print(response.text)const options = {method: 'DELETE', headers: {'X-API-Key': '<api-key>'}};
fetch('https://fi.production.flamapis.com/flam-voice-svc/api/v1/public/voices/{id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://fi.production.flamapis.com/flam-voice-svc/api/v1/public/voices/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "DELETE",
CURLOPT_HTTPHEADER => [
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://fi.production.flamapis.com/flam-voice-svc/api/v1/public/voices/{id}"
req, _ := http.NewRequest("DELETE", url, nil)
req.Header.Add("X-API-Key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.delete("https://fi.production.flamapis.com/flam-voice-svc/api/v1/public/voices/{id}")
.header("X-API-Key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://fi.production.flamapis.com/flam-voice-svc/api/v1/public/voices/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Delete.new(url)
request["X-API-Key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"data.deleted": true
}Endpoints
Delete a voice
Delete a voice from your workspace.
DELETE
/
flam-voice-svc
/
api
/
v1
/
public
/
voices
/
{id}
Delete a voice
curl --request DELETE \
--url https://fi.production.flamapis.com/flam-voice-svc/api/v1/public/voices/{id} \
--header 'X-API-Key: <api-key>'import requests
url = "https://fi.production.flamapis.com/flam-voice-svc/api/v1/public/voices/{id}"
headers = {"X-API-Key": "<api-key>"}
response = requests.delete(url, headers=headers)
print(response.text)const options = {method: 'DELETE', headers: {'X-API-Key': '<api-key>'}};
fetch('https://fi.production.flamapis.com/flam-voice-svc/api/v1/public/voices/{id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://fi.production.flamapis.com/flam-voice-svc/api/v1/public/voices/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "DELETE",
CURLOPT_HTTPHEADER => [
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://fi.production.flamapis.com/flam-voice-svc/api/v1/public/voices/{id}"
req, _ := http.NewRequest("DELETE", url, nil)
req.Header.Add("X-API-Key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.delete("https://fi.production.flamapis.com/flam-voice-svc/api/v1/public/voices/{id}")
.header("X-API-Key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://fi.production.flamapis.com/flam-voice-svc/api/v1/public/voices/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Delete.new(url)
request["X-API-Key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"data.deleted": true
}Deletes a voice. The voice must belong to the API key’s workspace, otherwise the request returns
404.
Deleting a voice frees a slot against your plan’s max_voices limit.
Authorization
string
required
Your workspace API key (
flv_…).Path parameters
string
required
The voice id.
Response
boolean
true when the voice was deleted.curl -X DELETE \
"https://fi.production.flamapis.com/flam-voice-svc/api/v1/public/voices/665f1a2b3c4d5e6f7a8b9c0d" \
-H "X-API-Key: $FLAM_API_KEY"
const id = "665f1a2b3c4d5e6f7a8b9c0d";
const res = await fetch(
`https://fi.production.flamapis.com/flam-voice-svc/api/v1/public/voices/${id}`,
{ method: "DELETE", headers: { "X-API-Key": process.env.FLAM_API_KEY } },
);
console.log((await res.json()).data.deleted);
import os, requests
voice_id = "665f1a2b3c4d5e6f7a8b9c0d"
res = requests.delete(
f"https://fi.production.flamapis.com/flam-voice-svc/api/v1/public/voices/{voice_id}",
headers={"X-API-Key": os.environ["FLAM_API_KEY"]},
)
print(res.json()["data"]["deleted"])
Response
{
"status": 200,
"data": { "deleted": true },
"error": false
}
Prompt
Copy this into your coding agent (Claude Code, Cursor, Codex…) to implement this endpoint.You are implementing a typed client for one Finesse Voice API endpoint: "Delete a voice".
Everything you need is in this prompt. Do not invent anything that is not specified here.
WHAT TO BUILD
- A function deleteVoice(id) (name it per the project's conventions) that deletes one voice from
the API key's workspace and returns true on success.
- This is destructive: take exactly one explicit id, no bulk or wildcard delete, and do not call
it from any automatic cleanup path unless asked.
- Detect the stack first: look for package.json, tsconfig.json, pyproject.toml,
requirements.txt, go.mod, Gemfile, composer.json and similar. Use the project's language, HTTP
client, module layout, error-handling conventions and test runner. If there is no project yet or
the stack is unclear, use TypeScript on Node 18+ with the built-in fetch and no new dependencies.
- If the project already has a Finesse API client module, add this to it (reuse its auth, base
URL, error type and retry helper) instead of creating a parallel one.
- Keep the base URL (https://fi.production.flamapis.com) in one constant or config value.
ENDPOINT
- Method: DELETE
- URL: https://fi.production.flamapis.com/flam-voice-svc/api/v1/public/voices/{id}
- No request body.
PARAMETERS
- id (path, string, required): the voice id, a 24-character hex string (for example
"665f1a2b3c4d5e6f7a8b9c0d"). Validate it locally against /^[0-9a-f]{24}$/i and URL-encode it.
- The voice must belong to the key's workspace, otherwise 404.
AUTHENTICATION
- Send the header X-API-Key: <workspace API key> on every request. Keys start with "flv_".
- Read the key from the environment variable FLAM_API_KEY (or the project's existing secrets or
config mechanism). Fail fast with a clear error if it is missing, before making any request.
- Never hard-code, log or commit the key, and never ship it in browser/client-side code: call this
from server-side code only. The key can synthesize with every voice in its workspace.
- A key is bound to one workspace. Referencing a voice or job from another workspace returns 404.
RESPONSE ENVELOPE
JSON responses use one envelope. On success "error" is false and the payload is in "data":
{
"status": 200,
"data": { "...": "endpoint payload" },
"error": false
}
On failure "error" is true, "data" is omitted and "message" carries the detail:
{
"status": 404,
"error": true,
"message": "Voice not found"
}
SUCCESS RESPONSE (200, application/json)
{
"status": 200,
"data": { "deleted": true },
"error": false
}
- data.deleted (boolean): true when the voice was deleted.
LIMITS
- Deleting a voice frees a slot against the plan's max_voices limit.
ERRORS
- 401: X-API-Key missing, malformed, invalid or revoked. Do not retry.
- 404: the voice does not exist in this workspace (it may already be deleted, or belong to another
workspace). Surface a distinct not-found error so callers can choose to treat it as "already
gone". Do not retry.
- 429: rate limited. Retry with backoff.
- 502: upstream temporarily unavailable. Retry with backoff.
- Surface failures as one typed error (for example FinesseApiError) carrying: HTTP status, message
(the envelope "message" or the flat "error" string), optional feature / unit / limit / used, a
retryable flag, and the raw body for debugging.
- Parse error bodies defensively: if a body is not valid JSON, keep the raw text in the error.
RETRIES
- Retry only 429 (rate limited), 502 (provider unavailable or warming up) and network errors or
timeouts, with exponential backoff plus jitter (for example about 1s, 2s, 4s; at most 3 retries),
then surface the error.
- Never retry 400, 401, 402, 403, 404 or 422: they fail the same way again.
(Delete is idempotent in effect: a retry after a success that was lost in transit returns 404,
which callers can treat as already deleted.)
ACCEPTANCE CRITERIA
- deleteVoice validates the id, sends DELETE to the exact URL with the X-API-Key header, and
returns data.deleted.
- 404 is a distinct not-found error. 401 is never retried. The key is never logged.
TEST PLAN
- Unit tests with mocked HTTP: 200 { deleted: true }; 404; 401; 429 then 200; invalid id
rejected without a network call.
- Smoke script that only deletes a voice it created itself: create a throwaway voice with
POST https://fi.production.flamapis.com/flam-voice-svc/api/v1/public/voices and JSON body { "name": "smoke-delete-<timestamp>" } (201, the new
voice is in data with its id), then deleteVoice(thatId) and print the result. Never delete an
id taken from the environment in the smoke test.
RULES
- Implement only what this spec describes. Do not invent parameters, fields, headers, endpoints or
error codes. If something is ambiguous, missing, or conflicts with the existing codebase, stop
and ask me before guessing.
- Match the project's existing style and conventions; do not refactor unrelated code.

