Drop the Music Video Marketplace Workspace into your own product as an iframe, with your users already signed in. Your server signs a small JSON payload describing the logged-in user with your client_secret (HMAC-SHA256); we verify it, link or provision the matching MVM account, and boot the embed under your branding. No user-facing login step, no password sharing.
Building your own front end instead of embedding ours? See the Partner API docs.
client_secret.Sign server-side only. Your client_secret must never reach a browser.
| Credential | Description | Where it is used |
|---|---|---|
client_id | Your unique partner identifier. Not secret. | Embed URL path + request bodies |
client_secret | HMAC signing key. | Server-side signing only — never expose to browsers |
client_id: pk_partner_demo_0000000000000000 client_secret: sk_partner_demo_REPLACE_ME_0000000000000000 # example only
Credentials are issued during onboarding (invite only — there is no public signup). Ask us to rotate immediately if a secret leaks.
client_secret.const crypto = require('crypto');
const payloadString = JSON.stringify({
partner_external_user_id: user.id,
email: user.email,
display_name: user.name,
timestamp: new Date().toISOString(),
});
const signature = crypto
.createHmac('sha256', CLIENT_SECRET) // sk_partner_demo_REPLACE_ME_...
.update(payloadString)
.digest('hex');
const b64 = Buffer.from(payloadString).toString('base64');Byte-for-byte matters: sign the exact string you send. Re-serialising the JSON on the way out (different key order or spacing) invalidates the signature.
{
"partner_external_user_id": "your-user-123",
"email": "user@example.com",
"display_name": "Jane Doe",
"timestamp": "2026-03-23T12:00:00.000Z",
"logo_url": "https://cdn.yourbrand.example/logo.svg",
"accent_color": "#1D4ED8"
}| Field | Required | Description |
|---|---|---|
partner_external_user_id | Yes | Your platform's unique ID for the currently logged-in user. Must be unique per user. |
email | Recommended | The logged-in user's email — used to link existing MVM purchases and to auto-provision an MVM account. |
display_name | No | Display name shown in the embed. |
timestamp | Recommended | ISO 8601. Must be within 5 minutes of server time. Without it, payloads never expire (less secure). |
logo_url | No | Absolute https:// logo URL. Overrides the logo we have stored for you, for this session. |
accent_color | No | 6-digit hex colour (e.g. #1D4ED8). Overrides the stored accent, for this session. |
Never put your partner admin email or a hardcoded user ID in the payload — every user would then share a single MVM account, and see each other's purchases.
Math.abs(Date.now() - new Date(timestamp).getTime()) <= 5 * 60 * 1000
Older than 5 minutes returns 403 Payload expired. Generate a fresh payload + signature on every iframe load — do not cache or reuse signed payloads.
https://musicvideomarketplace.com/partner/embed/{CLIENT_ID}?payload={BASE64_PAYLOAD}&sig={HMAC_SIGNATURE}payload is the base64 of the signed JSON string, URL-encoded. sig is the lowercase hex HMAC of the raw JSON string.
https://musicvideomarketplace.com/partner/embed/pk_partner_demo_0000000000000000 ?payload=eyJwYXJ0bmVyX2V4dGVybmFsX3VzZXJfaWQiOiJ5b3VyLXVzZXItMTIzIn0%3D &sig=0000000000000000000000000000000000000000000000000000000000000000
Mint the URL in a server endpoint of your own (e.g. GET /api/mvm-embed-url) and set it as the iframe src at runtime.
<iframe
id="mvm-embed"
style="width:100%;height:800px;border:none;border-radius:12px;background:#111"
allow="autoplay; fullscreen; clipboard-write"
></iframe>
<script>
fetch('/api/mvm-embed-url') // your endpoint, your auth
.then((r) => r.json())
.then(({ embedUrl }) => {
document.getElementById('mvm-embed').src = embedUrl;
});
</script>logo_url / accent_color)Both branding fields are part of the signed payload, so they are covered by the same HMAC-SHA256 signature as the identity fields — they cannot be tampered with or injected by a browser without your client_secret. There is no separate signature for branding.
Resolution order, per session:
logo_url / accent_color, when present and valid.branding_config), set by your partner manager.Each field resolves independently: sending only accent_color keeps the stored logo. Invalid values (a non-http(s) URL, malformed hex) are ignored rather than rejected — the session still boots and falls back to the stored value, so a bad colour never locks your users out.
const payloadString = JSON.stringify({
partner_external_user_id: user.id,
email: user.email,
timestamp: new Date().toISOString(),
logo_url: "https://cdn.yourbrand.example/logo.svg",
accent_color: "#1D4ED8",
});
// sign payloadString exactly as above — no separate branding signatureThe verification response echoes what was used in branding_source, which is the quickest way to confirm your fields were accepted:
"branding_source": { "logo": "payload", "accent": "branding_config" }| Value | Meaning |
|---|---|
payload | Taken from your signed payload. |
branding_config | Your payload omitted it (or it was invalid) — stored config used. |
default | Neither available — no partner branding applied. |
The embed calls this for you. Use it directly only when you want to test a signature from your own backend.
POST https://awfrtgkoramnvpsvrjjv.supabase.co/functions/v1/partner-verify-session
Content-Type: application/json
{
"client_id": "pk_partner_demo_0000000000000000",
"payload": "{\"partner_external_user_id\":\"user-123\",\"email\":\"user@example.com\",\"display_name\":\"Jane Doe\",\"timestamp\":\"2026-03-25T12:00:00.000Z\"}",
"signature": "0000000000000000000000000000000000000000000000000000000000000000"
}payload here is the raw JSON string (the exact string you signed) — base64 is only used in the iframe URL parameter.
200 OK
{
"session_token": "00000000-0000-0000-0000-000000000000",
"partner_name": "Demo Partner",
"partner_type": "purchase",
"logo_url": "https://cdn.yourbrand.example/logo.svg",
"accent_color": "#1D4ED8",
"branding_source": { "logo": "payload", "accent": "branding_config" }
}Sessions last 24 hours from last activity. Subsequent calls pass session_token in the JSON body (not as a header).
| Status | Message | Fix |
|---|---|---|
401 | Invalid signature | Sign the raw JSON string, hex digest, correct client_secret. |
403 | Payload expired | Regenerate payload + signature per iframe load. |
403 | Unknown or disabled client_id | Check the ID in the URL path; contact us if disabled. |
400 | Missing partner_external_user_id | Always send a per-user ID. |
client_secret lives only in server-side config, never in client JS.timestamp included and freshly generated on every load.branding_source in the verification response.autoplay and fullscreen.