Get an API key
Ask the Exynos installation owner for a dedicated key. Use one key per integration so it can be rotated independently.
Developer platform
Analyze tracks, create release-ready masters, and mix complete stem sessions with the same Exynos engines that power the website.
# Keep the key on your server
export EXYNOS_API_KEY="YOUR_API_KEY"
curl --fail-with-body \
-H "X-API-Key: $EXYNOS_API_KEY" \
-F "file=@track.wav" \
https://tamamologics.de/api/analyze
Quick start
Three steps are enough. Use the API from a trusted backend, CLI, worker, or desktop application.
Ask the Exynos installation owner for a dedicated key. Use one key per integration so it can be rotated independently.
Put the key in a server-side secret or an environment variable such as EXYNOS_API_KEY.
Add X-API-Key to every request. Never append a key to a URL or query string.
The API intentionally has no cross-origin browser access. A frontend would expose your long-lived key to every visitor. Call Exynos from your own backend and return only the result your app needs.
Authentication
Header keys are stateless and work across CLI tools, backend runtimes, queues, and native applications.
A mastering job belongs to the exact key that submitted it. Send that same key while polling, previewing, and downloading. A different or revoked key receives an intentional 404/401. Never share one production key between unrelated customers.
End-to-end example
Submit the audio once, poll a lightweight job endpoint, then download before the result expires.
BASE_URL="https://tamamologics.de"
API_KEY="$EXYNOS_API_KEY"
# 1. Submit the mastering job
curl --fail-with-body -H "X-API-Key: $API_KEY" \
-F "file=@track.wav" \
-F 'settings={"preset":"AI","target_lufs":-14,"ceiling":-1,"bitdepth":24}' \
"$BASE_URL/api/master"
# => {"success":true,"job_id":"JOB_ID"}
# 2. Poll approximately every two seconds
curl --fail-with-body -H "X-API-Key: $API_KEY" \
"$BASE_URL/api/job/JOB_ID"
# 3. Download immediately after completion
curl --fail-with-body -H "X-API-Key: $API_KEY" \
-OJ "$BASE_URL/api/download/JOB_ID"
import { readFile, writeFile } from "node:fs/promises";
const base = "https://tamamologics.de";
const headers = { "X-API-Key": process.env.EXYNOS_API_KEY };
const form = new FormData();
form.append(
"file",
new Blob([await readFile("track.wav")], { type: "audio/wav" }),
"track.wav"
);
form.append("settings", JSON.stringify({
preset: "AI", target_lufs: -14, ceiling: -1, bitdepth: 24
}));
let response = await fetch(`${base}/api/master`, {
method: "POST", headers, body: form
});
if (!response.ok) throw new Error(JSON.stringify(await response.json()));
const { job_id } = await response.json();
let job;
for (;;) {
response = await fetch(`${base}/api/job/${job_id}`, { headers });
if (!response.ok) throw new Error(JSON.stringify(await response.json()));
job = await response.json();
if (job.status === "completed" && job.result) break;
if (job.status === "error") throw new Error(job.error || "Mastering failed");
await new Promise(resolve => setTimeout(resolve, 2000));
}
response = await fetch(`${base}/api/download/${job_id}`, { headers });
if (!response.ok) throw new Error(JSON.stringify(await response.json()));
await writeFile(job.result.output_filename, Buffer.from(await response.arrayBuffer()));
import json, os, time, requests
from pathlib import Path
client = requests.Session()
client.headers["X-API-Key"] = os.environ["EXYNOS_API_KEY"]
base = "https://tamamologics.de"
with open("track.wav", "rb") as audio:
response = client.post(
f"{base}/api/master",
files=[("file", ("track.wav", audio, "audio/wav"))],
data={"settings": json.dumps({
"preset": "AI", "target_lufs": -14,
"ceiling": -1, "bitdepth": 24
})},
timeout=(15, 300),
)
response.raise_for_status()
job_id = response.json()["job_id"]
while True:
response = client.get(f"{base}/api/job/{job_id}", timeout=30)
response.raise_for_status()
job = response.json()
if job["status"] == "completed" and job.get("result"):
break
if job["status"] == "error":
raise RuntimeError(job.get("error", "Mastering failed"))
time.sleep(2)
name = Path(job["result"]["output_filename"]).name
with client.get(f"{base}/api/download/{job_id}", stream=True,
timeout=(15, 600)) as response:
response.raise_for_status()
with open(name, "wb") as output:
for chunk in response.iter_content(1024 * 1024):
if chunk:
output.write(chunk)
Core audio API
These are the stable, developer-facing processing operations. All multipart examples let your HTTP client generate the boundary automatically.
/api/analyzeRuns a synchronous technical analysis and adds recommended mastering targets. Use it to explain what Exynos hears before you submit a master.
| Field | Type | Required | Description |
|---|---|---|---|
file | Audio file | Yes | One file, maximum 250 MiB. Supported: .aac, .aif, .aiff, .caf, .flac, .m4a, .mp3, .ogg, .wav. |
/api/masterQueues an asynchronous mastering job. A successful submission returns HTTP 200 and a job_id; it does not contain the rendered audio yet.
| Field | Type | Required | Description |
|---|---|---|---|
file | Audio file, repeated | Yes | 1–24 tracks. Combined audio and reference maximum 250 MiB. |
settings | JSON string | No | Preset, loudness, ceiling, export depth, tone, and advanced modules. Maximum 65,536 characters. |
reference_file | Audio file | No | Optional tonal/loudness reference in a supported format. |
/api/job/<job_id> · /api/preview/<job_id> · /api/download/<job_id>Poll status every one or two seconds. When status becomes completed, preview inline or download the final attachment. Results expire 10 minutes after completion and live only in the current server process.
| Status | Meaning | Next action |
|---|---|---|
queued | Waiting for the engine. | Poll again. |
processing | Audio render is running. | Use progress for UI; poll again. |
completed | Result is ready. | Download immediately. |
error | The render failed. | Show the error and stop polling. |
/api/mixRenders a complete WAV synchronously. Give this request a long client/proxy timeout; repeated stems parts map to zero-based routing[].index.
| Field | Type | Required | Description |
|---|---|---|---|
stems | WAV, repeated | Yes | 1–96 files; total maximum 900 MiB; each up to 12 minutes. |
settings | JSON string | Yes | Style, per-stem routing, buses, reference matching, and render output. |
reference | WAV | No | Used when reference_match is true. |
curl --fail-with-body \
-H "X-API-Key: $EXYNOS_API_KEY" \
-F "stems=@vocal.wav" \
-F "stems=@beat.wav" \
-F 'settings={"style":{"name":"clean","headroom_db":-6,"sequence_ai_enabled":true,"sequence_strength":0.72,"use_true_peak_limiter":true},"routing":[{"index":0,"category":"vocals"},{"index":1,"category":"music"}],"render":{"output_sr":48000,"bitdepth":24}}' \
-o exynos_mix.wav \
"https://tamamologics.de/api/mix"Complete reference
Search by path, action, authentication type, or feature. Open any operation for its request, response, and common errors.
API-key access and the website's optional-advertising consent state.
/api/access/status
Check API access
Reports whether this installation has keys configured and whether the current request is authorized.
{"configured": true, "authorized": false}/api/access/verify
Create a browser key session
Validates an API key and stores a short-lived, signed browser grant. Intended for the first-party access screen, not server integrations.
{"ok": true, "next": "/mastering"}/api/privacy/consent
Read privacy choice
Returns the advertising-consent state for the current browser/session.
{"ok":true,"available":true,"version":"…","decided":true,"advertising":false,"decided_at":0,"receipt_id":"…"}/api/privacy/consent
Update privacy choice
Stores an explicit optional-advertising choice and returns the resulting consent record.
{"ok":true,"decided":true,"advertising":false,"receipt_id":"…"}Analyze, master, and mix audio with the Exynos processing engines.
/api/analyze
Analyze a track
Synchronously measures loudness, dynamics, spectrum, stereo image, and returns an AI mastering recommendation.
JSON analysis object including ai_recommendation./api/master
Submit mastering job
Queues one or more tracks for asynchronous mastering and returns a job identifier immediately.
{"success": true, "job_id": "b6f…"}/api/mix
Render a stem mix
Synchronously mixes up to 96 WAV stems with intelligent routing, buses, vocal anchoring, and sequence-aware automation.
Binary audio/wav plus X-Mix-*, X-Vocal-*, and X-Sequence-* diagnostic headers./api/premium/validate
Validate supporter access
Checks a legacy donator key or the live supporter rank of the signed-in account.
{"ok": true}Poll an asynchronous mastering job, preview it, and download the result.
/api/job/<job_id>
Read job status
Returns queued, processing, completed, or error state. Poll approximately every two seconds.
{"status":"completed","job_id":"…","progress":100,"result":{"output_filename":"…","processing_time":"12.4s","ai_summary":{}}}/api/preview/<job_id>
Stream a preview
Streams the first completed master as inline WAV audio for playback.
Binary audio/wav (inline)./api/download/<job_id>
Download a master
Downloads a WAV for a normal single-track master or a ZIP for batch/spatial exports.
Binary audio/wav or application/zip attachment.Website-account sessions used by community and publishing features.
/api/auth/me
Read current account
Returns the account attached to the current cookie session, including supporter status.
{"ok":true,"user":{"id":"…","username":"artist","email":"…","is_donator":true}}/api/auth/login
Sign in
Validates credentials and establishes a persistent signed account cookie.
{"ok":true,"user":{"id":"…","username":"artist","is_donator":false}}/api/auth/register
Create account
Creates a website account and signs it in.
{"ok":true,"user":{"id":"…","username":"artist"}}/api/auth/logout
Sign out
Revokes existing account sessions while keeping an independent browser API-key grant intact.
{"ok": true}/api/auth/forgot-password
Request password reset
Sends a one-hour reset link when the email exists. The response is deliberately identical for unknown emails.
{"ok":true,"message":"If the email is registered, we have sent a reset link."}/api/auth/reset-password
Reset password
Consumes a one-time password-reset token and revokes older account sessions.
{"ok": true}/api/auth/profile
Update profile
Updates or clears the email address of the signed-in account.
{"ok":true,"user":{"id":"…","username":"artist","email":"new@example.com","is_donator":false}}/api/donators
List supporters
Returns up to 500 usernames whose hub.db donator flag is enabled.
{"donators":["producer_one","producer_two"]}Discover, preview, upload, and download community sound packs.
/api/packs
Search packs
Returns up to 200 packs filtered by free-text query and style.
{"count":1,"items":[{"id":"…","title":"Drum Kit","style":"Drums","downloads":12}]}/api/packs
Upload a pack
Publishes one account-owned pack file, up to 1 GiB.
{"ok": true}/api/packs/<pack_id>/preview
Preview a pack
Streams the stored pack asset inline when a previewable file is available.
Binary file response./api/packs/<pack_id>/download
Download a pack
Downloads a pack attachment and increments its download count.
Binary attachment.Read community content and perform signed-in social actions.
/api/community/posts
List posts
Returns up to 200 community posts with optional search, category, and sorting.
{"items":[{"id":"…","title":"Mix feedback","category":"Feedback","upvotes":4}]}/api/community/posts
Create a post
Publishes a post as the signed-in account.
{"ok": true}/api/community/posts/<pid>
Read post and comments
Returns one post, its comments, vote totals, and user_voted state for the current account.
{"post":{"id":"…","user_voted":false},"comments":[]}/api/community/posts/<pid>/upvote
Toggle post vote
Adds or removes the current account's upvote.
{"voted":true,"upvotes":5}/api/community/posts/<pid>/comments
Add a comment
Adds a non-empty comment of up to 6,000 characters.
{"ok": true}/api/community/comments/<cid>/upvote
Toggle comment vote
Adds or removes the current account's comment upvote.
{"ok": true}Read and publish the signed-in account's public link-page configuration.
/api/linktree/config
Read artist-page config
Returns the account's saved configuration or an editable default.
{"ok":true,"alias":"artist","profile_name":"Artist","bio":"…","avatar_url":"","links":[],"theme":"dark"}/api/linktree/config
Publish artist-page config
Publishes an alias, profile, theme, and up to 12 validated HTTP(S) links.
{"ok": true}No endpoints match that filter. Try a shorter path or feature name.
Settings & models
Start with the minimal examples. Add advanced processing only when your product needs direct control.
A safe AI-first payload for streaming-focused material.
presetAI, DSP_MudCleaner, Glue, Punchy, Smooth, or EDM.target_lufsClamped from −18 to −8 LUFS.ceilingClamped from −3 to −0.1 dBTP.bitdepth16, 24, or 32; invalid values become 24.bass_adj / mid_adj / high_adjManual tone, each −12 to +12 dB.width / saturationWidth 0.5–1.5; saturation 0–6.Enable a packaged spatial export only when the client can consume ZIP results.
binaural_spatial_masterCreates a headphone-ready binaural master.adm_exportAdds ADM/BW64 assets and metadata where available.spatial_amount0–1 intensity.spatial_sample_rate48,000 or 96,000 Hz.Routing follows the order of repeated multipart stem files. Categories normalize to drums, bass, vocals, music, and fx.
styleclean, punchy, warm, or aggressive, plus headroom, vocal presence, sequence intelligence, reverb, delay, ducking, and limiter controls.routing[]index, category, gain trim (−18…18 dB), pan (−1…1), compression (0…1), width (0…2), filters, polarity, solo/mute, and sends.busesPer-category gain, glue, tone (neutral/bright/dark), width, reverb, and delay sends.render.output_srSource/null, 44.1, 48, 88.2, 96, 176.4, or 192 kHz.render.bitdepth16 or 24-bit WAV output.reference_matchSet true and include the reference multipart file.{
"preset": "AI",
"target_lufs": -14,
"ceiling": -1,
"bitdepth": 24
}Reliability
Check HTTP status and JSON error bodies before treating a response as audio. Back off when the server tells you to.
| Status | Code / condition | What to do |
|---|---|---|
400 | Invalid input | Fix field names, multipart parts, JSON settings, formats, or bounds. Do not retry unchanged. |
401 | API_KEY_REQUIRED / API_KEY_OR_LOGIN_REQUIRED | Send a configured key on every request. Never place it in the URL. |
403 | Invalid session origin | For website-cookie mutations, use the same origin. Header-key server calls are not cross-site browser calls. |
404 | Missing or non-owned job/resource | Confirm the ID and the submitting key. Completed job results may already have expired. |
413 | PAYLOAD_TOO_LARGE / file limit | Reduce upload size or split the workload within the documented endpoint limits. |
429 | RATE_LIMITED / CONCURRENCY_LIMIT | Honor Retry-After when present; otherwise wait for an active mastering job to finish. |
503 | QUEUE_FULL / MIX_BUSY | Retry with exponential backoff and jitter. Avoid synchronized retry storms. |
500 | Processing error | Log a request correlation on your side, retry once if safe, then contact support without sending API keys. |
Analyze/master audio: 250 MiB. Master: up to 24 tracks. Mix: 96 WAV stems / 900 MiB total. Mix stem duration: 12 minutes each.
Active mastering jobs time out after 20 minutes. Completed files expire after 10 minutes and are stored in memory, so a process restart removes them.
A global 429 response includes Retry-After in seconds. Apply exponential backoff plus a small random delay.
Use HTTPS in production, long upload/render timeouts, streaming downloads, and automatic multipart boundaries generated by your HTTP client.
Developer support
Bring your request shape, response status, and a redacted error to Discord. Never post your API key, reset token, or private audio URL.
A donation helps keep the audio engines online and funds the next release.