Agent note

Agent notes: custom catalogs

Gotcha notes for AI agents working with AudD custom catalogs — the access requirement, how a custom match looks different, and why uploads must not be blindly retried.

view .md auddcustom catalogagentupload

Terse gotchas for an agent building against AudD custom catalogs. A custom catalog is your account’s private fingerprint database — songs you upload that aren’t in the 160-million-track public DB. Once a track is in your catalog, ordinary recognition calls can match against it. Read these before you generate upload or matching code.

1. It needs special access — an agent can’t self-enable it

Custom-catalog upload goes to POST https://api.audd.io/upload/, but the endpoint requires special access on the account. You can’t turn it on from code or from the dashboard.

If the task needs a custom catalog, it needs a human to request access first. Access is granted by emailing [email protected]. Don’t generate code that assumes /upload/ will work on a fresh account — it won’t until access is enabled. Surface this as a prerequisite, not a runtime retry.

If you call /upload/ without access, treat the failure as a setup problem (escalate to the human), not something to loop on.

2. A custom match looks different — key off audio_id

When recognition matches a track from your custom catalog, the result is not shaped like a public-DB match:

  • audio_id — an integer, present and identifying your uploaded track. This is the field that says “this came from your catalog.”
  • artist / title — may be null, because the matched track is your private audio and AudD has no public metadata for it. Whatever you supplied at upload time (or nothing) is what you get.
result = audd.recognize(source)
if result is None:
    ...  # no match at all
elif result.audio_id is not None:
    ...  # CUSTOM-catalog match — your track; look it up by audio_id
else:
    ...  # public-DB match — artist/title are real

Don’t branch on artist/title to detect a custom match. They can be null on a custom match and populated on a public match — branch on audio_id being present. Map audio_id back to your own records to recover the real metadata for your private tracks.

3. Never blindly auto-retry an upload

/upload/ is not safe to retry naively. A retry after a timeout — when the first upload actually succeeded — can create a duplicate catalog entry, and now the same audio matches two audio_ids.

Make uploads idempotent on your side before you retry anything. Track which tracks you’ve uploaded (by your own stable key / hash), check that registry before re-uploading, and only retry when you can prove the prior attempt didn’t land. A generic “retry on network error” wrapper around /upload/ is a bug here.

This is the opposite of the recognition endpoints, where a retry on a transient failure is fine — recognition is read-only, upload mutates your catalog.

4. Recognition against the catalog is the same call

There is no separate “recognize against my catalog” endpoint. You make the same recognition call — POST https://api.audd.io/ (or enterprise for long files) with your account’s token. The only difference is what’s in your account’s fingerprint DB: with tracks uploaded, matches can come from your catalog (returning audio_id) as well as the public database.

So the integration is two phases:

  1. Once, at setup — upload your tracks to /upload/ (idempotently; see above), with access already granted.
  2. Per request — recognize normally; inspect audio_id to tell a custom match from a public one.

You don’t pass a “catalog” flag on the recognize call. If your tracks aren’t matching, the question is whether they’re in your catalog, not whether you set the right recognition parameter.

5. Store the metadata you’ll want back at upload time

Because a custom match can return null for artist / title, the audio_id is often the only useful thing on the result. Plan for that before you upload, not after.

Keep your own audio_id → metadata table. Whatever you need on a match — title, internal asset ID, rights owner, a URL — store it keyed by the audio_id the upload assigns, so a later match resolves to something meaningful. AudD won’t hold arbitrary metadata for you; the catalog is a fingerprint store, not a metadata store.

A match against your catalog then becomes a two-step lookup: AudD gives you the audio_id, your table turns it into the record you actually care about.

6. Don’t treat a custom miss as a public miss

When you’ve uploaded private tracks and a clip doesn’t match, the result is still a plain result == null — exactly the same no-match outcome as the public DB. There is no separate “not in your catalog” signal.

So if you expected one of your uploaded tracks to match and got null, debug the catalog state, not the call:

  • Did the upload actually succeed (vs. a silent failure you retried into a duplicate, or skipped)?
  • Is the clip long and clean enough to fingerprint? Custom tracks follow the same recognition constraints as public ones — a very short or very noisy clip may not match either database.

Don’t add recognition parameters trying to “force” a catalog hit; there’s nothing to force.

Quick checklist before you ship

  • Access granted on the account (human emailed [email protected]). ✗ → stop.
  • Uploads are idempotent — you can’t create duplicate audio_ids on retry.
  • Match handling branches on audio_id, not on artist/title.
  • You have an audio_id → metadata table for resolving custom matches.
  • No-match (result == null) is handled the same for custom and public.

Related

Reading this as an AI agent? The raw Markdown is at agents/custom-catalog.md, and the full index is /resources/llms.txt.