REST API
A human-friendly HTTP API for ONCE music distribution: upload assets, run AI detection, generate cover art, submit releases, and monitor delivery. The same capabilities, authentication, billing, and validation as the ONCE MCP server, exposed as conventional REST endpoints for developers who are not using an MCP client.
- Base URL:
https://once.app/v1 - Machine-readable spec:
GET /v1/openapi.json(OpenAPI 3.1) - API index:
GET /v1 - You do not need to know anything about MCP to use this API.
The MCP server (https://beta.once.app/api/mcp) remains fully supported,
this REST API is an additional surface over the same platform, not a
replacement. If you’re building an AI-agent integration, MCP gives you tool
discovery and native auth challenges; if you’re building a backend or app,
use this REST API.
Billing
Billing is identical to the MCP server: 1 credit per human song, 2 credits per AI-detected song. Submissions debit credits from the authenticated account. AI-detected songs bill at 2 credits automatically.
Quick start
BASE=https://once.app/v1
AUTH="Authorization: Bearer $ONCE_ACCESS_TOKEN"
# 0. Read the metadata rules (public; your inputs are validated against these)
curl $BASE/metadata-rules
# 1. Confirm who you are and your credit balance
curl -H "$AUTH" $BASE/me
curl -H "$AUTH" $BASE/me/credits
# 2. Upload cover art (small file, base64), or generate it, see /cover-art
curl -X POST $BASE/files -H "$AUTH" -H 'Content-Type: application/json' \
-d '{ "type": "coverArt", "file_name": "cover.jpg", "data_base64": "<base64>" }'See Authentication for how to obtain an access token, then Uploads, AI Detection, and Releases for the full workflow.
Endpoint index
Discovery & metadata
| Endpoint | Description |
|---|---|
GET /v1 | API index. |
GET /v1/openapi.json | OpenAPI 3.1 description of this API. |
GET /v1/metadata-rules | Metadata policy hitlist (markdown; Accept: application/json for a JSON wrapper). Public. |
GET /v1/release-schema | Authoritative required fields and an example payload. |
GET /v1/distribution-stores | Supported DSP/store IDs for release.distribution_store_ids, plus defaults and selection semantics. Public. |
GET /v1/pricing | Credit pricing: $1/credit, per-song cost (human vs AI), discounted bulk bundles, and auto-reload. Public. |
Profile & credits
| Endpoint | Description |
|---|---|
GET /v1/me | Profile of the authenticated user. |
GET /v1/me/credits?transactions=N | Credit balance, lifetime aggregates, and recent transactions. |
GET /v1/me/autoreload | Current auto-reload configuration. |
POST /v1/me/autoreload | Enable, disable, or reconfigure auto-reload (enabled, package_id/quantity, payment_method_id?, threshold_credits?). |
POST /v1/credits/checkout | Create a Stripe checkout session to buy credits (credits for a custom amount, or package_id for a discounted bundle; optional save_payment_method). |
Files & uploads
| Endpoint | Description |
|---|---|
POST /v1/files | Upload a small file as JSON base64. |
POST /v1/files/from-url | Import a file from a public URL. |
POST /v1/uploads | Create a chunked upload session for large local files. |
Audio intelligence
| Endpoint | Description |
|---|---|
POST /v1/audio/ai-detection | AI Song Detector result for an uploaded file. |
POST /v1/audio/acr-check | Registry-match (Pex Search / Identify Music) check. |
POST /v1/cover-art | Generate or iteratively edit AI album art. |
Drafts & releases
| Endpoint | Description |
|---|---|
POST /v1/drafts | Upsert a work-in-progress release snapshot. |
GET /v1/releases?limit=100 | Recent releases for the authenticated user. |
POST /v1/releases | Submit a release for distribution. Returns 201. |
GET /v1/releases/:id | Merged metadata for a release. |
GET /v1/releases/:id/status | Store delivery + aggregate status. |
GET /v1/releases/:id/job | Background processing job state and errors. |
Webhooks
Register endpoints to receive release.status_changed events instead of
polling. See Status for the payload shape, signature
verification, and delivery/retry behavior.
| Endpoint | Description |
|---|---|
GET /v1/webhooks | List registered webhook endpoints (signing secrets are never returned). |
POST /v1/webhooks | Register an https endpoint (url, optional description). Returns 201 with the signing secret exactly once. Up to 5 per account. |
PATCH /v1/webhooks/:id | Enable or disable an endpoint (active). Re-enabling resets the failure count. |
DELETE /v1/webhooks/:id | Delete an endpoint. |
Fraud API
| Endpoint | Description |
|---|---|
POST /v1/fraud/score | Risk score, severity, and signal flags for an email. Requires an API key (Personal Access Token) carrying the once:fraud scope; never returns IPs or other-account data. Free during a limited-time beta. |
Errors
Errors use a stable, machine-readable envelope:
{ "type": "validation_error", "code": "email_taken", "message": "..." }type is the error family, code is a machine-readable cause (e.g.
email_taken, invalid_credentials, pkce_required), and message is
human-readable.
| Family | HTTP | Notes |
|---|---|---|
invalid_request_error | 400 | Malformed request. |
authentication_error | 401 | Missing or invalid access token. |
permission_error | 403 | Not allowed for this account. |
not_found_error | 404 | No such resource. |
conflict_error | 409 | e.g. email_taken. |
validation_error | 422 | The platform rejected the content (metadata policy, weak password…). |
locked_error | 423 | account_locked. |
rate_limit_error | 429 | Honor the Retry-After header / retryAfterSeconds. |
oauth_error | 400/401 | Token endpoint errors (invalid_grant, …). |
upstream_error | 502 | The platform returned something unexpected; safe to retry with backoff. |
api_error | 500 | Unexpected gateway error. |
Provenance
Partners can tag requests with the X-Once-Provenance header (e.g. AIMD).
The tag is forwarded to the platform and recorded on releases for analytics.
See Authentication for partner onboarding.
Questions or partner access: tech@once.app.