{
  "openapi": "3.1.0",
  "info": {
    "title": "Subliss API",
    "version": "1.0.0",
    "summary": "Read public subliminals and creator profiles on Subliss.",
    "description": "The Subliss API reads what anyone can already see on Discover and creator pages: public subliminals and public creator profiles. It only reads, and it never returns private subliminals, affirmations or account details. Every request needs a developer key, made under Account on subliss.app.",
    "termsOfService": "https://subliss.app/terms",
    "contact": { "name": "Subliss", "email": "hello@subliss.app", "url": "https://subliss.app/contact" }
  },
  "externalDocs": { "description": "Subliss API docs", "url": "https://subliss.app/developers/index.html" },
  "servers": [{ "url": "https://api.subliss.app/v1" }],
  "security": [{ "developerKey": [] }],
  "paths": {
    "/me": {
      "get": {
        "operationId": "getMe",
        "summary": "The account a key belongs to",
        "description": "Returns the handle and name of the account that made the key. Use it to check a key works.",
        "responses": {
          "200": { "description": "The key's owner.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Me" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/tracks": {
      "get": {
        "operationId": "listTracks",
        "summary": "List public subliminals",
        "description": "Public subliminals, newest first unless sort says otherwise. Filter by title, category or creator, and page with limit and offset.",
        "parameters": [
          { "name": "search", "in": "query", "description": "Words to find in the title. Up to 100 characters.", "schema": { "type": "string", "maxLength": 100 } },
          { "name": "category", "in": "query", "description": "A category key or label from /categories, such as healing or Self-worth.", "schema": { "type": "string" } },
          { "name": "creator", "in": "query", "description": "A creator's handle, with or without @.", "schema": { "type": "string" } },
          { "name": "sort", "in": "query", "description": "newest (by publish date) or popular (by plays).", "schema": { "type": "string", "enum": ["newest", "popular"], "default": "newest" } },
          { "name": "limit", "in": "query", "description": "How many to return, 1 to 100.", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 } },
          { "name": "offset", "in": "query", "description": "How many to skip, 0 to 10000. Use next_offset from the last page.", "schema": { "type": "integer", "minimum": 0, "maximum": 10000, "default": 0 } },
          { "name": "published_after", "in": "query", "description": "Only subliminals published at this date and time or later, such as 2026-11-01T09:00:00Z.", "schema": { "type": "string", "format": "date-time" } }
        ],
        "responses": {
          "200": { "description": "A page of subliminals.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TrackPage" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/tracks/{id}": {
      "get": {
        "operationId": "getTrack",
        "summary": "Get a public subliminal",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "description": "The subliminal's id.", "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": { "description": "The subliminal.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Track" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/creators/{handle}": {
      "get": {
        "operationId": "getCreator",
        "summary": "Get a creator's public profile",
        "parameters": [
          { "name": "handle", "in": "path", "required": true, "description": "The creator's handle, with or without @.", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "The creator.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Creator" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/categories": {
      "get": {
        "operationId": "listCategories",
        "summary": "List the categories",
        "responses": {
          "200": {
            "description": "Every category a subliminal can have.",
            "content": { "application/json": { "schema": {
              "type": "object",
              "required": ["categories"],
              "properties": { "categories": { "type": "array", "items": { "$ref": "#/components/schemas/Category" } } }
            } } }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "developerKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "A Subliss developer key: sbl_ followed by 64 characters. Make one under Account on subliss.app and send it as Authorization: Bearer sbl_… Never put it in an address."
      }
    },
    "schemas": {
      "Me": {
        "type": "object",
        "required": ["handle", "name", "url"],
        "properties": {
          "handle": { "type": ["string", "null"], "description": "The account's handle, if it has one." },
          "name": { "type": ["string", "null"] },
          "url": { "type": ["string", "null"], "format": "uri", "description": "The account's creator page." }
        }
      },
      "TrackCreator": {
        "type": "object",
        "required": ["handle", "name", "url"],
        "properties": {
          "handle": { "type": ["string", "null"] },
          "name": { "type": ["string", "null"] },
          "url": { "type": "string", "format": "uri" }
        }
      },
      "Track": {
        "type": "object",
        "required": ["id", "title", "url", "categories", "duration_seconds", "play_count", "like_count", "published_at", "creator"],
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "title": { "type": "string" },
          "url": { "type": "string", "format": "uri", "description": "The subliminal's public page on subliss.app." },
          "categories": { "type": "array", "items": { "type": "string" }, "description": "Category labels, such as Healing." },
          "duration_seconds": { "type": "integer" },
          "play_count": { "type": "integer" },
          "like_count": { "type": "integer" },
          "published_at": { "type": "string", "format": "date-time" },
          "creator": { "$ref": "#/components/schemas/TrackCreator" }
        }
      },
      "TrackPage": {
        "type": "object",
        "required": ["tracks", "has_more", "next_offset"],
        "properties": {
          "tracks": { "type": "array", "items": { "$ref": "#/components/schemas/Track" } },
          "has_more": { "type": "boolean" },
          "next_offset": { "type": ["integer", "null"], "description": "The offset for the next page, or null on the last page." }
        }
      },
      "Creator": {
        "type": "object",
        "required": ["handle", "name", "url", "avatar_url", "bio", "track_count", "total_play_count", "follower_count", "joined_at"],
        "properties": {
          "handle": { "type": ["string", "null"] },
          "name": { "type": ["string", "null"] },
          "url": { "type": "string", "format": "uri" },
          "avatar_url": { "type": ["string", "null"], "format": "uri" },
          "bio": { "type": ["string", "null"] },
          "track_count": { "type": "integer" },
          "total_play_count": { "type": "integer" },
          "follower_count": { "type": "integer" },
          "joined_at": { "type": ["string", "null"], "format": "date-time" }
        }
      },
      "Category": {
        "type": "object",
        "required": ["key", "label"],
        "properties": { "key": { "type": "string" }, "label": { "type": "string" } }
      },
      "Error": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "required": ["code", "message", "docs"],
            "properties": {
              "code": { "type": "string", "description": "A short code that stays the same, such as invalid_key." },
              "message": { "type": "string", "description": "What went wrong and what to do, in plain words." },
              "docs": { "type": "string", "format": "uri" }
            }
          }
        }
      }
    },
    "responses": {
      "BadRequest": { "description": "A parameter is out of range, or the key was sent in the address.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "Unauthorized": { "description": "No key, or a key that is not a Subliss key or has been revoked.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "NotFound": { "description": "No public subliminal or creator matches.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "RateLimited": {
        "description": "The key has made 60 requests this minute.",
        "headers": { "Retry-After": { "description": "Seconds until the next minute starts.", "schema": { "type": "integer" } } },
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "ServerError": { "description": "Something went wrong on our side.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
    }
  }
}
