{
  "openapi": "3.1.0",
  "jsonSchemaDialect": "https://spec.openapis.org/oas/3.1/dialect/base",
  "info": {
    "title": "Melodreams Developer API",
    "version": "1.0.0",
    "summary": "Read-only access to Melodreams profile data and your own analytics.",
    "description": "A small, read-only HTTP API for reading Melodreams profile data and your own analytics from your own server.\n\n## Read-only by design\n\nEvery operation is a `GET`. There is no endpoint that creates, updates or deletes anything, no webhooks, no bulk export and no enumeration. Editing stays in the Melodreams dashboard so that per-plan caps are enforced in exactly one place.\n\n## Authentication\n\nAll `/v1` operations except `GET /v1/scopes` require a bearer token of the form `mdr_live_<token_id>_<secret>`, where `token_id` is 22 base64url characters and `secret` is 43 base64url characters. There is no test or sandbox environment; every token is a `live` token.\n\nTreat the token as an **opaque string**. base64url includes `_` and `-`, so the id and the secret may themselves contain underscores; a client that splits the token on `_` will corrupt it. Pass it through unchanged.\n\nThe token must be sent in the `Authorization` header. Query-parameter authentication is **not** supported, because URLs leak into access logs, shell history, browser history and `Referer` headers.\n\nTokens are **server-side credentials**. A token shipped in front-end JavaScript, a mobile app or a browser extension is a leaked token. CORS on this API permits exactly one browser origin (the developer portal), so browser calls fail by design.\n\n## Plan requirement\n\nThe Developer API requires an active Melodreams subscription; there is no free tier. Plan status is resolved live on every request against the account that owns the token, not baked into the token, so a lapsed subscription stops API access even for a token minted while subscribed. A failed payment keeps working for a 7-day `past_due_grace` window.\n\n## Limits\n\nPer token: 120 requests per minute (burst) and 50,000 requests per calendar month, resetting at 00:00 UTC on the 1st. Both are keyed on the token id, not on the caller's IP address, and a successfully authenticated request meets no per-IP limit at all. Up to 5 active tokens per account.\n\nA separate limit of 20 requests per minute per source IP is consumed only by **failed** requests to `/v1/*` — a missing token, a malformed token, or a token that fails authentication — so that credential-guessing floods are cheap to absorb.\n\n`public:read` additionally caps each token at **500 distinct profiles per UTC day**. Re-reading a profile the token has already fetched that day does not count again and is not limited. Reads of the token owner's own data (`profile:read`, `analytics:read`) never count. Exceeding it returns `distinct_profile_cap`. Profile data is public one profile at a time, but bulk harvesting of the userbase is not a use case Melodreams supports; contact support if you have a legitimate high-volume need.\n\n## Errors\n\nEvery error uses the same envelope. The `error` field is a stable machine-readable code and is the contract; `message` is for humans and may be reworded at any time.",
    "termsOfService": "https://legal.melodreams.com/terms-of-service",
    "contact": {
      "name": "Melodreams Developer Portal",
      "url": "https://developer.melodreams.com/"
    }
  },
  "externalDocs": {
    "description": "Developer API documentation",
    "url": "https://developer.melodreams.com/docs"
  },
  "servers": [
    {
      "url": "https://api-dev1.melodreams.com",
      "description": "Production"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Service",
      "description": "Unauthenticated endpoints describing the service itself. These do not consume quota."
    },
    {
      "name": "Identity",
      "description": "Who a token belongs to and what it may do."
    },
    {
      "name": "Profiles",
      "description": "Public profiles and the token owner's own profile."
    },
    {
      "name": "Analytics",
      "description": "The token owner's view and click counters."
    }
  ],
  "paths": {
    "/health": {
      "get": {
        "tags": [
          "Service"
        ],
        "operationId": "getHealth",
        "summary": "Liveness check",
        "description": "Unauthenticated liveness check. Reveals readiness and nothing else, and consumes no quota.\n\nThis is the one endpoint whose body is **not** wrapped in the `{ ok, data }` envelope: it sits outside `/v1` because it is not part of the versioned contract. `GET /v1/health` is an alias for the same handler.",
        "security": [],
        "responses": {
          "200": {
            "description": "The service is up.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                },
                "example": {
                  "ok": true,
                  "service": "developer-api",
                  "version": "v1",
                  "cache": {
                    "entries": 412,
                    "max": 5000
                  },
                  "timestamp": "2026-07-22T10:31:04.118Z"
                }
              }
            }
          }
        }
      }
    },
    "/v1/scopes": {
      "get": {
        "tags": [
          "Service"
        ],
        "operationId": "listScopes",
        "summary": "Scope catalogue",
        "description": "The machine-readable scope catalogue. Public and unauthenticated because it is not sensitive, and useful for generating a permissions UI. Consumes no quota and is not subject to the per-IP limit.",
        "security": [],
        "responses": {
          "200": {
            "description": "The full scope catalogue.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "scopes"
                      ],
                      "properties": {
                        "scopes": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Scope"
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "data": {
                    "scopes": [
                      {
                        "scope": "public:read",
                        "description": "Read any public Melodreams profile.",
                        "requires_subscription": false
                      },
                      {
                        "scope": "profile:read",
                        "description": "Read the token owner's own profile, links and theme.",
                        "requires_subscription": false
                      },
                      {
                        "scope": "analytics:read",
                        "description": "Read the token owner's profile view and link click counters.",
                        "requires_subscription": true
                      }
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/me": {
      "get": {
        "tags": [
          "Identity"
        ],
        "operationId": "getMe",
        "summary": "Token identity",
        "description": "Who this token belongs to, what it can do, and what its limits are.\n\nRequires a valid token but **no scope at all**. This is the endpoint an integration should call at start-up to verify its credentials, and the first thing to try when something is not working.",
        "responses": {
          "200": {
            "description": "Token identity and limits.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/TokenIdentity"
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "data": {
                    "user_id": "8f2b1c44-7d6e-4a19-b3c0-5e91d2a7f004",
                    "username": "aurora",
                    "org_id": null,
                    "account_type": "user",
                    "tier": "full",
                    "subscribed": true,
                    "token": {
                      "id": "Zk9xQ2pM7vTb1sYwLd4NrA",
                      "environment": "live",
                      "scopes": [
                        "analytics:read",
                        "profile:read",
                        "public:read"
                      ]
                    },
                    "limits": {
                      "requests_per_minute": 120,
                      "requests_per_month": 50000
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PlanRequired"
          },
          "403": {
            "$ref": "#/components/responses/AccountBlocked"
          },
          "410": {
            "$ref": "#/components/responses/AccountDeleted"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamError"
          }
        }
      }
    },
    "/v1/profiles/{username}": {
      "get": {
        "tags": [
          "Profiles"
        ],
        "operationId": "getPublicProfile",
        "summary": "Get a public profile",
        "description": "Any public Melodreams profile, by handle.\n\nThe response is a stable projection: fields the API does not document are dropped rather than passed through, so a field you see here will still be here next month. It exposes nothing that `melo.bio/{username}` does not already serve to an anonymous browser.\n\nA handle that does not exist and a handle whose profile is not public both return `profile_not_found`. The two cases are deliberately indistinguishable so this endpoint cannot be used to enumerate private handles.\n\nThis is the only operation subject to the distinct-profile cap: a token may read 500 **different** usernames per UTC day, after which a new one returns `distinct_profile_cap`. Re-reading a username the token has already fetched that day does not count and is not limited, so an integration that polls a fixed set of profiles is unaffected. A username that does not exist still counts, because the set is updated before the profile is looked up.\n\nResponses are cacheable by shared caches for 60 seconds.",
        "security": [
          {
            "bearerAuth": [
              "public:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "username",
            "in": "path",
            "required": true,
            "description": "Melodreams handle. Case-insensitive; lowercased before lookup. Must match `^[a-z0-9_-]{3,30}$` once lowercased.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{3,30}$",
              "minLength": 3,
              "maxLength": 30
            },
            "example": "aurora"
          }
        ],
        "responses": {
          "200": {
            "description": "The public profile.",
            "headers": {
              "Cache-Control": {
                "description": "Public profile data is safe for a shared cache and is marked cacheable for 60 seconds.",
                "schema": {
                  "type": "string"
                },
                "example": "public, max-age=60, s-maxage=60, stale-while-revalidate=300"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/PublicProfile"
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "data": {
                    "username": "aurora",
                    "display_name": "Aurora",
                    "bio": "Producer. Night shift. Mixing in Berlin.",
                    "avatar_url": "https://img.melodreams.com/u/aurora/avatar.webp",
                    "banner_url": null,
                    "theme": "midnight",
                    "avatar": {
                      "shape": "circle",
                      "border": true,
                      "border_color": "#3b82f6",
                      "frame": "none",
                      "frame_color": null
                    },
                    "links": [
                      {
                        "label": "Latest release",
                        "url": "https://open.spotify.com/album/4kaurora",
                        "icon": "spotify",
                        "category": "music"
                      },
                      {
                        "label": "Tour dates",
                        "url": "https://aurora.example/tour"
                      }
                    ],
                    "socials": [
                      {
                        "platform": "instagram",
                        "value": "auroraplays"
                      },
                      {
                        "platform": "soundcloud",
                        "value": "aurora"
                      }
                    ],
                    "flags": {
                      "access_code_required": false,
                      "status_dot": true,
                      "discoverable": true,
                      "listable": true
                    },
                    "custom_domain": null,
                    "melo_bio_mode": "both",
                    "updated_at": "2026-07-19T21:04:33.512Z"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidUsername"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PlanRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/ProfileNotFound"
          },
          "410": {
            "$ref": "#/components/responses/AccountDeleted"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamError"
          }
        }
      }
    },
    "/v1/me/profile": {
      "get": {
        "tags": [
          "Profiles"
        ],
        "operationId": "getOwnProfile",
        "summary": "Get the token owner's own profile",
        "description": "The token owner's own profile. Identical in shape to the public projection, plus a `visibility` object describing settings that have no business being exposed about someone else's profile.\n\nWorks whether or not the profile is currently public. Never shared-cacheable: the response is specific to one token and is sent with `Cache-Control: no-store`.",
        "security": [
          {
            "bearerAuth": [
              "profile:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "The owner's profile.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/OwnProfile"
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "data": {
                    "username": "aurora",
                    "display_name": "Aurora",
                    "bio": "Producer. Night shift. Mixing in Berlin.",
                    "avatar_url": "https://img.melodreams.com/u/aurora/avatar.webp",
                    "banner_url": null,
                    "theme": "midnight",
                    "avatar": {
                      "shape": "circle",
                      "border": true,
                      "border_color": "#3b82f6",
                      "frame": "none",
                      "frame_color": null
                    },
                    "links": [
                      {
                        "label": "Latest release",
                        "url": "https://open.spotify.com/album/4kaurora"
                      }
                    ],
                    "socials": [
                      {
                        "platform": "instagram",
                        "value": "auroraplays"
                      }
                    ],
                    "flags": {
                      "access_code_required": false,
                      "status_dot": true,
                      "discoverable": true,
                      "listable": true
                    },
                    "custom_domain": null,
                    "melo_bio_mode": "both",
                    "updated_at": "2026-07-19T21:04:33.512Z",
                    "visibility": {
                      "is_public": true,
                      "custom_domain_redirect": false,
                      "reserved_style": "hidden"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PlanRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/ProfileNotFound"
          },
          "410": {
            "$ref": "#/components/responses/AccountDeleted"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamError"
          }
        }
      }
    },
    "/v1/me/analytics": {
      "get": {
        "tags": [
          "Analytics"
        ],
        "operationId": "getOwnAnalytics",
        "summary": "Get the token owner's analytics counters",
        "description": "The token owner's profile view count and link click counters.\n\nThere are no query parameters, no date ranges and no filters: this returns the current lifetime counters, the same data the dashboard shows. `clicks.by_link` is sorted by count descending and capped at the top 100 links so the response size is bounded. The dashboard's hourly breakdown is deliberately not exposed.\n\nAnalytics is a paid capability in the product, so this endpoint re-checks the live plan on every request in addition to the scope check. A brand-new profile with nothing recorded yet returns zeros, not a 404.",
        "security": [
          {
            "bearerAuth": [
              "analytics:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "The owner's counters.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Analytics"
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "data": {
                    "views": 18422,
                    "clicks": {
                      "total": 4310,
                      "by_link": [
                        {
                          "label": "Latest release",
                          "count": 2871
                        },
                        {
                          "label": "Tour dates",
                          "count": 1102
                        },
                        {
                          "label": "Merch",
                          "count": 337
                        }
                      ]
                    },
                    "updated_at": "2026-07-22T09:58:12.004Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PlanRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "410": {
            "$ref": "#/components/responses/AccountDeleted"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamError"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "mdr_live_<token_id>_<secret>",
        "description": "A Melodreams API token, minted in the developer portal at https://developer.melodreams.com/#tokens and shown exactly once at creation.\n\nFormat: `mdr_live_<token_id>_<secret>` — 75 characters total, where `token_id` is 22 base64url characters (the public half, stored in plaintext and safe to log) and `secret` is 43 base64url characters (never stored; only a peppered SHA-256 hash is kept). There is no test or sandbox environment; the environment segment is always `live`.\n\nThe token is **opaque**. base64url includes `_` and `-`, so the id and the secret may themselves contain underscores. Do not split the token on `_`, and do not trim, lowercase or re-encode it. For a log-safe label, take the first 31 characters (`mdr_live_<token_id>`).\n\nSend it as `Authorization: Bearer <token>`. Query-parameter authentication is not supported. Tokens are server-side credentials only.\n\nA token may be created with an expiry of 1–365 days (the portal offers 1, 7, 30, 90 and 365 days, defaulting to 30) or with no expiry at all. Short-lived tokens are recommended.\n\nThe `scopes` listed on each operation's security requirement are the scopes the token must carry; this is not an OAuth flow and scopes cannot be requested per call — they are fixed when the token is created."
      }
    },
    "headers": {
      "XRateLimitLimit": {
        "description": "The monthly request quota for this token. This is the monthly quota, not the per-minute burst limit.",
        "schema": {
          "type": "integer"
        },
        "example": 50000
      },
      "XRateLimitRemaining": {
        "description": "Requests remaining in the current calendar month, after counting this one. Omitted if the metering layer was briefly unavailable, in which case the request is allowed through rather than rejected.",
        "schema": {
          "type": "integer"
        },
        "example": 49713
      },
      "XRateLimitReset": {
        "description": "When the monthly counter resets: 00:00 UTC on the 1st of the next calendar month. An ISO 8601 timestamp, NOT a Unix epoch and NOT a seconds-remaining value.",
        "schema": {
          "type": "string",
          "format": "date-time"
        },
        "example": "2026-08-01T00:00:00.000Z"
      },
      "WWWAuthenticate": {
        "description": "RFC 6750 challenge telling the client how to authenticate.",
        "schema": {
          "type": "string"
        },
        "example": "Bearer realm=\"melodreams\", charset=\"UTF-8\""
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "title": "Error",
        "description": "The single error shape used by every failing request. `error` is the contract and is stable; `message` is for humans and may be reworded at any time.",
        "required": [
          "ok",
          "error",
          "message"
        ],
        "properties": {
          "ok": {
            "const": false
          },
          "error": {
            "$ref": "#/components/schemas/ErrorCode"
          },
          "message": {
            "type": "string",
            "description": "Human-readable explanation. Often more specific than the generic text for the code. Never parse it."
          },
          "docs": {
            "type": "string",
            "format": "uri",
            "description": "Deep link into the documentation, anchored on the error code.",
            "example": "https://developer.melodreams.com/docs#insufficient_scope"
          }
        }
      },
      "ErrorCode": {
        "type": "string",
        "title": "ErrorCode",
        "description": "The complete, fixed error vocabulary. These codes will not change once shipped.",
        "enum": [
          "bad_request",
          "invalid_username",
          "invalid_scope",
          "missing_token",
          "malformed_token",
          "invalid_token",
          "token_revoked",
          "token_expired",
          "session_required",
          "plan_required",
          "insufficient_scope",
          "account_blocked",
          "not_found",
          "profile_not_found",
          "account_deleted",
          "rate_limited",
          "quota_exceeded",
          "distinct_profile_cap",
          "internal_error",
          "api_unavailable",
          "scope_paused",
          "upstream_error"
        ]
      },
      "Health": {
        "type": "object",
        "title": "Health",
        "description": "Liveness payload. Not wrapped in the { ok, data } envelope.",
        "required": [
          "ok",
          "service",
          "version",
          "timestamp"
        ],
        "properties": {
          "ok": {
            "const": true
          },
          "service": {
            "type": "string",
            "example": "developer-api"
          },
          "version": {
            "type": "string",
            "example": "v1"
          },
          "cache": {
            "type": "object",
            "description": "Observability counters for the in-memory authentication cache.",
            "properties": {
              "entries": {
                "type": "integer"
              },
              "max": {
                "type": "integer"
              }
            }
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Scope": {
        "type": "object",
        "title": "Scope",
        "required": [
          "scope",
          "description",
          "requires_subscription"
        ],
        "properties": {
          "scope": {
            "type": "string",
            "enum": [
              "public:read",
              "profile:read",
              "analytics:read"
            ]
          },
          "description": {
            "type": "string"
          },
          "requires_subscription": {
            "type": "boolean",
            "description": "Whether this scope maps to a capability that is paid-only in the product itself. Separate from the plan requirement, which applies to the whole API."
          }
        }
      },
      "TokenIdentity": {
        "type": "object",
        "title": "TokenIdentity",
        "required": [
          "user_id",
          "username",
          "org_id",
          "account_type",
          "tier",
          "subscribed",
          "token",
          "limits"
        ],
        "properties": {
          "user_id": {
            "type": "string",
            "format": "uuid",
            "description": "The Melodreams account that owns the token."
          },
          "username": {
            "type": [
              "string",
              "null"
            ],
            "description": "The owner's handle."
          },
          "org_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "Set only for organisation-scoped tokens."
          },
          "account_type": {
            "type": "string",
            "enum": [
              "user",
              "org"
            ]
          },
          "tier": {
            "type": "string",
            "enum": [
              "full",
              "past_due_grace"
            ],
            "description": "The live access tier. Any other tier would have been rejected before this handler ran. `past_due_grace` means a payment failed and the integration has up to 7 days before it stops — worth alerting on."
          },
          "subscribed": {
            "type": "boolean",
            "description": "True while the plan requirement is satisfied, including during the grace window."
          },
          "token": {
            "type": "object",
            "required": [
              "id",
              "environment",
              "scopes"
            ],
            "properties": {
              "id": {
                "type": "string",
                "description": "The public token id — segment 3 of the token string. Safe to log.",
                "minLength": 22,
                "maxLength": 22,
                "example": "Zk9xQ2pM7vTb1sYwLd4NrA"
              },
              "environment": {
                "type": "string",
                "const": "live",
                "description": "Always `live`. There is no test or sandbox environment."
              },
              "scopes": {
                "type": "array",
                "description": "Sorted and de-duplicated.",
                "items": {
                  "type": "string",
                  "enum": [
                    "public:read",
                    "profile:read",
                    "analytics:read"
                  ]
                }
              }
            }
          },
          "limits": {
            "type": "object",
            "required": [
              "requests_per_minute",
              "requests_per_month"
            ],
            "properties": {
              "requests_per_minute": {
                "type": "integer",
                "example": 120
              },
              "requests_per_month": {
                "type": "integer",
                "example": 50000
              }
            }
          }
        }
      },
      "Link": {
        "type": "object",
        "title": "Link",
        "description": "One link on a profile. Editor internals — ordering keys, ids and scheduling windows — are never included. Links with no destination are omitted from the array entirely.",
        "required": [
          "label",
          "url"
        ],
        "properties": {
          "label": {
            "type": [
              "string",
              "null"
            ]
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "icon": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "thumbnail": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "Social": {
        "type": "object",
        "title": "Social",
        "required": [
          "platform",
          "value"
        ],
        "properties": {
          "platform": {
            "type": "string",
            "example": "instagram"
          },
          "value": {
            "type": "string",
            "example": "auroraplays"
          }
        }
      },
      "AvatarStyle": {
        "type": "object",
        "title": "AvatarStyle",
        "required": [
          "shape",
          "border",
          "border_color",
          "frame",
          "frame_color"
        ],
        "properties": {
          "shape": {
            "type": "string",
            "default": "circle"
          },
          "border": {
            "type": "boolean"
          },
          "border_color": {
            "type": [
              "string",
              "null"
            ]
          },
          "frame": {
            "type": "string",
            "default": "none"
          },
          "frame_color": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "ProfileFlags": {
        "type": "object",
        "title": "ProfileFlags",
        "required": [
          "access_code_required",
          "status_dot",
          "discoverable",
          "listable"
        ],
        "properties": {
          "access_code_required": {
            "type": "boolean",
            "description": "Whether the profile is gated behind an access code. Reported as a boolean only — the access-code hash and salt are never read from storage."
          },
          "status_dot": {
            "type": "boolean"
          },
          "discoverable": {
            "type": "boolean"
          },
          "listable": {
            "type": "boolean"
          }
        }
      },
      "PublicProfile": {
        "type": "object",
        "title": "PublicProfile",
        "description": "A stable projection of a public profile. Contains nothing that melo.bio does not already serve to an anonymous browser. Email addresses, billing identifiers and audience data are never included.",
        "required": [
          "username",
          "display_name",
          "bio",
          "avatar_url",
          "banner_url",
          "theme",
          "avatar",
          "links",
          "socials",
          "flags",
          "custom_domain",
          "melo_bio_mode",
          "updated_at"
        ],
        "properties": {
          "username": {
            "type": "string"
          },
          "display_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "bio": {
            "type": [
              "string",
              "null"
            ]
          },
          "avatar_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "banner_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "theme": {
            "type": [
              "string",
              "null"
            ]
          },
          "avatar": {
            "$ref": "#/components/schemas/AvatarStyle"
          },
          "links": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Link"
            }
          },
          "socials": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Social"
            }
          },
          "flags": {
            "$ref": "#/components/schemas/ProfileFlags"
          },
          "custom_domain": {
            "type": [
              "string",
              "null"
            ]
          },
          "melo_bio_mode": {
            "type": "string",
            "default": "both"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "OwnProfile": {
        "title": "OwnProfile",
        "description": "The public projection plus owner-only visibility settings.",
        "allOf": [
          {
            "$ref": "#/components/schemas/PublicProfile"
          },
          {
            "type": "object",
            "required": [
              "visibility"
            ],
            "properties": {
              "visibility": {
                "type": "object",
                "required": [
                  "is_public",
                  "custom_domain_redirect",
                  "reserved_style"
                ],
                "properties": {
                  "is_public": {
                    "type": "boolean",
                    "description": "Whether the profile is served publicly at all."
                  },
                  "custom_domain_redirect": {
                    "type": "boolean"
                  },
                  "reserved_style": {
                    "type": "string",
                    "default": "hidden"
                  }
                }
              }
            }
          }
        ]
      },
      "Analytics": {
        "type": "object",
        "title": "Analytics",
        "required": [
          "views",
          "clicks",
          "updated_at"
        ],
        "properties": {
          "views": {
            "type": "integer",
            "minimum": 0,
            "description": "Total profile views."
          },
          "clicks": {
            "type": "object",
            "required": [
              "total",
              "by_link"
            ],
            "properties": {
              "total": {
                "type": "integer",
                "minimum": 0
              },
              "by_link": {
                "type": "array",
                "description": "Sorted by count descending and capped at the top 100 links.",
                "maxItems": 100,
                "items": {
                  "type": "object",
                  "required": [
                    "label",
                    "count"
                  ],
                  "properties": {
                    "label": {
                      "type": "string"
                    },
                    "count": {
                      "type": "integer",
                      "minimum": 0
                    }
                  }
                }
              }
            }
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      }
    },
    "responses": {
      "InvalidUsername": {
        "description": "`invalid_username` — the handle in the path is not a valid Melodreams username.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "ok": false,
              "error": "invalid_username",
              "message": "That username is not a valid Melodreams handle.",
              "docs": "https://developer.melodreams.com/docs#invalid_username"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "The credential is missing, malformed, unknown, revoked or expired. One of `missing_token`, `malformed_token`, `invalid_token`, `token_revoked`, `token_expired`.\n\nAn unknown token id, a wrong secret and a mismatched environment segment all return `invalid_token` so the response cannot be used to probe which token ids exist. None of these are retryable without a new credential.",
        "headers": {
          "WWW-Authenticate": {
            "$ref": "#/components/headers/WWWAuthenticate"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "missing_token": {
                "summary": "No Authorization header",
                "value": {
                  "ok": false,
                  "error": "missing_token",
                  "message": "No API token was supplied. Send it as: Authorization: Bearer mdr_live_…",
                  "docs": "https://developer.melodreams.com/docs#missing_token"
                }
              },
              "malformed_token": {
                "summary": "Not structurally a Melodreams token",
                "value": {
                  "ok": false,
                  "error": "malformed_token",
                  "message": "The API token is not in the expected format.",
                  "docs": "https://developer.melodreams.com/docs#malformed_token"
                }
              },
              "invalid_token": {
                "summary": "Unknown token id or wrong secret",
                "value": {
                  "ok": false,
                  "error": "invalid_token",
                  "message": "The API token is not valid.",
                  "docs": "https://developer.melodreams.com/docs#invalid_token"
                }
              },
              "token_revoked": {
                "summary": "Revoked in the portal",
                "value": {
                  "ok": false,
                  "error": "token_revoked",
                  "message": "This API token has been revoked.",
                  "docs": "https://developer.melodreams.com/docs#token_revoked"
                }
              },
              "token_expired": {
                "summary": "Past its expiry date",
                "value": {
                  "ok": false,
                  "error": "token_expired",
                  "message": "This API token has expired.",
                  "docs": "https://developer.melodreams.com/docs#token_expired"
                }
              }
            }
          }
        }
      },
      "PlanRequired": {
        "description": "`plan_required` — the token is valid but the owning account has no active Melodreams subscription. Checked live on every request against the current tier, not baked into the token. Not retryable; resubscribing takes effect within 30 seconds.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "ok": false,
              "error": "plan_required",
              "message": "The Melodreams Developer API requires an active subscription. This token's account is on the free tier.",
              "docs": "https://developer.melodreams.com/docs#plan_required"
            }
          }
        }
      },
      "Forbidden": {
        "description": "`insufficient_scope` — the token does not carry the required scope; or `account_blocked` — the account is not in good standing. Scopes are immutable, so `insufficient_scope` requires a new token rather than a retry.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "insufficient_scope": {
                "summary": "Token lacks the required scope",
                "value": {
                  "ok": false,
                  "error": "insufficient_scope",
                  "message": "This endpoint requires the \"analytics:read\" scope. This token has: public:read.",
                  "docs": "https://developer.melodreams.com/docs#insufficient_scope"
                }
              },
              "account_blocked": {
                "summary": "Account suspended, locked or under review",
                "value": {
                  "ok": false,
                  "error": "account_blocked",
                  "message": "The account associated with this token is not in good standing.",
                  "docs": "https://developer.melodreams.com/docs#account_blocked"
                }
              }
            }
          }
        }
      },
      "AccountBlocked": {
        "description": "`account_blocked` — the account behind the token is suspended, locked, under review, deactivated or restricted.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "ok": false,
              "error": "account_blocked",
              "message": "The account associated with this token is not in good standing.",
              "docs": "https://developer.melodreams.com/docs#account_blocked"
            }
          }
        }
      },
      "ProfileNotFound": {
        "description": "`profile_not_found` — no public profile exists for that username. A handle that does not exist and a handle that is not public are deliberately indistinguishable. From `/v1/me/profile` it means the account has no profile row yet.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "ok": false,
              "error": "profile_not_found",
              "message": "No public profile exists for that username.",
              "docs": "https://developer.melodreams.com/docs#profile_not_found"
            }
          }
        }
      },
      "AccountDeleted": {
        "description": "`account_deleted` — the account behind the token has been deleted. Terminal; stop retrying and remove the integration.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "ok": false,
              "error": "account_deleted",
              "message": "The account associated with this token has been deleted.",
              "docs": "https://developer.melodreams.com/docs#account_deleted"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Three distinct conditions share this status. Only the first is retryable, so branch on `error` before backing off.\n\n`rate_limited` — the per-token burst limit of 120/minute was hit. Back off and retry; it clears within a minute. Also returned when a source IP has exhausted the 20/minute budget for failed authentication and then sends a request with no token or an unparseable one, in which case the credential is the problem rather than the pace.\n\n`quota_exceeded` — the token's monthly quota of 50,000 requests is exhausted. **Retrying will not help**; it resets at 00:00 UTC on the 1st.\n\n`distinct_profile_cap` — the token has already read 500 distinct profiles today and asked for a new one. Re-reading a profile it has already fetched today is unaffected and unlimited. **Retrying will not help, and neither will a different username**; it resets at 00:00 UTC. The `message` carries the current count and the cap as context and must not be parsed.\n\nThe rate-limit headers are present on `quota_exceeded` and `distinct_profile_cap`, which are refused by the metering layer, but not on `rate_limited`, which is refused before it.",
        "headers": {
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/XRateLimitLimit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/XRateLimitRemaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/XRateLimitReset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "rate_limited": {
                "summary": "Burst limit — retryable",
                "value": {
                  "ok": false,
                  "error": "rate_limited",
                  "message": "Too many requests. Slow down.",
                  "docs": "https://developer.melodreams.com/docs#rate_limited"
                }
              },
              "quota_exceeded": {
                "summary": "Monthly quota — not retryable",
                "value": {
                  "ok": false,
                  "error": "quota_exceeded",
                  "message": "Monthly quota of 50000 requests exhausted. Resets 2026-08-01T00:00:00.000Z.",
                  "docs": "https://developer.melodreams.com/docs#quota_exceeded"
                }
              },
              "distinct_profile_cap": {
                "summary": "Daily distinct-profile cap — not retryable",
                "value": {
                  "ok": false,
                  "error": "distinct_profile_cap",
                  "message": "This token has read 500 distinct profiles today, which is the daily limit of 500. Re-reading profiles you have already fetched today still works. This limit exists to prevent bulk harvesting; contact support if you have a legitimate need for a higher one.",
                  "docs": "https://developer.melodreams.com/docs#distinct_profile_cap"
                }
              }
            }
          }
        }
      },
      "InternalError": {
        "description": "`internal_error` — something went wrong on our side. Internal messages and stack traces are never included. Safe to retry once with backoff.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "ok": false,
              "error": "internal_error",
              "message": "Something went wrong on our end.",
              "docs": "https://developer.melodreams.com/docs#internal_error"
            }
          }
        }
      },
      "UpstreamError": {
        "description": "`upstream_error` — a dependency was unavailable or too slow. Transient; retry shortly with backoff and jitter.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "ok": false,
              "error": "upstream_error",
              "message": "A dependency was unavailable. Retry shortly.",
              "docs": "https://developer.melodreams.com/docs#upstream_error"
            }
          }
        }
      }
    }
  }
}
