# MDG Developer API v1: complete agent integration guide

Build a server-side integration against MDG's implemented OpenAPI contract at `/openapi.json` or `/openapi.yaml`. Never assume an undocumented endpoint exists. The developer portal is served at `/` and `/developers` on the backend; the public docs domain requires MDG DNS/hosting activation.

## 1. Provision access

- An MDG root administrator uses `/admin/developer-partners` in the existing admin application on the intended deployment.
- Choose an existing active label account and its exact tenant, or a direct artist account in `MDG_DIRECT`. Create a pending partner with the minimum required scopes, request/upload limits and approved receiver hostnames, then approve it.
- Issue a named, expiring sandbox key. Deliver it through the existing secure channel. Do not place it in source, URLs, client bundles, prompts, logs or screenshots.
- Obtain the actual sandbox base URL from MDG. It includes `/api/v1`. Set `MDG_BASE_URL` and `MDG_API_KEY` in your server's secret configuration. Sandbox and production require separate approvals, hosts and credentials.
- Request `identity:read`, `artists:read`, `artists:write` if creating/mapping profiles, `releases:read`, `releases:write`, `releases:submit`, `uploads:write`, `catalog:read`, and webhook scopes only if using those features.
- Existing subscription, distribution agreement, account and tenant restrictions apply. Complete those through MDG's existing account/rights workflows. Partner approval does not activate distribution or confer rights.

## 2. Implement the HTTP boundary

Send `Authorization: Bearer <credential>`. Use HTTPS and JSON, except upload chunks. Attach a durable unique `Idempotency-Key` (16–128 allowed characters) to each documented mutation. Save its association with the exact operation, object and payload **before** sending the first attempt. Keep it unchanged for identical retries, even across key rotation or process restarts. Never log authorization, Upload-Token, signing secrets, request bodies or clearance links.

Start with `GET /identity`; verify partner ID, tenant, environment and granted scopes. Fetch `GET /reference` for current language, genre and DSP identifiers and media policies. Handle safe error `{code,message,requestId,details?}` responses. Keep request IDs for support. Respect 429 and Retry-After; apply bounded jittered retry delays.

For `operation_in_progress`, wait and inspect the resource. For `outcome_unknown`, stop automatic writes, query the release/catalog/external mapping and contact MDG. A new idempotency key is not a safe workaround. Do not delete MDG's operation records. Business-rule errors require corrected data and a new logical operation/key.

## 3. Create or map the artist

Call `GET /artists` (cursor pagination) and match only authoritative accessible IDs. For your existing artist, call `PUT /artists/{id}/mapping` with your stable `externalId`.

For a new artist, call `POST /artists` with `name`, `legalName`, `externalId`, and the artist's actual `email` for label invitations. Direct accounts use the existing artist-profile service and its limits. Label accounts receive `onboardingRequired: true`: MDG sends its existing roster invitation. The artist must personally accept that invitation and any required consent; the API never returns its bearer link. Poll `GET /artists?externalId=...` until the accepted profile is returned. Stop while onboarding is pending. Do not generate artist accounts, accept invitations or transfer ownership on their behalf.

Use `PATCH /artists/{id}` only for documented profile fields. DSP link changes retain existing MDG mapping verification.

## 4. Build the draft

Call `POST /releases` with stable `externalId`, `title`, `artistId`, `releaseType` (`single`, `ep`, `album`) and known metadata. Fill release date, languageCode, active primary/secondary genre IDs, selected distributionPlatforms, rights metadata and productionType. Use actual ISRC/UPC values where owned/assigned; the existing service may generate an ISRC when appropriate. Never fabricate catalog identifiers.

Save the returned `release._id`. Append tracks with `POST /releases/{id}/tracks`; save the returned `trackId` values. Provide titles/numbers, languages/genres, producer, composer, contributors, AI declaration where applicable, featured credits and complete split collaborators. Contributions use `{name,role}`. Featured artists require actual legal identities and clearance emails. Splits use names, emails, roles, positive percentageShare values totalling 100%; external collaborators require validated ROIDs. Existing acceptance requirements remain in force.

Change draft metadata with `PATCH /releases/{id}` and `PATCH /releases/{id}/tracks/{trackId}`. Server-controlled ownership, state, approvals, clearances and media URLs are not accepted. Serialize your writes per release; do not edit the same record concurrently in your integration and the MDG dashboard.

## 5. Upload and attach media

For each complete artwork/audio file:

