Listening Copy

Developers

Watermark API

Watermark and trace audio from your own code. Two endpoints, one bearer key, one credit per call. Same engine as the app.

Documentation reviewed 26 July 2026 by Berg Capital ehf.

Overview

The API embeds an inaudible, recipient-unique signature into an audio file, and later identifies which signature a leaked file carries. Use it to sign promos before they go out, or to check a file that turned up somewhere it shouldn't.

  • Base URL: https://listeningcopy.com
  • All requests use HTTPS. Files are sent as multipart/form-data.
  • Watermarked output is always MP3 320. A signed file is a listening copy, not a master.
  • Files are processed in memory and not retained. Only the signature id and your label are stored, so trace can name a match.

Authentication

Create a key in the Developers console. Send it as a bearer token on every request. Keep it secret; it spends your credits.

Authorization: Bearer lc_live_xxxxxxxxxxxxxxxxxxxxxxxx

A missing or invalid key returns 401. Revoke a key any time in the console.

Credits & limits

Each watermark and each trace costs 1 credit. Your plan's monthly allowance is spent first, then purchased credits (which never expire). When you run out, calls return 402 and we email you a heads-up before that happens.

Check your balance any time with GET /v1/account. Keep uploads under 2 GB.

Watermark a file

POST /v1/watermark

Upload an audio file and a label identifying the recipient. Returns the signed MP3 and the signature id.

FieldTypeNotes
filefileRequired. WAV, FLAC, AIFF or MP3.
labeltextOptional. Who this copy is for, e.g. "Jane Doe, radio promo". Returned by trace.

The response body is the MP3. The signature id comes back in the X-Watermark-Id header, store it if you want to look it up later.

curl -X POST https://listeningcopy.com/v1/watermark \
  -H "Authorization: Bearer lc_live_..." \
  -F "file=@mix.wav" \
  -F "label=Jane Doe, radio promo" \
  -o watermarked.mp3 -D -

Trace a file

POST /v1/trace

Upload a suspect file. If it carries one of your signatures, you get back the id and the label it was signed with. Add ?deep=1 for a slower, more robust scan that recovers signatures from heavily degraded files.

curl -X POST https://listeningcopy.com/v1/trace \
  -H "Authorization: Bearer lc_live_..." \
  -F "file=@leaked.mp3"

Response:

{
  "matched": true,
  "results": [
    { "id": "a4f5ecf5a5918a644435c6b0f89c0f5a",
      "label": "Jane Doe, radio promo",
      "watermarkedAt": 1784923715799 }
  ]
}

No match returns { "matched": false, "results": [] }. A trace still costs 1 credit whether or not it matches.

Account

GET /v1/account

Your current credit balance and total watermarks.

curl https://listeningcopy.com/v1/account -H "Authorization: Bearer lc_live_..."
# { "credits": 380, "watermarked": 214 }

Errors

CodeMeaning
400No file attached, or an unknown request.
401Missing or invalid API key.
402Out of credits. Top up in the console.
413File too large (over 2 GB).

Examples

Node

import { readFileSync } from "node:fs";

const form = new FormData();
form.set("file", new Blob([readFileSync("mix.wav")]), "mix.wav");
form.set("label", "Jane Doe, radio promo");

const res = await fetch("https://listeningcopy.com/v1/watermark", {
  method: "POST",
  headers: { Authorization: "Bearer lc_live_..." },
  body: form,
});
const id = res.headers.get("X-Watermark-Id");
const mp3 = Buffer.from(await res.arrayBuffer());

Python

import requests

with open("mix.wav", "rb") as f:
    r = requests.post(
        "https://listeningcopy.com/v1/watermark",
        headers={"Authorization": "Bearer lc_live_..."},
        files={"file": f},
        data={"label": "Jane Doe, radio promo"},
    )
open("watermarked.mp3", "wb").write(r.content)
print(r.headers["X-Watermark-Id"])

Questions? hello@listeningcopy.com · Manage keys in the console.