{
  "openapi": "3.0.3",
  "info": {
    "title": "s.id Developer API",
    "version": "2.1.0",
    "description": "Public REST API for the s.id developer platform.\n\n## Authentication\n\nAuthenticate every request with an API key created in **Dashboard → Developer → API Keys**.\nPass it as a Bearer token:\n\n```\nAuthorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n```\n\nKeys are scoped — a request to an endpoint whose required scope your key does not\nhave returns `403 insufficient_scope`.\n\n## Rate limits\n\n38 requests per minute per API key. Exceeding the limit returns `429`.\n\n## Webhooks\n\nRegister webhook endpoints in the dashboard to receive real-time events\n(`link.created`, `link.updated`, `link.archived`, `link.clicked`,\n`microsite.published`, `qr.scanned`). Each delivery is a `POST` signed with\nHMAC-SHA256 in the `X-SID-Signature: sha256=<hex>` header. See the `WebhookEvent`\nschema for the payload shape.\n\n## OAuth 2.0\n\nApps that act on behalf of other s.id users use the authorization-code flow\n(`/oauth/authorize` → `/oauth/token` → `/oauth/userinfo`)."
  },
  "x-sid-scopes": [
    {
      "name": "links:read",
      "description": "List and read links",
      "status": "available"
    },
    {
      "name": "links:write",
      "description": "Create and update links (create, edit, restore)",
      "status": "available"
    },
    {
      "name": "links:archive",
      "description": "Archive links",
      "status": "available"
    },
    {
      "name": "links:analytics",
      "description": "Read per-link click statistics and lifetime counts",
      "status": "available"
    },
    {
      "name": "qr:read",
      "description": "Read QR code settings (global and per-link)",
      "status": "available"
    },
    {
      "name": "qr:write",
      "description": "Customize QR code settings (global and per-link)",
      "status": "available"
    },
    {
      "name": "user:read",
      "description": "Read the authenticated user profile and account quota",
      "status": "available"
    },
    {
      "name": "microsites:read",
      "description": "Read microsites",
      "status": "available"
    },
    {
      "name": "microsites:write",
      "description": "Create, update and manage components of microsites",
      "status": "available"
    },
    {
      "name": "microsites:delete",
      "description": "Delete microsites and their components",
      "status": "available"
    }
  ],
  "x-sid-webhook-events": [
    {
      "name": "link.created",
      "description": "Fired when a new link is created",
      "status": "available"
    },
    {
      "name": "link.updated",
      "description": "Fired when a link's URL or title is changed",
      "status": "available"
    },
    {
      "name": "link.archived",
      "description": "Fired when a link is archived",
      "status": "available"
    },
    {
      "name": "link.clicked",
      "description": "Fired on each redirect (per-click event)",
      "status": "available"
    },
    {
      "name": "microsite.published",
      "description": "Fired when a microsite is published",
      "status": "available"
    },
    {
      "name": "qr.scanned",
      "description": "Fired when a QR code is scanned",
      "status": "available"
    }
  ],
  "servers": [
    {
      "url": "https://api.s.id/v2",
      "description": "Public API (API-key auth)"
    },
    {
      "url": "https://dash.s.id",
      "description": "OAuth 2.0 consent screen (browser redirect only)"
    },
    {
      "url": "https://api.s.id",
      "description": "OAuth 2.0 authorization server (authorize, token, revoke, userinfo)"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "tags": [
    {
      "name": "Links",
      "description": "Create and manage short links"
    },
    {
      "name": "User",
      "description": "Authenticated user profile and quota"
    },
    {
      "name": "QR",
      "description": "Customize global and per-link QR codes"
    },
    {
      "name": "Microsites",
      "description": "Manage link-in-bio microsites and their components"
    },
    {
      "name": "OAuth 2.0",
      "description": "Authorization-code flow for third-party apps acting on behalf of s.id users"
    },
    {
      "name": "Integrations",
      "description": "No-code automation platform integrations (Make.com)"
    },
    {
      "name": "MCP",
      "description": "Model Context Protocol server for AI agent access to the s.id platform"
    }
  ],
  "x-sid-mcp": {
    "host": "mcp.s.id",
    "endpoint": "/mcp",
    "url": "https://mcp.s.id/mcp",
    "protocol": "JSON-RPC 2.0",
    "methods": ["initialize", "ping", "tools/list", "tools/call"],
    "auth_methods": ["ApiKeyAuth", "OAuth2"],
    "authorization_server": "https://api.s.id",
    "discovery_urls": [
      "https://mcp.s.id/.well-known/oauth-protected-resource",
      "https://mcp.s.id/.well-known/oauth-protected-resource/mcp"
    ],
    "quota_pool": "separate from REST /v2 — only tools/call consumes quota",
    "tier_gate": "hosted_mcp_enabled",
    "tool_count": 28
  },
  "x-sid-mcp-tools": [
    {
      "name": "create_link",
      "summary": "Create a short link",
      "scope": "links:write",
      "group": "Links"
    },
    {
      "name": "bulk_create_links",
      "summary": "Create multiple short links in one call",
      "scope": "links:write",
      "group": "Links"
    },
    {
      "name": "get_link",
      "summary": "Get a link by ID",
      "scope": "links:read",
      "group": "Links"
    },
    {
      "name": "list_links",
      "summary": "List links",
      "scope": "links:read",
      "group": "Links"
    },
    {
      "name": "update_link",
      "summary": "Update a link",
      "scope": "links:write",
      "group": "Links"
    },
    {
      "name": "delete_link",
      "summary": "Archive a link",
      "scope": "links:archive",
      "group": "Links"
    },
    {
      "name": "unarchive_link",
      "summary": "Restore an archived link",
      "scope": "links:write",
      "group": "Links"
    },
    {
      "name": "check_short_availability",
      "summary": "Check if a custom slug is available",
      "scope": "links:read",
      "group": "Links"
    },
    {
      "name": "get_link_stats",
      "summary": "Get a link's click timeline",
      "scope": "links:analytics",
      "group": "Links"
    },
    {
      "name": "get_link_lifetime_stats",
      "summary": "Get a link's lifetime click count",
      "scope": "links:analytics",
      "group": "Links"
    },
    {
      "name": "get_account_stats",
      "summary": "Get account-level click analytics",
      "scope": "links:analytics",
      "group": "Links"
    },
    {
      "name": "create_microsite",
      "summary": "Create a microsite",
      "scope": "microsites:write",
      "group": "Microsites"
    },
    {
      "name": "get_microsite",
      "summary": "Get a microsite by slug",
      "scope": "microsites:read",
      "group": "Microsites"
    },
    {
      "name": "list_microsites",
      "summary": "List microsites",
      "scope": "microsites:read",
      "group": "Microsites"
    },
    {
      "name": "update_microsite",
      "summary": "Update a microsite",
      "scope": "microsites:write",
      "group": "Microsites"
    },
    {
      "name": "delete_microsite",
      "summary": "Delete a microsite",
      "scope": "microsites:delete",
      "group": "Microsites"
    },
    {
      "name": "check_microsite_slug",
      "summary": "Check if a microsite slug is available",
      "scope": "microsites:read",
      "group": "Microsites"
    },
    {
      "name": "create_microsite_component",
      "summary": "Add a component to a microsite",
      "scope": "microsites:write",
      "group": "Microsites"
    },
    {
      "name": "list_microsite_components",
      "summary": "List a microsite's components",
      "scope": "microsites:read",
      "group": "Microsites"
    },
    {
      "name": "update_microsite_component",
      "summary": "Update a microsite component",
      "scope": "microsites:write",
      "group": "Microsites"
    },
    {
      "name": "delete_microsite_component",
      "summary": "Delete a microsite component",
      "scope": "microsites:delete",
      "group": "Microsites"
    },
    {
      "name": "order_microsite_components",
      "summary": "Reorder a microsite's components",
      "scope": "microsites:write",
      "group": "Microsites"
    },
    {
      "name": "get_link_qr",
      "summary": "Get a link's QR code settings",
      "scope": "qr:read",
      "group": "QR"
    },
    {
      "name": "set_link_qr",
      "summary": "Customize a link's QR code",
      "scope": "qr:write",
      "group": "QR"
    },
    {
      "name": "get_global_qr",
      "summary": "Get global QR code settings",
      "scope": "qr:read",
      "group": "QR"
    },
    {
      "name": "set_global_qr",
      "summary": "Customize global QR code settings",
      "scope": "qr:write",
      "group": "QR"
    },
    {
      "name": "get_user_info",
      "summary": "Get the authenticated user's profile",
      "scope": "user:read",
      "group": "Account"
    },
    {
      "name": "get_quota",
      "summary": "Get the authenticated user's account quota",
      "scope": "user:read",
      "group": "Account"
    }
  ],
  "paths": {
    "/links": {
      "get": {
        "tags": ["Links"],
        "summary": "List links",
        "description": "Returns a paginated list of the authenticated user's links.",
        "operationId": "listLinks",
        "security": [
          {
            "ApiKeyAuth": ["links:read"]
          },
          {
            "OAuth2": ["links:read"]
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10,
              "maximum": 100
            }
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by short code or URL"
          }
        ],
        "responses": {
          "200": {
            "description": "List of links",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Envelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Link"
                          }
                        },
                        "total": {
                          "type": "integer"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "tags": ["Links"],
        "summary": "Create a link",
        "operationId": "createLink",
        "security": [
          {
            "ApiKeyAuth": ["links:write"]
          },
          {
            "OAuth2": ["links:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateLinkBody"
              },
              "example": {
                "long_url": "https://example.com/a-very-long-url",
                "title": "My Link",
                "custom_slug": "mylink"
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/LinkResponse"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/links/available": {
      "post": {
        "tags": ["Links"],
        "summary": "Check slug availability",
        "description": "Checks whether a custom slug is available before creating a link.",
        "operationId": "checkSlug",
        "security": [
          {
            "ApiKeyAuth": ["links:read"]
          },
          {
            "OAuth2": ["links:read"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["short"],
                "properties": {
                  "short": {
                    "type": "string",
                    "example": "mylink"
                  },
                  "domain_alias": {
                    "type": "string",
                    "description": "Custom domain, if any"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Slug is available",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "description": "Slug is taken or invalid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          }
        }
      }
    },
    "/links/{short}": {
      "parameters": [
        {
          "name": "short",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "The short code of the link"
        }
      ],
      "get": {
        "tags": ["Links"],
        "summary": "Get a link",
        "operationId": "getLink",
        "security": [
          {
            "ApiKeyAuth": ["links:read"]
          },
          {
            "OAuth2": ["links:read"]
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/LinkResponse"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "tags": ["Links"],
        "summary": "Update a link",
        "description": "Updates a link. All fields are optional; omitted fields are left unchanged.\n\n- `password`: set a non-empty string to protect, empty string `\"\"` to remove protection.\n- `custom_slug`: rename the short code (subject to quota).\n- `archive_at`: schedule auto-archive on a date (`YYYY-MM-DD`).\n- `domain_alias`: change the custom domain (must be owned by the user).",
        "operationId": "updateLink",
        "security": [
          {
            "ApiKeyAuth": ["links:write"]
          },
          {
            "OAuth2": ["links:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateLinkBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/LinkResponse"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "tags": ["Links"],
        "summary": "Archive a link",
        "description": "Archives (soft-deletes) a link. The short code stops resolving. Use `POST /links/{short}/unarchive` to restore.",
        "operationId": "archiveLink",
        "security": [
          {
            "ApiKeyAuth": ["links:archive"]
          },
          {
            "OAuth2": ["links:archive"]
          }
        ],
        "responses": {
          "200": {
            "description": "Link archived",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/links/{short}/unarchive": {
      "post": {
        "tags": ["Links"],
        "summary": "Restore an archived link",
        "description": "Restores a previously archived link, making its short code resolve again.",
        "operationId": "unarchiveLink",
        "security": [
          {
            "ApiKeyAuth": ["links:write"]
          },
          {
            "OAuth2": ["links:write"]
          }
        ],
        "parameters": [
          {
            "name": "short",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The short code of the archived link"
          }
        ],
        "responses": {
          "200": {
            "description": "Link restored",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/links/{short}/stats": {
      "get": {
        "tags": ["Links"],
        "summary": "Link click timeline",
        "description": "Returns a date-bucketed click-count timeline for the link.",
        "operationId": "getLinkStats",
        "security": [
          {
            "ApiKeyAuth": ["links:analytics"]
          },
          {
            "OAuth2": ["links:analytics"]
          }
        ],
        "parameters": [
          {
            "name": "short",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "start",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "end",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Click timeline",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Envelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/StatPoint"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/links/{short}/stats/lifetime": {
      "get": {
        "tags": ["Links"],
        "summary": "Lifetime click count",
        "description": "Returns the all-time total click count for a single link.",
        "operationId": "getLinkLifetimeStats",
        "security": [
          {
            "ApiKeyAuth": ["links:analytics"]
          },
          {
            "OAuth2": ["links:analytics"]
          }
        ],
        "parameters": [
          {
            "name": "short",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lifetime click count",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Envelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/LifetimeCount"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/user": {
      "get": {
        "tags": ["User"],
        "summary": "Get authenticated user",
        "operationId": "getUser",
        "security": [
          {
            "ApiKeyAuth": ["user:read"]
          },
          {
            "OAuth2": ["user:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "User profile",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Envelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/User"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/quota": {
      "get": {
        "tags": ["User"],
        "summary": "Get account quota",
        "description": "Returns the authenticated user's current plan limits and usage counters.",
        "operationId": "getQuota",
        "security": [
          {
            "ApiKeyAuth": ["user:read"]
          },
          {
            "OAuth2": ["user:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "Account quota",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Envelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/Quota"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/microsites": {
      "get": {
        "summary": "List microsites",
        "description": "Returns a paginated list of microsites owned by the authenticated user.",
        "operationId": "listMicrosites",
        "tags": ["Microsites"],
        "security": [
          {
            "ApiKeyAuth": ["microsites:read"]
          },
          {
            "OAuth2": ["microsites:read"]
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20,
              "maximum": 100
            }
          },
          {
            "name": "after",
            "in": "query",
            "description": "Cursor for the next page (opaque string from previous response)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of microsites",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Envelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Microsite"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "post": {
        "summary": "Create a microsite",
        "operationId": "createMicrosite",
        "tags": ["Microsites"],
        "security": [
          {
            "ApiKeyAuth": ["microsites:write"]
          },
          {
            "OAuth2": ["microsites:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["slug", "title", "kind"],
                "properties": {
                  "slug": {
                    "type": "string",
                    "maxLength": 48,
                    "description": "URL-safe identifier (alphanumeric + hyphens/underscores)"
                  },
                  "title": {
                    "type": "string",
                    "maxLength": 48
                  },
                  "kind": {
                    "type": "string",
                    "description": "Microsite category (e.g. `personal_branding`, `brand`, `other`)"
                  },
                  "theme": {
                    "type": "string",
                    "description": "Theme slug (optional, defaults to the platform default)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Microsite created",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Envelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/Microsite"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Validation error (slug already taken, quota exceeded, etc.)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/microsites/{slug}": {
      "get": {
        "summary": "Get a microsite",
        "operationId": "getMicrosite",
        "tags": ["Microsites"],
        "security": [
          {
            "ApiKeyAuth": ["microsites:read"]
          },
          {
            "OAuth2": ["microsites:read"]
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Microsite detail",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Envelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/Microsite"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Microsite not found"
          }
        }
      },
      "put": {
        "summary": "Update a microsite",
        "description": "Patches title, description, and/or visibility. All fields are optional.",
        "operationId": "updateMicrosite",
        "tags": ["Microsites"],
        "security": [
          {
            "ApiKeyAuth": ["microsites:write"]
          },
          {
            "OAuth2": ["microsites:write"]
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "maxLength": 48
                  },
                  "description": {
                    "type": "string",
                    "maxLength": 160
                  },
                  "hide": {
                    "type": "boolean",
                    "description": "Set `true` to hide the microsite from public (requires plan that supports visibility toggle)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated microsite",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Envelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/Microsite"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Microsite not found"
          }
        }
      },
      "delete": {
        "summary": "Delete a microsite",
        "operationId": "deleteMicrosite",
        "tags": ["Microsites"],
        "security": [
          {
            "ApiKeyAuth": ["microsites:delete"]
          },
          {
            "OAuth2": ["microsites:delete"]
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Microsite deleted"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Microsite not found"
          }
        }
      }
    },
    "/links/bulk": {
      "post": {
        "summary": "Bulk create links",
        "description": "Create up to 100 short links in a single request. Requires a subscription plan with bulk shortening enabled. Each item reports individual success/failure — the overall request always returns 200 even if some items fail.",
        "operationId": "bulkCreateLinks",
        "tags": ["Links"],
        "security": [
          {
            "ApiKeyAuth": ["links:write"]
          },
          {
            "OAuth2": ["links:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["links"],
                "properties": {
                  "links": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 100,
                    "items": {
                      "type": "object",
                      "required": ["long_url"],
                      "properties": {
                        "long_url": {
                          "type": "string",
                          "format": "uri",
                          "description": "Destination URL"
                        },
                        "title": {
                          "type": "string",
                          "maxLength": 48
                        },
                        "short": {
                          "type": "string",
                          "maxLength": 48,
                          "description": "Desired short code (optional; auto-generated if omitted)"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Bulk result — individual items may have success=false",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Envelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "properties": {
                            "total": {
                              "type": "integer"
                            },
                            "success": {
                              "type": "integer"
                            },
                            "failed": {
                              "type": "integer"
                            },
                            "items": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "index": {
                                    "type": "integer"
                                  },
                                  "success": {
                                    "type": "boolean"
                                  },
                                  "error": {
                                    "type": "string"
                                  },
                                  "data": {
                                    "$ref": "#/components/schemas/Link"
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Plan upgrade required (bulk shortening not in plan)"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/stats": {
      "get": {
        "summary": "Account-level click analytics",
        "description": "Returns a timeline of clicks plus breakdowns by top links, referers, locations, devices, and browsers for the authenticated account. Date range is gated by subscription plan.",
        "operationId": "getStats",
        "tags": ["Analytics"],
        "security": [
          {
            "ApiKeyAuth": ["links:analytics"]
          },
          {
            "OAuth2": ["links:analytics"]
          }
        ],
        "parameters": [
          {
            "name": "start",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "2026-01-01"
            },
            "description": "Start date (YYYY-MM-DD). Defaults to 30 days ago."
          },
          {
            "name": "end",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "2026-01-31"
            },
            "description": "End date (YYYY-MM-DD). Defaults to today."
          },
          {
            "name": "additional",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Include referer, location, device, browser breakdowns"
          }
        ],
        "responses": {
          "200": {
            "description": "Account analytics",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Envelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/AccountStats"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/qr": {
      "get": {
        "summary": "Get global QR settings",
        "description": "Returns the account-level (global) QR code settings applied to QR codes by default.",
        "operationId": "getGlobalQr",
        "tags": ["QR"],
        "security": [
          {
            "ApiKeyAuth": ["qr:read"]
          },
          {
            "OAuth2": ["qr:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "Global QR settings",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Envelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/QrSettings"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "put": {
        "summary": "Customize global QR settings",
        "description": "Updates the account-level (global) QR code settings. All fields are optional; omitted fields are left unchanged.",
        "operationId": "updateGlobalQr",
        "tags": ["QR"],
        "security": [
          {
            "ApiKeyAuth": ["qr:write"]
          },
          {
            "OAuth2": ["qr:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QrSettingsBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated global QR settings",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Envelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/QrSettings"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/links/{short}/qr": {
      "parameters": [
        {
          "name": "short",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "The short code of the link"
        }
      ],
      "get": {
        "summary": "Get a link's QR settings",
        "description": "Returns the QR code settings for a single link.",
        "operationId": "getLinkQr",
        "tags": ["QR"],
        "security": [
          {
            "ApiKeyAuth": ["qr:read"]
          },
          {
            "OAuth2": ["qr:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "Link QR settings",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Envelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/QrSettings"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "put": {
        "summary": "Customize a link's QR settings",
        "description": "Updates the QR code settings for a single link. All fields are optional; omitted fields are left unchanged.",
        "operationId": "updateLinkQr",
        "tags": ["QR"],
        "security": [
          {
            "ApiKeyAuth": ["qr:write"]
          },
          {
            "OAuth2": ["qr:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QrSettingsBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated link QR settings",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Envelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/QrSettings"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/microsites/available": {
      "post": {
        "summary": "Check microsite slug availability",
        "description": "Checks whether a microsite slug is available before creating a microsite.",
        "operationId": "checkMicrositeSlug",
        "tags": ["Microsites"],
        "security": [
          {
            "ApiKeyAuth": ["microsites:read"]
          },
          {
            "OAuth2": ["microsites:read"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["slug"],
                "properties": {
                  "slug": {
                    "type": "string",
                    "maxLength": 48,
                    "example": "mysite"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Slug availability result",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Envelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "properties": {
                            "available": {
                              "type": "boolean"
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/microsites/{slug}/components": {
      "parameters": [
        {
          "name": "slug",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "The slug of the microsite"
        }
      ],
      "get": {
        "summary": "List microsite components",
        "description": "Returns the components belonging to a microsite, in display order.",
        "operationId": "listMicrositeComponents",
        "tags": ["Microsites"],
        "security": [
          {
            "ApiKeyAuth": ["microsites:read"]
          },
          {
            "OAuth2": ["microsites:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "List of microsite components",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Envelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/MicrositeComponent"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "summary": "Add a microsite component",
        "description": "Adds a new component to a microsite.\n\nThe body is `{ kind, data, tag? }`. The shape of the `data` object depends on `kind`. Unknown fields are ignored, validation is per-kind, and invalid input returns `422`. All color fields are hex strings (e.g. `#1a56db`).\n\n**Kinds:** `PROFILE`, `LINK`, `HORIZONTAL_LINK`, `TEXT`, `IMAGE`, `MEDIA`, `DIVIDER`, `COUNTDOWN`, `MAPS`, `IMAGE_SLIDE`, `CV`, `AUTOPLAY_MUSIC`, `CONTACT`, `CALENDAR`, `SHOP_LISTING`, `SHOP_ITEM`, `SHOP_LEADERBOARD`.\n\n**Rules:**\n- `PROFILE`, `CV` and `AUTOPLAY_MUSIC` are unique — at most one per microsite.\n- `IMAGE_SLIDE` requires a plan with the Image Slide feature.\n- On create the password is always stored empty — set or change it via update (`PUT`).\n- Image fields (`image`, `imageBackground`, slide `image`) must be a local asset path, not a remote URL — they must match `[/.a-zA-Z0-9_-]+.(jpg|jpeg|png|svg|webp|gif|bmp)`; any value containing a scheme (`https://`), `//`, or `..` is rejected.\n\n**Shared field groups** (a kind that lists a group accepts all of its fields inside `data`):\n- **Button styling** (`LINK`, `CONTACT`, `CALENDAR`): `icon` (string, max 255), `textFont` (string, max 100), `textPosition` (string, max 100), `buttonEffect` (string, max 100), `buttonColor` (hex, max 20), `buttonBorderColor` (hex, max 20), `buttonIconBackground` (hex, max 20), `buttonShadowColor` (hex, max 20).\n- **Spoiler reveal** (`TEXT`, `IMAGE`, `MEDIA`, `MAPS`, `IMAGE_SLIDE`, `SHOP_LEADERBOARD`): `isSpoiler` (bool), `spoilerButtonText` (string, max 140), `spoilerButtonTextPosition` (string, max 100), `spoilerButtonIcon` (string), `spoilerButtonColor` (hex, max 20), `spoilerButtonFont` (string, max 100), `spoilerBackground` (string, max 100), `spoilerBackgroundOpacity` (string, max 100), `spoilerButtonBorderColor` (hex, max 20), `spoilerButtonIconBackground` (hex, max 20), `spoilerButtonShadowColor` (hex, max 20).\n- **Password protection** (`LINK`, `TEXT`, `IMAGE`, `MEDIA`, `MAPS`, `IMAGE_SLIDE`, `CONTACT`, `CV`, `SHOP_LEADERBOARD`): `passwordActive` (bool), `password` (string, max 255 — set via update only), `passwordMessage` (string, max 255).",
        "operationId": "createMicrositeComponent",
        "tags": ["Microsites"],
        "security": [
          {
            "ApiKeyAuth": ["microsites:write"]
          },
          {
            "OAuth2": ["microsites:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["kind", "data"],
                "properties": {
                  "kind": {
                    "type": "string",
                    "description": "Component kind. The shape of `data` depends on this value.",
                    "enum": [
                      "PROFILE",
                      "LINK",
                      "HORIZONTAL_LINK",
                      "TEXT",
                      "IMAGE",
                      "MEDIA",
                      "DIVIDER",
                      "COUNTDOWN",
                      "MAPS",
                      "IMAGE_SLIDE",
                      "CV",
                      "AUTOPLAY_MUSIC",
                      "CONTACT",
                      "CALENDAR",
                      "SHOP_LISTING",
                      "SHOP_ITEM",
                      "SHOP_LEADERBOARD"
                    ],
                    "example": "LINK"
                  },
                  "data": {
                    "type": "object",
                    "description": "Kind-specific component data. Its shape depends on `kind`. See the operation description and examples below."
                  },
                  "tag": {
                    "type": "string",
                    "description": "Optional grouping tag"
                  }
                }
              },
              "examples": {
                "PROFILE": {
                  "summary": "PROFILE component",
                  "value": {
                    "kind": "PROFILE",
                    "data": {
                      "title": "Jane Doe",
                      "description": "Designer & maker.",
                      "image": "a1b2c3d4-e5f6-7890-abcd-ef0123456789_400x400.png",
                      "titleColor": "#1a56db"
                    }
                  }
                },
                "LINK": {
                  "summary": "LINK component",
                  "value": {
                    "kind": "LINK",
                    "data": {
                      "value": "Visit my site",
                      "href": "https://example.com",
                      "buttonColor": "#1a56db"
                    }
                  }
                },
                "HORIZONTAL_LINK": {
                  "summary": "HORIZONTAL_LINK component",
                  "value": {
                    "kind": "HORIZONTAL_LINK",
                    "data": {
                      "style": "rounded",
                      "links": [
                        {
                          "icon": "instagram",
                          "url": "https://instagram.com/jane"
                        },
                        {
                          "icon": "twitter",
                          "url": "https://twitter.com/jane"
                        }
                      ]
                    }
                  }
                },
                "TEXT": {
                  "summary": "TEXT component",
                  "value": {
                    "kind": "TEXT",
                    "data": {
                      "content": "Welcome to my page!",
                      "textColor": "#222222",
                      "textPosition": "center"
                    }
                  }
                },
                "IMAGE": {
                  "summary": "IMAGE component",
                  "value": {
                    "kind": "IMAGE",
                    "data": {
                      "image": "a1b2c3d4-e5f6-7890-abcd-ef0123456789_1200x630.jpeg",
                      "content": "My latest work",
                      "href": "https://example.com"
                    }
                  }
                },
                "MEDIA": {
                  "summary": "MEDIA component",
                  "value": {
                    "kind": "MEDIA",
                    "data": {
                      "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
                      "autoPlay": false
                    }
                  }
                },
                "COUNTDOWN": {
                  "summary": "COUNTDOWN component",
                  "value": {
                    "kind": "COUNTDOWN",
                    "data": {
                      "timestamp": 1767225600,
                      "textFont": "Inter"
                    }
                  }
                },
                "MAPS": {
                  "summary": "MAPS component",
                  "value": {
                    "kind": "MAPS",
                    "data": {
                      "name": "Our Office",
                      "address": "Jl. Sudirman, Jakarta",
                      "lat": -6.2088,
                      "lng": 106.8456,
                      "useLatLng": true
                    }
                  }
                },
                "CALENDAR": {
                  "summary": "CALENDAR component",
                  "value": {
                    "kind": "CALENDAR",
                    "data": {
                      "title": "Product Launch",
                      "startDate": "2026-07-01T09:00:00Z",
                      "endDate": "2026-07-01T10:00:00Z",
                      "timezone": "Asia/Jakarta"
                    }
                  }
                },
                "SHOP_ITEM": {
                  "summary": "SHOP_ITEM component",
                  "value": {
                    "kind": "SHOP_ITEM",
                    "data": {
                      "shopItemId": "5f9f1b9b9b9b9b9b9b9b9b9b",
                      "style": "card"
                    }
                  }
                },
                "CV": {
                  "summary": "CV component (nested experiences / educations / skills)",
                  "value": {
                    "kind": "CV",
                    "data": {
                      "fullName": "Jane Doe",
                      "email": "jane@example.com",
                      "phone": "+628123456789",
                      "summary": "10 years of product design.",
                      "experiences": [
                        {
                          "name": "Acme Inc.",
                          "position": "Lead Designer",
                          "startDate": "2022-01",
                          "endDate": "",
                          "currentlyHere": true,
                          "location": "Jakarta, ID",
                          "description": "Owns the design system."
                        }
                      ],
                      "educations": [
                        {
                          "name": "University of Indonesia",
                          "position": "B.Des. Product Design",
                          "startDate": "2014-08",
                          "endDate": "2018-07",
                          "currentlyHere": false,
                          "gpa": 3.8,
                          "description": "Cum laude."
                        }
                      ],
                      "skills": [
                        {
                          "title": "Figma",
                          "description": "Expert"
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Component created",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Envelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/MicrositeComponent"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/microsites/{slug}/components/{componentId}": {
      "parameters": [
        {
          "name": "slug",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "The slug of the microsite"
        },
        {
          "name": "componentId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "The component ID"
        }
      ],
      "put": {
        "summary": "Update a microsite component",
        "description": "Updates a single microsite component.",
        "operationId": "updateMicrositeComponent",
        "tags": ["Microsites"],
        "security": [
          {
            "ApiKeyAuth": ["microsites:write"]
          },
          {
            "OAuth2": ["microsites:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["active", "kind", "data"],
                "properties": {
                  "active": {
                    "type": "boolean",
                    "description": "Whether the component is shown"
                  },
                  "kind": {
                    "type": "string",
                    "description": "Component kind (e.g. `LINK`, `PROFILE`, `TEXT`)",
                    "example": "LINK"
                  },
                  "data": {
                    "type": "object",
                    "description": "Kind-specific component data"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Component updated",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Envelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/MicrositeComponent"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "summary": "Delete a microsite component",
        "description": "Deletes a single microsite component.",
        "operationId": "deleteMicrositeComponent",
        "tags": ["Microsites"],
        "security": [
          {
            "ApiKeyAuth": ["microsites:delete"]
          },
          {
            "OAuth2": ["microsites:delete"]
          }
        ],
        "responses": {
          "200": {
            "description": "Component deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/microsites/{slug}/components/order": {
      "post": {
        "summary": "Reorder microsite components",
        "description": "Reorders a microsite's components according to the provided list of component IDs.",
        "operationId": "orderMicrositeComponents",
        "tags": ["Microsites"],
        "security": [
          {
            "ApiKeyAuth": ["microsites:write"]
          },
          {
            "OAuth2": ["microsites:write"]
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The slug of the microsite"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["orders"],
                "properties": {
                  "orders": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Component IDs in the desired display order"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Components reordered",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/oauth/authorize": {
      "get": {
        "tags": ["OAuth 2.0"],
        "summary": "Get consent screen data",
        "description": "A plain browser navigation here (no `Accept: application/json`) 302-redirects to the dash.s.id consent UI, preserving the query string. With `Accept: application/json`, returns application name, logo, and requested scopes for the consent UI to render.",
        "servers": [
          {
            "url": "https://api.s.id"
          }
        ],
        "parameters": [
          {
            "name": "client_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "redirect_uri",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "response_type",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": ["code"]
            }
          },
          {
            "name": "scope",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "example": "links:read user:read"
            }
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "description": "Recommended. Opaque value for CSRF protection. Returned unchanged in the redirect.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Consent screen data",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "client": {
                      "type": "object",
                      "properties": {
                        "client_id": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "logo_url": {
                          "type": "string"
                        }
                      }
                    },
                    "scopes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "state": {
                      "type": "string"
                    },
                    "redirect_uri": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/oauth/token": {
      "post": {
        "tags": ["OAuth 2.0"],
        "summary": "Exchange code or refresh token",
        "servers": [
          {
            "url": "https://api.s.id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/OAuthTokenRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OAuthTokenRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OAuthTokenResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid grant, unsupported_grant_type, or invalid_client",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Invalid client credentials",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/oauth/revoke": {
      "post": {
        "tags": ["OAuth 2.0"],
        "summary": "Revoke a token",
        "description": "Revokes an access or refresh token. Always returns 200 OK regardless of whether the token was valid (RFC 7009).",
        "servers": [
          {
            "url": "https://api.s.id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["token"],
                "properties": {
                  "token": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token revoked",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/oauth/introspect": {
      "post": {
        "tags": ["OAuth 2.0"],
        "summary": "Introspect a token",
        "description": "Reports whether a token is currently active and, if so, which scopes and client it belongs to (RFC 7662). Client-credential protected: `client_id`/`client_secret` identify the caller, not the token owner. Always returns `200` — including for an unknown, expired, or revoked token (`{\"active\": false}`) — to avoid leaking token validity to unauthenticated probing.",
        "servers": [
          {
            "url": "https://api.s.id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["token", "client_id", "client_secret"],
                "properties": {
                  "token": {
                    "type": "string"
                  },
                  "client_id": {
                    "type": "string"
                  },
                  "client_secret": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Introspection result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "active": {
                      "type": "boolean"
                    },
                    "scope": {
                      "type": "string",
                      "description": "Space-separated scopes. Present only when active is true."
                    },
                    "client_id": {
                      "type": "string"
                    },
                    "sub": {
                      "type": "string",
                      "description": "The authorizing user's ID."
                    },
                    "exp": {
                      "type": "integer",
                      "description": "Unix timestamp the access token expires at."
                    },
                    "token_type": {
                      "type": "string",
                      "example": "Bearer"
                    }
                  },
                  "example": {
                    "active": true,
                    "scope": "links:read links:write",
                    "client_id": "cl_abc123",
                    "sub": "12345",
                    "exp": 1735689600,
                    "token_type": "Bearer"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing token/client_id, or invalid client credentials"
          }
        }
      }
    },
    "/oauth/userinfo": {
      "get": {
        "tags": ["OAuth 2.0"],
        "summary": "Get authorized user profile",
        "description": "Returns the profile of the user who authorized the OAuth app. Requires `Authorization: Bearer <access_token>` (the OAuth access token, not an sk_live_ key).",
        "servers": [
          {
            "url": "https://api.s.id"
          }
        ],
        "security": [
          {
            "OAuth2": ["user:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "User profile",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OAuthUserInfo"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Unauthorized"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/oauth-authorization-server": {
      "get": {
        "tags": ["OAuth 2.0"],
        "summary": "OAuth 2.0 Authorization Server Metadata",
        "description": "RFC 8414 discovery document advertising every OAuth endpoint URL, supported scopes, and PKCE methods, so standards-compliant client libraries can configure themselves instead of hard-coding s.id's URLs.",
        "servers": [
          {
            "url": "https://api.s.id"
          }
        ],
        "responses": {
          "200": {
            "description": "Authorization server metadata",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "issuer": {
                      "type": "string"
                    },
                    "authorization_endpoint": {
                      "type": "string"
                    },
                    "token_endpoint": {
                      "type": "string"
                    },
                    "revocation_endpoint": {
                      "type": "string"
                    },
                    "introspection_endpoint": {
                      "type": "string"
                    },
                    "userinfo_endpoint": {
                      "type": "string"
                    },
                    "scopes_supported": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "response_types_supported": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "grant_types_supported": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "code_challenge_methods_supported": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/user/oauth/apps": {
      "get": {
        "tags": ["OAuth 2.0"],
        "summary": "List apps authorized by the current user",
        "description": "Returns all OAuth clients that have active tokens for the authenticated user. Auth: user session cookie (not API key).",
        "servers": [
          {
            "url": "https://api.s.id"
          }
        ],
        "responses": {
          "200": {
            "description": "List of connected apps",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/OAuthConnectedApp"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Unauthorized"
                }
              }
            }
          }
        }
      }
    },
    "/api/user/oauth/apps/{clientId}": {
      "delete": {
        "tags": ["OAuth 2.0"],
        "summary": "Revoke all tokens for an app",
        "description": "Revokes all active tokens granted by the current user to the specified OAuth client.",
        "servers": [
          {
            "url": "https://api.s.id"
          }
        ],
        "parameters": [
          {
            "name": "clientId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "App access revoked",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "app_access_revoked"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Unauthorized"
                }
              }
            }
          },
          "404": {
            "description": "App not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/integrations/make/webhook/subscribe": {
      "post": {
        "tags": ["Integrations"],
        "summary": "Subscribe a Make.com webhook",
        "description": "Registers a Make.com (Integromat) scenario webhook URL to receive s.id events. Authenticated via DeveloperAPIAuth (API key or OAuth Bearer) with no scope requirement — every authenticated developer credential can subscribe.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Subscribed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "subscribed"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Unauthorized"
                }
              }
            }
          }
        }
      }
    },
    "/integrations/make/webhook/unsubscribe": {
      "post": {
        "tags": ["Integrations"],
        "summary": "Unsubscribe a Make.com webhook",
        "description": "Removes a previously registered Make.com scenario webhook subscription. Authenticated via DeveloperAPIAuth with no scope requirement.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Unsubscribed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "unsubscribed"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Unauthorized"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "sk_live_*",
        "description": "API key issued in Dashboard → Developer. Send as `Authorization: Bearer sk_live_...`."
      },
      "OAuth2": {
        "type": "oauth2",
        "description": "Authorization-code flow for acting on behalf of other s.id users.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://api.s.id/oauth/authorize",
            "tokenUrl": "https://api.s.id/oauth/token",
            "refreshUrl": "https://api.s.id/oauth/token",
            "scopes": {
              "links:read": "List and read links",
              "links:write": "Create and update links (create, edit, restore)",
              "links:archive": "Archive links",
              "links:analytics": "Read per-link click statistics",
              "qr:read": "Read QR code settings",
              "qr:write": "Customize QR code settings",
              "user:read": "Read the authenticated user profile and quota",
              "microsites:read": "List and read microsites",
              "microsites:write": "Create, update and manage components of microsites",
              "microsites:delete": "Delete microsites and their components"
            }
          }
        }
      }
    },
    "responses": {
      "LinkResponse": {
        "description": "A single link",
        "content": {
          "application/json": {
            "schema": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/Envelope"
                },
                {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Link"
                    }
                  }
                }
              ]
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or invalid API key",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "code": 401,
              "message": "unauthorized"
            }
          }
        }
      },
      "Forbidden": {
        "description": "API key lacks the required scope",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ScopeError"
            },
            "example": {
              "error": "insufficient_scope",
              "required": "links:write"
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ValidationError": {
        "description": "Request validation failed",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Too many requests (38/min per key)",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ScopeError"
            },
            "example": {
              "error": "rate_limit_exceeded"
            }
          }
        }
      }
    },
    "schemas": {
      "Envelope": {
        "type": "object",
        "description": "Standard response envelope.",
        "properties": {
          "code": {
            "type": "integer",
            "example": 200
          },
          "message": {
            "type": "string"
          },
          "total": {
            "type": "integer",
            "nullable": true
          },
          "took": {
            "type": "integer",
            "description": "Server processing time in ms"
          },
          "data": {}
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "code": {
            "type": "integer"
          },
          "message": {
            "type": "string"
          },
          "errors": {}
        }
      },
      "ScopeError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "required": {
            "type": "string"
          }
        }
      },
      "CreateLinkBody": {
        "type": "object",
        "required": ["long_url"],
        "properties": {
          "long_url": {
            "type": "string",
            "format": "uri",
            "minLength": 11,
            "maxLength": 2083,
            "description": "The destination (long) URL"
          },
          "title": {
            "type": "string",
            "maxLength": 48
          },
          "custom_slug": {
            "type": "string",
            "maxLength": 48,
            "description": "Custom short code; auto-generated when omitted"
          },
          "password": {
            "type": "string",
            "description": "Optional password to protect the link"
          },
          "expired_at": {
            "type": "integer",
            "format": "int64",
            "description": "Optional expiry as a Unix timestamp (seconds)"
          },
          "domain_alias": {
            "type": "string",
            "description": "Custom domain to use instead of s.id"
          }
        }
      },
      "UpdateLinkBody": {
        "type": "object",
        "description": "All fields are optional. Omitted fields leave the existing value unchanged.",
        "properties": {
          "long_url": {
            "type": "string",
            "format": "uri",
            "maxLength": 2083,
            "description": "New destination URL"
          },
          "title": {
            "type": "string",
            "maxLength": 48
          },
          "custom_slug": {
            "type": "string",
            "maxLength": 48,
            "description": "Rename the short code (subject to plan quota)"
          },
          "password": {
            "type": "string",
            "maxLength": 255,
            "description": "Set a password (`\"\"` removes existing protection)"
          },
          "disposable": {
            "type": "boolean",
            "description": "Mark link as disposable (expires after first click)"
          },
          "adult": {
            "type": "boolean",
            "description": "Flag link as adult content"
          },
          "archive_at": {
            "type": "string",
            "format": "date",
            "example": "2026-12-31",
            "description": "Schedule auto-archive on this date (YYYY-MM-DD)"
          },
          "domain_alias": {
            "type": "string",
            "description": "Change the custom domain (must be owned by the user)"
          }
        }
      },
      "Link": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "example": 123
          },
          "short": {
            "type": "string",
            "example": "mylink"
          },
          "short_url": {
            "type": "string",
            "example": "https://s.id/mylink"
          },
          "long_url": {
            "type": "string",
            "example": "https://example.com/a-very-long-url"
          },
          "microsite": {
            "type": "boolean"
          },
          "protected": {
            "type": "boolean"
          },
          "disposable": {
            "type": "boolean"
          },
          "adult": {
            "type": "boolean"
          },
          "blocked": {
            "type": "boolean",
            "nullable": true
          },
          "blocked_reason": {
            "type": "string",
            "nullable": true
          },
          "blocked_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "archive_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "StatPoint": {
        "type": "object",
        "properties": {
          "time": {
            "type": "string",
            "format": "date-time"
          },
          "count": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "LifetimeCount": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "format": "int64",
            "description": "All-time total click count for the link"
          }
        }
      },
      "Quota": {
        "type": "object",
        "description": "Current plan limits and usage for the authenticated user.",
        "properties": {
          "links": {
            "type": "integer",
            "description": "Maximum number of active links allowed by the current plan"
          },
          "links_used": {
            "type": "integer",
            "description": "Number of active links currently in use"
          }
        }
      },
      "User": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "username": {
            "type": "string"
          }
        }
      },
      "WebhookEvent": {
        "type": "object",
        "description": "Payload POSTed to your webhook endpoint. Verify the `X-SID-Signature` header (HMAC-SHA256 of the raw body) before trusting it.",
        "properties": {
          "event": {
            "type": "string",
            "enum": [
              "link.created",
              "link.updated",
              "link.archived",
              "link.clicked",
              "microsite.published",
              "qr.scanned"
            ]
          },
          "link": {
            "type": "object",
            "properties": {
              "id": {
                "type": "integer",
                "format": "int64"
              },
              "short": {
                "type": "string"
              },
              "short_url": {
                "type": "string"
              },
              "long_url": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "created": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        },
        "example": {
          "event": "link.created",
          "link": {
            "id": 123,
            "short": "mylink",
            "short_url": "https://s.id/mylink",
            "long_url": "https://example.com/a-very-long-url",
            "title": "My Link",
            "created": "2026-06-22T10:00:00Z"
          },
          "timestamp": "2026-06-22T10:00:00Z"
        }
      },
      "Microsite": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Microsite ID (opaque hex string)"
          },
          "slug": {
            "type": "string",
            "description": "URL slug — the short path on s.id"
          },
          "title": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Public URL of the microsite"
          },
          "visibility": {
            "type": "string",
            "enum": ["public", "hidden"]
          },
          "created": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "QrSettings": {
        "type": "object",
        "description": "QR code customization settings (global or per-link).",
        "properties": {
          "logo": {
            "type": "string",
            "maxLength": 255,
            "nullable": true,
            "description": "URL of the logo image embedded in the QR code"
          },
          "color": {
            "type": "string",
            "nullable": true,
            "description": "Foreground color as a hex value, e.g. #1a56db",
            "example": "#1a56db"
          }
        }
      },
      "QrSettingsBody": {
        "type": "object",
        "description": "All fields are optional. Omitted fields leave the existing value unchanged.",
        "properties": {
          "logo": {
            "type": "string",
            "maxLength": 255,
            "description": "URL of the logo image embedded in the QR code"
          },
          "color": {
            "type": "string",
            "description": "Foreground color as a hex value, e.g. #1a56db",
            "example": "#1a56db"
          }
        }
      },
      "MicrositeComponent": {
        "type": "object",
        "description": "A single component within a microsite.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Component ID (opaque string)"
          },
          "kind": {
            "type": "string",
            "description": "Component kind. The shape of `data` depends on this value.",
            "enum": [
              "PROFILE",
              "LINK",
              "HORIZONTAL_LINK",
              "TEXT",
              "IMAGE",
              "MEDIA",
              "DIVIDER",
              "COUNTDOWN",
              "MAPS",
              "IMAGE_SLIDE",
              "CV",
              "AUTOPLAY_MUSIC",
              "CONTACT",
              "CALENDAR",
              "SHOP_LISTING",
              "SHOP_ITEM",
              "SHOP_LEADERBOARD"
            ],
            "example": "LINK"
          },
          "active": {
            "type": "boolean",
            "description": "Whether the component is shown"
          },
          "tag": {
            "type": "string",
            "nullable": true,
            "description": "Optional grouping tag"
          },
          "data": {
            "type": "object",
            "description": "Kind-specific component data. Its shape depends on `kind`."
          }
        }
      },
      "AccountStats": {
        "type": "object",
        "properties": {
          "total_links": {
            "type": "integer"
          },
          "timeline": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "date": {
                  "type": "string"
                },
                "count": {
                  "type": "integer"
                }
              }
            }
          },
          "links": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string"
                },
                "count": {
                  "type": "integer"
                }
              }
            }
          },
          "referer": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Populated when additional=true"
          },
          "location": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Populated when additional=true"
          },
          "device": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Populated when additional=true"
          },
          "browser": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Populated when additional=true"
          }
        }
      },
      "OAuthTokenRequest": {
        "type": "object",
        "properties": {
          "grant_type": {
            "type": "string",
            "enum": ["authorization_code", "refresh_token"]
          },
          "code": {
            "type": "string"
          },
          "redirect_uri": {
            "type": "string"
          },
          "client_id": {
            "type": "string"
          },
          "client_secret": {
            "type": "string"
          },
          "refresh_token": {
            "type": "string"
          }
        }
      },
      "OAuthTokenResponse": {
        "type": "object",
        "properties": {
          "access_token": {
            "type": "string"
          },
          "token_type": {
            "type": "string",
            "example": "Bearer"
          },
          "expires_in": {
            "type": "integer",
            "example": 3600
          },
          "refresh_token": {
            "type": "string"
          },
          "scope": {
            "type": "string"
          }
        }
      },
      "OAuthUserInfo": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          }
        }
      },
      "OAuthConnectedApp": {
        "type": "object",
        "properties": {
          "client_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "logo_url": {
            "type": "string"
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "authorized_at": {
            "type": "string",
            "format": "date-time"
          },
          "last_used_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When an access token belonging to this client was last used to authenticate a request. Null if never used."
          },
          "scopes_used": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Subset of `scopes` actually exercised by a request so far. Scopes granted but not present here are dormant."
          }
        }
      }
    }
  }
}