1. Compute its exact size and SHA-256 on the server. Read current constraints from `/reference`.
2. `POST /uploads` with releaseId, kind (`artwork` or `audio`), filename, contentType, size, sha256; audio also requires an existing trackId.
3. Save the returned session ID and short-lived Upload-Token securely. Sessions last one hour. Use returned chunkSize/partCount; do not guess them.
4. For each zero-based part, `PUT /uploads/{id}/parts/{part}` as multipart field `file`, with both Authorization and Upload-Token. Chunks must have the exact expected length. Identical part retries are safe; different bytes for the same index conflict.
5. Query `GET /uploads/{id}` with Upload-Token to resume. Do not send parts already listed with the expected hash.
6. `POST /uploads/{id}/complete` with `{}`, Authorization, Upload-Token and an idempotency key. Completion checks the full file, runs existing media checks and configured malware scanning, stores through B2 and attaches using the existing release update service.
7. Inspect scanStatus. `clean` means the configured scanner accepted the file; `not_configured` explicitly means no antivirus scan occurred. Required-scanner deployments fail closed when scanning is unavailable.

MDG never provides bucket authorization. Abandoned sessions expire; reserved bytes still count toward daily upload allowance. If completion has an uncertain storage outcome, contact MDG rather than repeating storage under a fresh key.

## 6. Validate and submit

Call `POST /releases/{id}/validate` with `{}`. It reuses existing deterministic metadata/QC rules and stored file evidence without invoking AI. Display findings by trackId, field, severity, message and recommendedFix. Resolve required fields, identifier conflicts, missing profile mappings, artwork/audio failures and rights warnings in your own UI using documented updates.

Call `POST /releases/{id}/submit` with `{}` and a new durable idempotency key. It calls the existing MDG submission service, including entitlements, distribution agreement, split integrity, FAC, producer clearance and QC enqueueing. It returns an ordinary MDG release with `reviewRequired: true`.

Read `GET /releases/{id}/fac`. Pending recipients sign through the existing MDG email and document routes. The partner API does not accept FAC, approve releases or distribute to DSPs. After required clearances, the release enters the existing pending-admin queue. Read `GET /releases/{id}` for metadata, status/history, edit permissions and safe QC findings. Corrections during review require MDG to explicitly enable editing. Do not interpret validation success or PENDING as approval.

## 7. Receive signed events

Have MDG approve your exact public HTTPS hostname. Configure `PUT /webhook` with `{url}`. Persist the returned signingSecret and keyId securely; repeated configuration rotates the secret. Set up verification before processing/replaying events.

Events: `release.status_changed`, `release.action_required`, `release.fac_changed`, `release.rejected`. Read exact request bytes before JSON parsing. Validate a numeric X-MDG-Timestamp within 300 seconds and compute HMAC-SHA256(signingSecret, timestamp + "." + rawBody). Constant-time compare its hex digest against X-MDG-Signature (`v1=<64 lowercase hex>`). Check X-MDG-Key-Id and that the body id equals X-MDG-Event-Id. Reject invalid signatures and stale timestamps.

Durably deduplicate by event id before applying side effects; acknowledge accepted events with 2xx promptly. Delivery is at least once and ordering is not guaranteed. Re-fetch current release state for sensitive decisions. Retry workers make up to 10 attempts with exponential backoff and jitter. Inspect `GET /webhook/deliveries`; request `POST /webhook/deliveries/{id}/replay` with `{}` and its own idempotency key. Replay keeps the event id but signs with a fresh timestamp/current secret. Never follow a receiver redirect.

## 8. Production readiness

Test wrong keys/environments, missing scopes, suspended partners, inaccessible object IDs, expired upload sessions, malformed media, duplicate parts, conflicting idempotency keys, uncertain timeouts, pending FAC, rejection/correction and duplicate/out-of-order webhook events. Confirm sandbox can never enter store-delivery/live/distributed states. No fake approval, clearance or delivery endpoints exist.

After MDG review of your sandbox integration, request production approval and a separate key. Keep keys server-side, monitor error/429 rates and webhook failures, and rotate credentials before expiry. Use `/api/v1`; tolerate additive fields/new status values. Breaking changes use another major path. Do not require upstream provider credentials.

## Examples

Download `/developers/examples/integration.mjs`, `/developers/examples/integration.py`, or `/developers/examples/curl.sh`. The full JavaScript/Python workflows read a real manifest and stable integration ID, resume using idempotency, upload actual files, validate and submit into MDG review. They require the existing account/artist agreements and consent to be complete. They do not create approvals or skip validation.
