{
  "openapi": "3.0.0",
  "info": {
    "title": "Text Watermark",
    "version": "2.0.0",
    "description": "TextWatermark API v2.0"
  },
  "servers": [
    {
      "url": "https://textwatermarking.com"
    }
  ],
  "tags": [
    {
      "name": "User Authentication",
      "description": "Endpoints for user registration, login, and session management."
    },
    {
      "name": "User Account",
      "description": "Manage user profile information, password, API quota, etc."
    },
    {
      "name": "Token Management",
      "description": "Endpoints for creating, listing, and revoking API tokens."
    },
    {
      "name": "Credits",
      "description": "Check credit balance and usage history."
    },
    {
      "name": "Watermarking",
      "description": "Core endpoints for encoding, decoding, and analyzing watermarked text."
    },
    {
      "name": "Signing Channels",
      "description": "Manage encryption contexts for keyed (AES-256-GCM) watermarking."
    }
  ],
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "A message describing the error."
          },
          "details": {
            "type": "object",
            "additionalProperties": true,
            "description": "Additional error details, if any."
          }
        },
        "required": [
          "error"
        ]
      },
      "User": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique identifier for the user.",
            "example": "a1b2c3d4-e5f6-7890-1234-567890abcdef"
          },
          "email": {
            "type": "string",
            "format": "email",
            "example": "user@example.com"
          },
          "username": {
            "type": "string",
            "example": "newuser"
          },
          "firstName": {
            "type": "string",
            "example": "Test"
          },
          "lastName": {
            "type": "string",
            "example": "User"
          }
        }
      },
      "ApiToken": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique identifier for the API token.",
            "example": "tok_a1b2c3d4e5f67890"
          },
          "name": {
            "type": "string",
            "description": "A user-defined name for the token.",
            "example": "My Production Key"
          },
          "permissions": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Permissions associated with this token (e.g., encode, decode).",
            "example": [
              "encode",
              "decode"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of when the token was created."
          },
          "last_used_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Timestamp of when the token was last used."
          }
        }
      },
      "ApiTokenWithSecret": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ApiToken"
          },
          {
            "type": "object",
            "properties": {
              "token": {
                "type": "string",
                "description": "The actual API token secret. Shown only once upon creation \u2014 store it securely.",
                "example": "a3f8e2b1c9d47f6a2b5c8d1e9f3a4b7c2e5d8f1a4c7b2e5d8f1a4c7b2e5d8f1"
              }
            },
            "required": [
              "token"
            ]
          }
        ]
      }
    },
    "responses": {
      "UnauthorizedError": {
        "description": "Unauthorized - JWT or API Key is missing, invalid, or expired.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "Authentication token is invalid or has expired."
            }
          }
        }
      },
      "BadRequestError": {
        "description": "Bad Request - The request payload is malformed or missing required fields.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "Invalid input.",
              "details": {
                "field_name": [
                  "Error message for this field."
                ]
              }
            }
          }
        }
      },
      "NotFoundError": {
        "description": "Not Found - The requested resource does not exist.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "Resource not found."
            }
          }
        }
      },
      "InternalServerError": {
        "description": "Internal Server Error - An unexpected error occurred on the server.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "An unexpected server error occurred."
            }
          }
        }
      }
    },
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "JWT for user-specific operations (e.g., managing profile, API tokens)."
      },
      "ApiTokenAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API token for watermarking operations. Format: 'Bearer <your-api-token>'. Obtain from POST /api/v2/tokens."
      }
    }
  },
  "paths": {
    "/api/auth/register": {
      "parameters": [],
      "post": {
        "summary": "Register User",
        "description": "Creates a new user profile and associated authentication credentials. After successful registration, the user typically needs to verify their email address.",
        "tags": [
          "User Authentication"
        ],
        "parameters": [
          {
            "name": "Content-Type",
            "in": "header",
            "required": false,
            "example": "application/json",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "User registration details.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email",
                    "example": "user@example.com"
                  },
                  "password": {
                    "type": "string",
                    "format": "password",
                    "example": "YourStrongPassword123!"
                  },
                  "username": {
                    "type": "string",
                    "example": "newuser"
                  },
                  "firstName": {
                    "type": "string",
                    "example": "Test"
                  },
                  "lastName": {
                    "type": "string",
                    "example": "User"
                  }
                },
                "required": [
                  "email",
                  "password",
                  "username"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "User registered successfully. Email verification may be required.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "User registered successfully. Please check your email to verify your account."
                    },
                    "user": {
                      "$ref": "#/components/schemas/User"
                    }
                  }
                },
                "example": {
                  "message": "User registered successfully. Please check your email to verify your account.",
                  "user": {
                    "id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
                    "email": "user@example.com",
                    "username": "newuser",
                    "firstName": "Test",
                    "lastName": "User"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - Validation error (e.g., email already exists, password too weak).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Validation failed.",
                  "details": {
                    "email": [
                      "The email has already been taken."
                    ]
                  }
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "An unexpected error occurred."
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/login": {
      "parameters": [],
      "post": {
        "summary": "User Login",
        "description": "Authenticates a user with their email and password, returning JWT access and refresh tokens upon success.",
        "tags": [
          "User Authentication"
        ],
        "parameters": [
          {
            "name": "Content-Type",
            "in": "header",
            "required": false,
            "example": "application/json",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "User login credentials.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email",
                    "example": "user@example.com"
                  },
                  "password": {
                    "type": "string",
                    "format": "password",
                    "example": "YourStrongPassword123!"
                  }
                },
                "required": [
                  "email",
                  "password"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Login successful. The refresh token is set as an httpOnly cookie (not in the response body).",
            "headers": {
              "Set-Cookie": {
                "description": "httpOnly refresh token cookie (30-day TTL). Sent automatically by the browser on subsequent requests.",
                "schema": {
                  "type": "string",
                  "example": "refreshToken=eyJ...; HttpOnly; Secure; SameSite=Strict; Path=/api/auth/refresh"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Login successful"
                    },
                    "accessToken": {
                      "type": "string",
                      "description": "JWT access token, valid for 2 hours.",
                      "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOi..."
                    },
                    "user": {
                      "$ref": "#/components/schemas/User"
                    }
                  }
                },
                "example": {
                  "message": "Login successful",
                  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhMWIyYzNkNC1lNWY2LTc4OTAtMTIzNC01Njc4OTBhYmNkZWYiLCJpYXQiOjE2MTYyMzkwMjIsImV4cCI6MTYxNjI0MjYyMn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
                  "user": {
                    "id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
                    "email": "user@example.com",
                    "username": "testuser"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - Invalid input (e.g., missing fields).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Email and password are required."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Invalid email or password."
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "An unexpected error occurred."
                }
              }
            }
          }
        }
      }
    },
    "/api/v2/users/me": {
      "get": {
        "summary": "Get User Profile",
        "description": "Fetches the profile, API tokens (metadata, not raw tokens), and quota information for the currently authenticated user.",
        "tags": [
          "User Account"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful retrieval of user profile information.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "user": {
                      "$ref": "#/components/schemas/User"
                    },
                    "api_tokens": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "name": {
                            "type": "string"
                          },
                          "permissions": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "last_used_at": {
                            "type": "string",
                            "format": "date-time",
                            "nullable": true
                          }
                        }
                      }
                    },
                    "quota": {
                      "type": "object",
                      "properties": {
                        "requests_made": {
                          "type": "integer"
                        },
                        "requests_limit": {
                          "type": "integer"
                        },
                        "requests_remaining": {
                          "type": "integer"
                        },
                        "resets_at": {
                          "type": "string",
                          "format": "date-time"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "user": {
                    "id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
                    "email": "user@example.com",
                    "username": "testuser",
                    "firstName": "Test",
                    "lastName": "User"
                  },
                  "api_tokens": [
                    {
                      "id": "tok_abcdef123456",
                      "name": "My Main Key",
                      "permissions": [
                        "encode",
                        "decode"
                      ],
                      "created_at": "2023-01-15T10:00:00Z",
                      "last_used_at": "2023-10-01T12:30:00Z"
                    }
                  ],
                  "quota": {
                    "requests_made": 1250,
                    "requests_limit": 10000,
                    "requests_remaining": 8750,
                    "resets_at": "2023-11-01T00:00:00Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "put": {
        "summary": "Update User Profile",
        "description": "Updates profile information (e.g., username, first name, last name) for the currently authenticated user.",
        "tags": [
          "User Account"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "description": "Fields to update in the user profile. Only include fields that need to be changed.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "username": {
                    "type": "string",
                    "example": "updated_username"
                  },
                  "firstName": {
                    "type": "string",
                    "example": "UpdatedFirst"
                  },
                  "lastName": {
                    "type": "string",
                    "example": "UpdatedLast"
                  }
                },
                "minProperties": 1
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "User profile updated successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Profile updated successfully."
                    },
                    "user": {
                      "$ref": "#/components/schemas/User"
                    }
                  }
                },
                "example": {
                  "message": "Profile updated successfully.",
                  "user": {
                    "id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
                    "email": "user@example.com",
                    "username": "updated_username",
                    "firstName": "UpdatedFirst",
                    "lastName": "UpdatedLast"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/v2/tokens": {
      "get": {
        "summary": "List User API Tokens",
        "description": "Retrieves a list of all API tokens (metadata only, no secrets) associated with the authenticated user's account.",
        "tags": [
          "Token Management"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "A list of API tokens.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ApiToken"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/v2/tokens/{tokenId}": {
      "parameters": [
        {
          "name": "tokenId",
          "in": "path",
          "required": true,
          "description": "The ID of the API token (e.g., tok_a1b2c3d4e5f67890). This is the value of the 'id' field of an API token, not the secret token string itself.",
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "delete": {
        "summary": "Revoke API Token",
        "description": "Permanently revokes and deletes an API token by its ID.",
        "tags": [
          "Token Management"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "API Token revoked successfully. No content returned."
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "description": "Forbidden - User does not have permission to delete this token or token belongs to another user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/v2/credits/balance": {
      "get": {
        "summary": "Get Credit Balance",
        "description": "Returns the current credit balance, subscription plan, and subscription status for the authenticated user.",
        "tags": [
          "Credits"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Credit balance information.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "balance": {
                      "type": "integer",
                      "description": "Current available credit balance.",
                      "example": 8750
                    },
                    "plan": {
                      "type": "string",
                      "description": "Active subscription plan name.",
                      "enum": [
                        "free",
                        "starter",
                        "pro"
                      ],
                      "example": "starter"
                    },
                    "subscription_status": {
                      "type": "string",
                      "enum": [
                        "active",
                        "past_due",
                        "paused",
                        "cancelled",
                        "expired"
                      ],
                      "example": "active"
                    },
                    "renews_at": {
                      "type": "string",
                      "format": "date-time",
                      "nullable": true,
                      "description": "Next renewal date for the subscription.",
                      "example": "2026-04-30T00:00:00Z"
                    }
                  }
                },
                "example": {
                  "balance": 8750,
                  "plan": "starter",
                  "subscription_status": "active",
                  "renews_at": "2026-04-30T00:00:00Z"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/v2/users/password": {
      "put": {
        "summary": "Change User Password",
        "description": "Allows the authenticated user to change their password.",
        "tags": [
          "User Account"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "description": "User's current and new password.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "currentPassword": {
                    "type": "string",
                    "format": "password",
                    "description": "The user's current password.",
                    "example": "OldPassword123!"
                  },
                  "newPassword": {
                    "type": "string",
                    "format": "password",
                    "description": "The desired new password. Must meet complexity requirements.",
                    "example": "NewSecurePassword456@"
                  }
                },
                "required": [
                  "currentPassword",
                  "newPassword"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Password changed successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Password updated successfully."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/watermark/encode": {
      "post": {
        "summary": "Encode Watermark",
        "description": "Embeds a secret payload into carrier text using Unicode variation selectors. The hidden data is invisible to the naked eye. Supports multiple encoding methods with automatic capacity validation.\n\nUse a **keyed API token** (linked to a signing channel) to enable AES-256-GCM encrypted watermarking.",
        "tags": [
          "Watermarking"
        ],
        "security": [
          {
            "ApiTokenAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "text",
                  "secret"
                ],
                "properties": {
                  "text": {
                    "type": "string",
                    "description": "The visible carrier text to embed the secret into.",
                    "example": "The quick brown fox jumps over the lazy dog."
                  },
                  "secret": {
                    "type": "string",
                    "description": "The secret payload to hide in the text.",
                    "example": "user_id:123,doc:confidential"
                  },
                  "method": {
                    "type": "string",
                    "enum": [
                      "auto",
                      "single",
                      "chunked",
                      "char",
                      "pattern"
                    ],
                    "default": "auto",
                    "description": "Encoding method:\n- `auto` \u2014 selects automatically (single word \u2192 char, multi-word \u2192 chunked)\n- `single` \u2014 1 byte per grapheme (Approach A, lowest density)\n- `chunked` \u2014 N bytes per grapheme, configurable via `chunkSize` (Approach B)\n- `char` \u2014 distributes across all graphemes of a word/token (up to 256 bytes/grapheme)\n- `pattern` \u2014 encode into a specific pattern string\n\nOmit for automatic selection. Keyed tokens always use AES-256-GCM regardless of this field.",
                    "example": "auto"
                  },
                  "chunkSize": {
                    "type": "integer",
                    "minimum": 1,
                    "default": 1,
                    "description": "Number of secret bytes to embed per grapheme. Only used when `method` is `chunked`.",
                    "example": 4
                  },
                  "firstLetterOnly": {
                    "type": "boolean",
                    "default": false,
                    "description": "When `method` is `char`, embed the entire secret only into the first grapheme of the carrier. Default distributes across all graphemes.",
                    "example": false
                  },
                  "output": {
                    "type": "string",
                    "enum": [
                      "full",
                      "tokens"
                    ],
                    "default": "full",
                    "description": "`full` (default) returns the complete encoded carrier text. `tokens` returns only the graphemes that carry variation selectors \u2014 useful for MCP agents storing minimal payloads.",
                    "example": "full"
                  },
                  "pattern": {
                    "type": "string",
                    "description": "Required when `method` is `pattern`. The pattern string to encode into.",
                    "example": "AAAA-BBBB-CCCC"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Text successfully watermarked.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "encoded": {
                      "type": "string",
                      "description": "The watermarked text with the secret embedded as invisible Unicode variation selectors.",
                      "example": "The quick brown fox jumps over the lazy dog."
                    },
                    "keyed": {
                      "type": "boolean",
                      "description": "True if the token is linked to a signing channel and AES-256-GCM encryption was applied.",
                      "example": false
                    },
                    "stats": {
                      "type": "object",
                      "properties": {
                        "originalLength": {
                          "type": "integer",
                          "example": 44
                        },
                        "secretLength": {
                          "type": "integer",
                          "example": 27
                        },
                        "encodedLength": {
                          "type": "integer",
                          "example": 71
                        },
                        "chunkSize": {
                          "type": "integer",
                          "description": "Only present for single/chunked methods.",
                          "example": 1
                        },
                        "method": {
                          "type": "string",
                          "example": "auto"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request \u2014 missing parameters or carrier text too short.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Carrier text too short",
                  "details": "method=single needs 27 graphemes; got 5",
                  "required_length": 27
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "402": {
            "description": "Insufficient credits \u2014 balance reached zero before the operation could complete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Payment Required",
                  "message": "Insufficient credits. Current balance: 0"
                }
              }
            }
          }
        }
      }
    },
    "/api/watermark/encode-robust": {
      "post": {
        "summary": "Encode Watermark (Robust)",
        "description": "Embeds the secret as individual bits (1 bit per carrier character) using the `watermark_text` WASM function. More resilient to partial text loss than the VS-per-grapheme approach; requires 8\u00d7 more carrier characters per byte of payload. Supports keyed (AES-256-GCM encrypted) mode via a signing channel token.",
        "tags": [
          "Watermarking"
        ],
        "security": [
          {
            "ApiTokenAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "text",
                  "secret"
                ],
                "properties": {
                  "text": {
                    "type": "string",
                    "description": "Carrier text. Must have at least 8\u00d7 the byte length of the secret.",
                    "example": "The quick brown fox jumps over the lazy dog."
                  },
                  "secret": {
                    "type": "string",
                    "description": "Payload to hide.",
                    "example": "user_id:123"
                  },
                  "distribution": {
                    "type": "string",
                    "enum": [
                      "even",
                      "random",
                      "clustered"
                    ],
                    "default": "even",
                    "description": "How bits are distributed across the carrier."
                  },
                  "stealth_level": {
                    "type": "string",
                    "enum": [
                      "standard",
                      "high",
                      "maximum"
                    ],
                    "default": "standard",
                    "description": "Stealth intensity of the embedding."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Text robustly watermarked.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "watermarked": {
                      "type": "string",
                      "example": "The quick brown fox jumps over the lazy dog."
                    },
                    "keyed": {
                      "type": "boolean",
                      "example": false
                    },
                    "stats": {
                      "type": "object",
                      "properties": {
                        "visibleLength": {
                          "type": "integer",
                          "example": 44
                        },
                        "hiddenLength": {
                          "type": "integer",
                          "example": 10
                        },
                        "watermarkBitCount": {
                          "type": "integer",
                          "example": 80
                        },
                        "totalLength": {
                          "type": "integer",
                          "example": 124
                        },
                        "distribution": {
                          "type": "string",
                          "example": "even"
                        },
                        "stealthLevel": {
                          "type": "string",
                          "example": "standard"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "402": {
            "description": "Insufficient credits \u2014 balance reached zero before the operation could complete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Payment Required",
                  "message": "Insufficient credits. Current balance: 0"
                }
              }
            }
          }
        }
      }
    },
    "/api/watermark/decode": {
      "post": {
        "summary": "Decode Watermark",
        "description": "Extracts the hidden secret from watermarked text. Works for all unkeyed methods (auto/single/chunked/char). For keyed (encrypted) watermarks, the API token must be linked to the same signing channel used during encoding.",
        "tags": [
          "Watermarking"
        ],
        "security": [
          {
            "ApiTokenAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "text"
                ],
                "properties": {
                  "text": {
                    "type": "string",
                    "description": "The watermarked text to decode.",
                    "example": "The quick brown fox jumps over the lazy dog."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Secret successfully decoded.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "decoded": {
                      "type": "string",
                      "description": "The recovered secret payload.",
                      "example": "user_id:123,doc:confidential"
                    },
                    "keyed": {
                      "type": "boolean",
                      "description": "True if the watermark was decrypted using a signing channel key.",
                      "example": false
                    },
                    "stats": {
                      "type": "object",
                      "properties": {
                        "decodedLength": {
                          "type": "integer",
                          "example": 27
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "402": {
            "description": "Insufficient credits \u2014 balance reached zero before the operation could complete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Payment Required",
                  "message": "Insufficient credits. Current balance: 0"
                }
              }
            }
          }
        }
      }
    },
    "/api/watermark/decode-robust": {
      "post": {
        "summary": "Decode Watermark (Robust)",
        "description": "Extracts a bit-level watermark encoded with `encode-robust`. For keyed tokens, bits are decrypted using the signing channel key. Returns a `confidence` score (ratio of set bits to total extracted bits).",
        "tags": [
          "Watermarking"
        ],
        "security": [
          {
            "ApiTokenAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "text"
                ],
                "properties": {
                  "text": {
                    "type": "string",
                    "description": "Robustly watermarked text to decode.",
                    "example": "The quick brown fox jumps over the lazy dog."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Watermark extracted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "decoded": {
                      "type": "string",
                      "example": "user_id:123"
                    },
                    "keyed": {
                      "type": "boolean",
                      "example": false
                    },
                    "is_encoded": {
                      "type": "boolean",
                      "example": true
                    },
                    "bits_recovered": {
                      "type": "integer",
                      "example": 62
                    },
                    "confidence": {
                      "type": "number",
                      "format": "float",
                      "example": 0.775
                    },
                    "stats": {
                      "type": "object",
                      "properties": {
                        "extracted_bit_count": {
                          "type": "integer",
                          "example": 80
                        },
                        "reconstructed_char_count": {
                          "type": "integer",
                          "example": 10
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "422": {
            "description": "Decryption failed \u2014 wrong channel or corrupted watermark.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits \u2014 balance reached zero before the operation could complete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Payment Required",
                  "message": "Insufficient credits. Current balance: 0"
                }
              }
            }
          }
        }
      }
    },
    "/api/watermark/analyze": {
      "post": {
        "summary": "Analyze Watermarked Text",
        "description": "Analyzes encoded text and returns statistics: grapheme counts, variation selector count, hidden byte capacity, and size overhead ratio. Pass `original` for ratio and `original_length` to be meaningful.",
        "tags": [
          "Watermarking"
        ],
        "security": [
          {
            "ApiTokenAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "encoded"
                ],
                "properties": {
                  "encoded": {
                    "type": "string",
                    "description": "The watermarked text to analyze.",
                    "example": "The quick brown fox jumps over the lazy dog."
                  },
                  "original": {
                    "type": "string",
                    "description": "The original (pre-encoded) text. Required for `original_length` and `ratio` to be non-zero.",
                    "example": "The quick brown fox jumps over the lazy dog."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Analysis results.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "original_length": {
                      "type": "integer",
                      "description": "Grapheme count of the original text. 0 if `original` was not provided.",
                      "example": 44
                    },
                    "encoded_length": {
                      "type": "integer",
                      "description": "Total characters (base + variation selectors) in the encoded text.",
                      "example": 71
                    },
                    "encoded_bytes": {
                      "type": "integer",
                      "description": "Number of hidden bytes embedded (equals the variation selector count).",
                      "example": 27
                    },
                    "ratio": {
                      "type": "number",
                      "format": "float",
                      "description": "encoded_length / original_length. 0 if original not provided.",
                      "example": 1.61
                    },
                    "base_characters": {
                      "type": "integer",
                      "description": "Number of visible grapheme clusters in the encoded text.",
                      "example": 44
                    },
                    "variation_selectors": {
                      "type": "integer",
                      "description": "Number of invisible variation selector codepoints carrying hidden data.",
                      "example": 27
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "402": {
            "description": "Insufficient credits \u2014 balance reached zero before the operation could complete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Payment Required",
                  "message": "Insufficient credits. Current balance: 0"
                }
              }
            }
          }
        }
      }
    },
    "/api/v2/channels": {
      "post": {
        "summary": "Create Signing Channel",
        "description": "Creates a new signing channel with a server-managed AES-256-GCM key. Requires starter or pro plan. Limits: starter 3, pro 20.",
        "tags": [
          "Signing Channels"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "channel_name"
                ],
                "properties": {
                  "channel_name": {
                    "type": "string",
                    "description": "Unique name for the channel.",
                    "example": "my-production-channel"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Channel created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    },
                    "channel": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "channel_name": {
                          "type": "string"
                        },
                        "is_active": {
                          "type": "boolean"
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date-time"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "description": "Plan limit reached or free plan.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Channel name already exists.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "summary": "List Signing Channels",
        "description": "Returns all signing channels for the authenticated user, including the count of active tokens per channel. The channel secret is never returned.",
        "tags": [
          "Signing Channels"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Channel list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "channels": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "channel_name": {
                            "type": "string"
                          },
                          "is_active": {
                            "type": "boolean"
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "active_tokens": {
                            "type": "integer",
                            "example": 2
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          }
        }
      }
    },
    "/api/v2/channels/{channelId}": {
      "delete": {
        "summary": "Deactivate Signing Channel",
        "description": "Soft-deletes a channel (`is_active = false`). The channel secret is preserved so existing watermarks can still be decoded. Tokens bound to this channel remain functional until individually revoked.",
        "tags": [
          "Signing Channels"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "channelId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Channel deactivated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    },
                    "channel": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "channel_name": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "description": "Channel not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/verify-email": {
      "post": {
        "summary": "Verify Email",
        "description": "Verifies the user email address using the token sent to the registered email. Required before watermark operations are allowed.",
        "tags": [
          "User Authentication"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "token"
                ],
                "properties": {
                  "token": {
                    "type": "string",
                    "description": "The verification token from the email.",
                    "example": "abc123def456..."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Email verified successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Email verified successfully"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/auth/refresh": {
      "post": {
        "summary": "Refresh Access Token",
        "description": "Issues a new JWT access token using the httpOnly refresh cookie. The browser sends the cookie automatically. In server-side clients, include the cookie jar.",
        "tags": [
          "User Authentication"
        ],
        "responses": {
          "200": {
            "description": "New access token issued.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "accessToken": {
                      "type": "string",
                      "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          }
        }
      }
    },
    "/api/auth/logout": {
      "post": {
        "summary": "Logout",
        "description": "Invalidates the current session by clearing the httpOnly refresh cookie.",
        "tags": [
          "User Authentication"
        ],
        "responses": {
          "200": {
            "description": "Logged out successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Logged out successfully"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}