On this page
You need
- A succeeded job. See Get results.
Create a link
POST
/v1/jobs/{id}/shareA job has at most one live share. Creating one on a job that already has one returns the existing share unchanged unless you ask to rotate, so a client that cannot remember whether it shared a job never leaves a trail of links.
| Field | Type | Meaning |
|---|---|---|
| expires_at | datetime | Optional, absolute. Default and maximum: the job's retention deadline, 7 days after it finished. |
| include_filenames | bool | Off by default. On, the page prints the real stem names instead of Track 1. |
| rotate | bool | Mint a new token and kill the old one. |
| Field | Type | Meaning |
|---|---|---|
| token | string | The secret in the link. Only the owner ever sees it. |
| url | string | The absolute page URL to hand out. |
| expires_at | datetime | When the link dies. |
| revoked | bool | False on a live share. |
curl -X POST https://dueta.ai/v1/jobs/$JOB_ID/share \
-H "Authorization: Bearer $DUETA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"include_filenames": false}'
# -> 201 {"share_id": "...", "job_id": "...", "token": "N1x...",
# "url": "https://.../s/N1x...", "expires_at": "...", "revoked": false}Read as a visitor
GET
/v1/shares/{token}GET
/v1/shares/{token}/stems/{n}GET
/v1/shares/{token}/original/{n}No key, no cookie, no account. The view carries the audio and what made it, and nothing about the account: no ids, no cost, no error text. Tracks are addressed by position, never by name, and both audio routes honor Range so a player can seek.
{
"job_type": "separation",
"engine": "DUETA Duplex",
"created_at": "2026-08-28T04:11:52Z",
"duration_seconds": 182.4,
"sample_rate": 48000,
"stems": [
{ "stem_id": "1", "label": "Track 1", "si_sdr_db": 14.2, "audio_url": "/v1/shares/N1x.../stems/1" },
{ "stem_id": "2", "label": "Track 2", "si_sdr_db": 14.2, "audio_url": "/v1/shares/N1x.../stems/2" }
],
"originals": [
{ "stem_id": "1", "label": "Original", "si_sdr_db": null, "audio_url": "/v1/shares/N1x.../original/1" }
],
"expires_at": "2026-09-04T04:12:10Z",
"product": "DUETA",
"company": "MindLogic"
}# No key, no cookie, no account.
curl https://dueta.ai/v1/shares/$TOKEN
# One track; range requests work, so a player can seek.
curl -r 0-1023 https://dueta.ai/v1/shares/$TOKEN/stems/1 -o head.wav
# The original recording the job was made from (1-based).
curl https://dueta.ai/v1/shares/$TOKEN/original/1 -o original.wavRevoke
GET
/v1/jobs/{id}/shareDELETE
/v1/jobs/{id}/shareImmediate and total: the share is re-read on every request, so the next byte an already open page asks for is a 404. GET reads the current share, or 404 if the job is not shared.
curl -X DELETE https://dueta.ai/v1/jobs/$JOB_ID/share -H "Authorization: Bearer $DUETA_API_KEY"
# -> 204. From now on GET /v1/shares/$TOKEN is 404, mid-playback included.Cases
- 409
- The job has not succeeded. A link that starts empty cannot be told from a broken one, so only a result can be shared.
- 422
- expires_at is in the past or beyond the retention deadline.
- 404 public
- Unknown, revoked, and expired tokens are one 404 with one sentence. The public route never says which.
- Rate limit
- Public reads are limited per IP: 60 a minute on the view, 240 on audio. Creating shares is 30 a minute per account.
- Filenames
- With include_filenames the uploaded filenames become public. Default off.