openapi: 3.1.0 info: title: ntfy API description: 'ntfy is a simple HTTP-based pub-sub notification service. It allows you to send push notifications to your phone or desktop via scripts from any computer. ## Features - **Publish messages**: Send messages to topics via PUT/POST - **Subscribe to topics**: Receive messages via JSON stream, SSE, raw stream, or WebSocket - **User management**: Authentication, tiered access, and account management - **Attachments**: Upload and attach files to messages - **Email & Phone**: Forward notifications to email or via phone calls - **UnifiedPush**: Support for UnifiedPush protocol ## Authentication Some endpoints require authentication if access control is enabled. Use either: - Basic Auth: `Authorization: Basic base64(username:password)` - Bearer Token: `Authorization: Bearer ` ## Rate Limiting Requests may be rate-limited based on IP address or user tier. ## CORS Proxy If you are running ntfy locally and accessing this documentation from "localhost" and attempting to make requests to a hosted ntfy server (like ntfy.sh) you may need to enable the "CORS Proxy" checkbox in the top right corner of the page. This will proxy the requests through the Scalar server to the hosted ntfy server. **BE Aware** this will count against the rate limit of the Scalar Proxy Server. So you may recieve 429 responses from the remote ntfy server.. ## Experimental Endpoints The following endpoints are experimental and may be changed or removed in the future. Use at your own risk. - Account Management Endpoints - Admin Endpoints ## Add your own ntfy server To add your own ntfy server to the drop down menu, add the following to the `servers` section of "docs/api/openapi.yaml" (or replace the exsiting server with your own https://myntfyserver.editinyaml.com): ```yaml servers: - url: https://your-ntfy-instance.com description: Your custom server ``` Once you have added your own custom server you will need to run `mkdocs build` to rebuild the documentation. ' version: 2.0.0 contact: name: ntfy url: https://ntfy.sh license: name: Apache-2.0 OR GPLv2 url: https://github.com/binwiederhier/ntfy servers: - url: https://ntfy.sh description: Public ntfy server - url: https://myntfyserver.editinyaml.com description: My NTFY Server tags: - name: Publish description: Publishing messages to topics - name: Subscribe description: Subscribing to topics and receiving messages - name: Account - **EXPERIMENTAL** description: User account management (EXPERIMENTAL) - THESE ENDPOINTS MAY CHANGE, BE REMOVED, OR ADDED TO IN THE FUTURE. - name: Admin - **EXPERIMENTAL** description: Administrative operations (EXPERIMENTAL) - THESE ENDPOINTS MAY CHANGE, BE REMOVED, OR ADDED TO IN THE FUTURE. - name: Matrix description: Matrix push gateway - name: WebPush description: Web Push subscriptions paths: /{topic}: post: tags: - Publish summary: Publish message to topic description: 'Publishes a message to a topic. The message body can be plain text, or you can use various headers to customize the notification. Topics are created on the fly when first used. Choose a topic name that''s not easily guessable as it acts like a password. ' operationId: publishMessage security: - {} - BasicAuth: [] - BearerAuth: [] parameters: - name: topic in: path required: true description: Topic name (1-64 characters, alphanumeric, dash, underscore) schema: type: string pattern: ^[-_A-Za-z0-9]{1,64}$ - $ref: '#/components/parameters/XTitle' - $ref: '#/components/parameters/XPriority' - $ref: '#/components/parameters/XTags' - $ref: '#/components/parameters/XClick' - $ref: '#/components/parameters/XIcon' - $ref: '#/components/parameters/XAttach' - $ref: '#/components/parameters/XFilename' - $ref: '#/components/parameters/XActions' - $ref: '#/components/parameters/XEmail' - $ref: '#/components/parameters/XCall' - $ref: '#/components/parameters/XDelay' - $ref: '#/components/parameters/XCache' - $ref: '#/components/parameters/XFirebase' - $ref: '#/components/parameters/XMarkdown' - $ref: '#/components/parameters/XTemplate' - $ref: '#/components/parameters/XPollId' - $ref: '#/components/parameters/XUnifiedPush' requestBody: description: Message body (plain text or binary data) content: text/plain: schema: type: string application/octet-stream: schema: type: string format: binary responses: '200': description: Message published successfully content: application/json: schema: $ref: '#/components/schemas/Message' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' put: tags: - Publish summary: Publish message to topic (PUT) description: Same as POST but uses PUT method operationId: publishMessagePut security: - {} - BasicAuth: [] - BearerAuth: [] parameters: - name: topic in: path required: true description: Topic name schema: type: string pattern: ^[-_A-Za-z0-9]{1,64}$ - $ref: '#/components/parameters/XTitle' - $ref: '#/components/parameters/XPriority' - $ref: '#/components/parameters/XTags' - $ref: '#/components/parameters/XClick' - $ref: '#/components/parameters/XIcon' - $ref: '#/components/parameters/XAttach' - $ref: '#/components/parameters/XFilename' - $ref: '#/components/parameters/XActions' - $ref: '#/components/parameters/XEmail' - $ref: '#/components/parameters/XCall' - $ref: '#/components/parameters/XDelay' - $ref: '#/components/parameters/XCache' - $ref: '#/components/parameters/XFirebase' - $ref: '#/components/parameters/XMarkdown' - $ref: '#/components/parameters/XTemplate' - $ref: '#/components/parameters/XPollId' - $ref: '#/components/parameters/XUnifiedPush' requestBody: description: Message body content: text/plain: schema: type: string application/octet-stream: schema: type: string format: binary responses: '200': description: Message published successfully content: application/json: schema: $ref: '#/components/schemas/Message' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' get: tags: - Subscribe summary: Get topic (web UI) description: Returns the web UI for the topic operationId: getTopic parameters: - name: topic in: path required: true description: Topic name schema: type: string pattern: ^[-_A-Za-z0-9]{1,64}$ - name: x-unifiedpush in: query description: UnifiedPush discovery schema: type: boolean responses: '200': description: Web UI or UnifiedPush info content: application/json: schema: type: object properties: unifiedpush: type: object properties: version: type: integer text/html: schema: type: string /{topic}/json: get: tags: - Subscribe summary: Subscribe to JSON stream description: 'Subscribes to a topic and returns a streaming HTTP response with JSON messages. The connection stays open indefinitely. Messages are sent as newline-delimited JSON (NDJSON). Control messages (open, keepalive) are also sent. ' operationId: subscribeJson security: - {} - BasicAuth: [] - BearerAuth: [] parameters: - name: topic in: path required: true description: Topic name or comma-separated list of topics schema: type: string pattern: ^[-_A-Za-z0-9]{1,64}(,[-_A-Za-z0-9]{1,64})*$ - $ref: '#/components/parameters/Poll' - $ref: '#/components/parameters/Since' - $ref: '#/components/parameters/Scheduled' - $ref: '#/components/parameters/FilterId' - $ref: '#/components/parameters/FilterMessage' - $ref: '#/components/parameters/FilterTitle' - $ref: '#/components/parameters/FilterPriority' - $ref: '#/components/parameters/FilterTags' responses: '200': description: Streaming JSON response content: application/x-ndjson: schema: type: array items: $ref: '#/components/schemas/Message' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' /{topic}/sse: get: tags: - Subscribe summary: Subscribe to Server-Sent Events stream description: 'Subscribes to a topic using Server-Sent Events (SSE). This is ideal for JavaScript clients using EventSource. Messages are sent as SSE events with JSON data. ' operationId: subscribeSse security: - {} - BasicAuth: [] - BearerAuth: [] parameters: - name: topic in: path required: true description: Topic name or comma-separated list of topics schema: type: string pattern: ^[-_A-Za-z0-9]{1,64}(,[-_A-Za-z0-9]{1,64})*$ - $ref: '#/components/parameters/Poll' - $ref: '#/components/parameters/Since' - $ref: '#/components/parameters/Scheduled' - $ref: '#/components/parameters/FilterId' - $ref: '#/components/parameters/FilterMessage' - $ref: '#/components/parameters/FilterTitle' - $ref: '#/components/parameters/FilterPriority' - $ref: '#/components/parameters/FilterTags' responses: '200': description: SSE stream content: text/event-stream: schema: type: string '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' /{topic}/raw: get: tags: - Subscribe summary: Subscribe to raw stream description: 'Subscribes to a topic and returns raw text messages, one per line. Only the message body is returned. No other fields are included. Keepalive messages are sent as empty lines. ' operationId: subscribeRaw security: - {} - BasicAuth: [] - BearerAuth: [] parameters: - name: topic in: path required: true description: Topic name or comma-separated list of topics schema: type: string pattern: ^[-_A-Za-z0-9]{1,64}(,[-_A-Za-z0-9]{1,64})*$ - $ref: '#/components/parameters/Poll' - $ref: '#/components/parameters/Since' - $ref: '#/components/parameters/Scheduled' responses: '200': description: Raw text stream content: text/plain: schema: type: string '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' /{topic}/ws: get: tags: - Subscribe summary: Subscribe via WebSocket description: 'Subscribes to a topic using WebSocket. Messages are sent as JSON objects. This is ideal for real-time applications. The connection supports bi-directional communication with ping/pong keepalive. ' operationId: subscribeWs security: - {} - BasicAuth: [] - BearerAuth: [] parameters: - name: topic in: path required: true description: Topic name or comma-separated list of topics schema: type: string pattern: ^[-_A-Za-z0-9]{1,64}(,[-_A-Za-z0-9]{1,64})*$ - $ref: '#/components/parameters/Poll' - $ref: '#/components/parameters/Since' - $ref: '#/components/parameters/Scheduled' - $ref: '#/components/parameters/FilterId' - $ref: '#/components/parameters/FilterMessage' - $ref: '#/components/parameters/FilterTitle' - $ref: '#/components/parameters/FilterPriority' - $ref: '#/components/parameters/FilterTags' responses: '101': description: WebSocket connection established content: application/json: schema: $ref: '#/components/schemas/Message' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' /{topic}/publish: get: tags: - Publish summary: Publish message (GET alias) description: Alias for publishing a message via GET request. Message parameters must be passed via headers. operationId: publishMessageGet security: - {} - BasicAuth: [] - BearerAuth: [] parameters: - name: topic in: path required: true description: Topic name schema: type: string pattern: ^[-_A-Za-z0-9]{1,64}$ - $ref: '#/components/parameters/XTitle' - $ref: '#/components/parameters/XPriority' - $ref: '#/components/parameters/XTags' - $ref: '#/components/parameters/XClick' - $ref: '#/components/parameters/XIcon' - $ref: '#/components/parameters/XAttach' - $ref: '#/components/parameters/XFilename' - $ref: '#/components/parameters/XActions' - $ref: '#/components/parameters/XEmail' - $ref: '#/components/parameters/XCall' - $ref: '#/components/parameters/XDelay' - $ref: '#/components/parameters/XCache' - $ref: '#/components/parameters/XFirebase' - $ref: '#/components/parameters/XMarkdown' - $ref: '#/components/parameters/XTemplate' - $ref: '#/components/parameters/XPollId' - $ref: '#/components/parameters/XUnifiedPush' - name: message in: query description: Message body (if not empty GET request) schema: type: string responses: '200': description: Message published successfully content: application/json: schema: $ref: '#/components/schemas/Message' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' /{topic}/send: get: tags: - Publish summary: Publish message (send alias) description: Alias for publishing a message via GET request operationId: publishMessageSend security: - {} - BasicAuth: [] - BearerAuth: [] parameters: - name: topic in: path required: true description: Topic name schema: type: string pattern: ^[-_A-Za-z0-9]{1,64}$ - $ref: '#/components/parameters/XTitle' - $ref: '#/components/parameters/XPriority' - $ref: '#/components/parameters/XTags' - $ref: '#/components/parameters/XClick' - $ref: '#/components/parameters/XIcon' - $ref: '#/components/parameters/XAttach' - $ref: '#/components/parameters/XFilename' - $ref: '#/components/parameters/XActions' - $ref: '#/components/parameters/XEmail' - $ref: '#/components/parameters/XCall' - $ref: '#/components/parameters/XDelay' - $ref: '#/components/parameters/XCache' - $ref: '#/components/parameters/XFirebase' - $ref: '#/components/parameters/XMarkdown' - $ref: '#/components/parameters/XTemplate' - $ref: '#/components/parameters/XPollId' - $ref: '#/components/parameters/XUnifiedPush' - name: message in: query description: Message body schema: type: string responses: '200': description: Message published successfully content: application/json: schema: $ref: '#/components/schemas/Message' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' /{topic}/trigger: get: tags: - Publish summary: Publish message (trigger alias) description: Alias for publishing a message via GET request operationId: publishMessageTrigger security: - {} - BasicAuth: [] - BearerAuth: [] parameters: - name: topic in: path required: true description: Topic name schema: type: string pattern: ^[-_A-Za-z0-9]{1,64}$ - $ref: '#/components/parameters/XTitle' - $ref: '#/components/parameters/XPriority' - $ref: '#/components/parameters/XTags' - $ref: '#/components/parameters/XClick' - $ref: '#/components/parameters/XIcon' - $ref: '#/components/parameters/XAttach' - $ref: '#/components/parameters/XFilename' - $ref: '#/components/parameters/XActions' - $ref: '#/components/parameters/XEmail' - $ref: '#/components/parameters/XCall' - $ref: '#/components/parameters/XDelay' - $ref: '#/components/parameters/XCache' - $ref: '#/components/parameters/XFirebase' - $ref: '#/components/parameters/XMarkdown' - $ref: '#/components/parameters/XTemplate' - $ref: '#/components/parameters/XPollId' - $ref: '#/components/parameters/XUnifiedPush' - name: message in: query description: Message body schema: type: string responses: '200': description: Message published successfully content: application/json: schema: $ref: '#/components/schemas/Message' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' /{topic}/auth: get: tags: - Subscribe summary: Check topic authentication description: Check if the client is authenticated to access the topic operationId: checkTopicAuth security: - BasicAuth: [] - BearerAuth: [] parameters: - name: topic in: path required: true description: Topic name or comma-separated list of topics schema: type: string pattern: ^[-_A-Za-z0-9]{1,64}(,[-_A-Za-z0-9]{1,64})*$ responses: '200': description: Authentication successful content: application/json: schema: type: object properties: success: type: boolean '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' /v1/health: get: tags: - Admin - **EXPERIMENTAL** summary: Health check description: Returns server health status operationId: healthCheck security: [] responses: '200': description: Server is healthy content: application/json: schema: type: object properties: healthy: type: boolean /v1/stats: get: tags: - Admin - **EXPERIMENTAL** summary: Server statistics description: Returns public server statistics operationId: getStats security: [] responses: '200': description: Statistics retrieved successfully content: application/json: schema: type: object properties: messages: type: integer description: Total number of messages messages_rate: type: number format: float description: Average messages per second /v1/tiers: get: tags: - Account - **EXPERIMENTAL** summary: List available tiers description: Returns list of available subscription tiers with pricing operationId: getTiers security: - {} - BearerAuth: [] responses: '200': description: Tiers retrieved successfully content: application/json: schema: type: array items: type: object properties: code: type: string name: type: string prices: type: object properties: month: type: integer description: Price in cents per month year: type: integer description: Price in cents per year limits: $ref: '#/components/schemas/AccountLimits' /v1/users: get: tags: - Admin - **EXPERIMENTAL** summary: List users description: Returns list of all users (admin only) operationId: listUsers security: - AdminAuth: [] responses: '200': description: Users retrieved successfully content: application/json: schema: type: array items: $ref: '#/components/schemas/UserInfo' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' post: tags: - Admin - **EXPERIMENTAL** summary: Create user description: Creates a new user (admin only) operationId: createUser security: - AdminAuth: [] requestBody: required: true content: application/json: schema: type: object required: - username properties: username: type: string password: type: string format: password tier: type: string role: type: string enum: - user - admin default: user responses: '200': description: User created successfully content: application/json: schema: $ref: '#/components/schemas/UserInfo' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' put: tags: - Admin - **EXPERIMENTAL** summary: Update user description: Updates an existing user (admin only) operationId: updateUser security: - AdminAuth: [] requestBody: required: true content: application/json: schema: type: object required: - username properties: username: type: string password: type: string format: password tier: type: string responses: '200': description: User updated successfully content: application/json: schema: $ref: '#/components/schemas/UserInfo' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' delete: tags: - Admin - **EXPERIMENTAL** summary: Delete user description: Deletes a user (admin only) operationId: deleteUser security: - AdminAuth: [] requestBody: required: true content: application/json: schema: type: object required: - username properties: username: type: string responses: '200': description: User deleted successfully '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /v1/users/access: put: tags: - Admin - **EXPERIMENTAL** summary: Grant user access to topic description: Grants a user access to a topic or topic pattern (admin only) operationId: grantAccess security: - AdminAuth: [] requestBody: required: true content: application/json: schema: type: object required: - username - topic - permission properties: username: type: string topic: type: string description: Topic name or pattern (supports wildcards) permission: type: string enum: - read - write - readwrite responses: '200': description: Access granted successfully '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' delete: tags: - Admin - **EXPERIMENTAL** summary: Reset user access to topic description: Resets user access to a topic (admin only) operationId: resetAccess security: - AdminAuth: [] requestBody: required: true content: application/json: schema: type: object required: - username - topic properties: username: type: string topic: type: string responses: '200': description: Access reset successfully '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' /v1/account: post: tags: - Account - **EXPERIMENTAL** summary: Create account description: Creates a new user account operationId: createAccount security: [] requestBody: required: true content: application/json: schema: type: object required: - username - password properties: username: type: string password: type: string format: password responses: '200': description: Account created successfully content: application/json: schema: $ref: '#/components/schemas/Account' '400': $ref: '#/components/responses/BadRequest' '409': description: Username already exists '429': $ref: '#/components/responses/TooManyRequests' get: tags: - Account - **EXPERIMENTAL** summary: Get account info description: Returns information about the authenticated user's account operationId: getAccount security: - BearerAuth: [] - BasicAuth: [] responses: '200': description: Account info retrieved successfully content: application/json: schema: $ref: '#/components/schemas/Account' '401': $ref: '#/components/responses/Unauthorized' delete: tags: - Account - **EXPERIMENTAL** summary: Delete account description: Deletes the authenticated user's account operationId: deleteAccount security: - BearerAuth: [] - BasicAuth: [] requestBody: required: true content: application/json: schema: type: object required: - password properties: password: type: string format: password responses: '200': description: Account deleted successfully '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' /v1/account/password: post: tags: - Account - **EXPERIMENTAL** summary: Change password description: Changes the authenticated user's password operationId: changePassword security: - BearerAuth: [] - BasicAuth: [] requestBody: required: true content: application/json: schema: type: object required: - password - new_password properties: password: type: string format: password description: Current password new_password: type: string format: password description: New password responses: '200': description: Password changed successfully '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' /v1/account/token: post: tags: - Account - **EXPERIMENTAL** summary: Create access token description: Creates a new API access token for the authenticated user operationId: createToken security: - BearerAuth: [] - BasicAuth: [] requestBody: content: application/json: schema: type: object properties: label: type: string description: Label for the token expires: type: integer description: Unix timestamp when token expires responses: '200': description: Token created successfully content: application/json: schema: $ref: '#/components/schemas/Token' '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' patch: tags: - Account - **EXPERIMENTAL** summary: Update access token description: Updates an existing access token operationId: updateToken security: - BearerAuth: [] - BasicAuth: [] requestBody: required: true content: application/json: schema: type: object required: - token properties: token: type: string description: Token to update label: type: string expires: type: integer format: int64 responses: '200': description: Token updated successfully content: application/json: schema: $ref: '#/components/schemas/Token' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' delete: tags: - Account - **EXPERIMENTAL** summary: Delete access token description: Deletes an access token operationId: deleteToken security: - BearerAuth: [] - BasicAuth: [] requestBody: required: true content: application/json: schema: type: object required: - token properties: token: type: string responses: '200': description: Token deleted successfully '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /v1/account/settings: patch: tags: - Account - **EXPERIMENTAL** summary: Update account settings description: Updates the authenticated user's account settings operationId: updateSettings security: - BearerAuth: [] - BasicAuth: [] requestBody: content: application/json: schema: type: object properties: language: type: string description: Preferred language code notification: type: object properties: sound: type: string min_priority: type: integer minimum: 1 maximum: 5 delete_after: type: integer responses: '200': description: Settings updated successfully '401': $ref: '#/components/responses/Unauthorized' /v1/account/subscription: post: tags: - Account - **EXPERIMENTAL** summary: Add topic subscription description: Subscribes to a topic operationId: addSubscription security: - BearerAuth: [] - BasicAuth: [] requestBody: required: true content: application/json: schema: type: object required: - topic properties: topic: type: string display_name: type: string responses: '200': description: Subscription added successfully '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' patch: tags: - Account - **EXPERIMENTAL** summary: Update topic subscription description: Updates a topic subscription operationId: updateSubscription security: - BearerAuth: [] - BasicAuth: [] requestBody: required: true content: application/json: schema: type: object required: - topic properties: topic: type: string display_name: type: string responses: '200': description: Subscription updated successfully '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' delete: tags: - Account - **EXPERIMENTAL** summary: Delete topic subscription description: Unsubscribes from a topic operationId: deleteSubscription security: - BearerAuth: [] - BasicAuth: [] requestBody: required: true content: application/json: schema: type: object required: - topic properties: topic: type: string responses: '200': description: Subscription deleted successfully '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /v1/account/reservation: post: tags: - Account - **EXPERIMENTAL** summary: Reserve topic description: Reserves a topic for exclusive use operationId: reserveTopic security: - BearerAuth: [] - BasicAuth: [] requestBody: required: true content: application/json: schema: type: object required: - topic properties: topic: type: string pattern: ^[-_A-Za-z0-9]{1,64}$ everyone: type: string enum: - read-write - read-only - deny default: deny description: Access level for other users responses: '200': description: Topic reserved successfully '401': $ref: '#/components/responses/Unauthorized' '409': description: Topic already reserved '429': $ref: '#/components/responses/TooManyRequests' /v1/account/reservation/{topic}: delete: tags: - Account - **EXPERIMENTAL** summary: Delete topic reservation description: Removes a topic reservation operationId: deleteReservation security: - BearerAuth: [] - BasicAuth: [] parameters: - name: topic in: path required: true description: Topic name schema: type: string pattern: ^[-_A-Za-z0-9]{1,64}$ responses: '200': description: Reservation deleted successfully '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /v1/account/phone: put: tags: - Account - **EXPERIMENTAL** summary: Add phone number description: Adds and verifies a phone number for voice call notifications operationId: addPhoneNumber security: - BearerAuth: [] - BasicAuth: [] requestBody: required: true content: application/json: schema: type: object required: - number - code properties: number: type: string pattern: ^\+\d{1,100}$ code: type: string description: Verification code received via SMS responses: '200': description: Phone number added successfully '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' delete: tags: - Account - **EXPERIMENTAL** summary: Delete phone number description: Removes a phone number operationId: deletePhoneNumber security: - BearerAuth: [] - BasicAuth: [] requestBody: required: true content: application/json: schema: type: object required: - number properties: number: type: string pattern: ^\+\d{1,100}$ responses: '200': description: Phone number removed successfully '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /v1/account/phone/verify: put: tags: - Account - **EXPERIMENTAL** summary: Request phone verification code description: Requests a verification code via SMS operationId: verifyPhoneNumber security: - BearerAuth: [] - BasicAuth: [] requestBody: required: true content: application/json: schema: type: object required: - number - channel properties: number: type: string pattern: ^\+\d{1,100}$ channel: type: string enum: - sms - call responses: '200': description: Verification code sent successfully '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' /v1/account/billing/portal: post: tags: - Account - **EXPERIMENTAL** summary: Create billing portal session description: Creates a Stripe billing portal session operationId: createBillingPortal security: - BearerAuth: [] - BasicAuth: [] responses: '200': description: Portal session created content: application/json: schema: type: object properties: redirect_url: type: string format: uri '401': $ref: '#/components/responses/Unauthorized' /v1/account/billing/subscription: post: tags: - Account - **EXPERIMENTAL** summary: Create subscription description: Creates a paid subscription via Stripe checkout operationId: createSubscription security: - BearerAuth: [] - BasicAuth: [] requestBody: content: application/json: schema: type: object properties: tier: type: string interval: type: string enum: - month - year responses: '200': description: Checkout session created content: application/json: schema: type: object properties: redirect_url: type: string format: uri '401': $ref: '#/components/responses/Unauthorized' put: tags: - Account - **EXPERIMENTAL** summary: Update subscription description: Modifies an existing subscription operationId: updateSubscription security: - BearerAuth: [] - BasicAuth: [] requestBody: content: application/json: schema: type: object properties: tier: type: string interval: type: string enum: - month - year responses: '200': description: Subscription updated successfully '401': $ref: '#/components/responses/Unauthorized' delete: tags: - Account - **EXPERIMENTAL** summary: Cancel subscription description: Cancels the paid subscription operationId: cancelSubscription security: - BearerAuth: [] - BasicAuth: [] responses: '200': description: Subscription cancelled successfully '401': $ref: '#/components/responses/Unauthorized' /v1/account/billing/subscription/success/{CHECKOUT_SESSION_ID}: get: tags: - Account - **EXPERIMENTAL** summary: Subscription checkout success description: Handles successful Stripe checkout redirect operationId: subscriptionCheckoutSuccess security: - BearerAuth: [] - BasicAuth: [] parameters: - name: CHECKOUT_SESSION_ID in: path required: true description: Stripe checkout session ID schema: type: string responses: '200': description: Checkout processed successfully '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /v1/account/billing/webhook: post: tags: - Account - **EXPERIMENTAL** summary: Stripe webhook handler description: Handles incoming webhooks from Stripe operationId: stripeWebhook security: [] requestBody: required: true content: application/json: schema: type: object responses: '200': description: Webhook processed successfully /v1/webpush: post: tags: - WebPush summary: Register Web Push subscription description: Registers a Web Push subscription for browser notifications operationId: registerWebPush security: - BearerAuth: [] - BasicAuth: [] requestBody: required: true content: application/json: schema: type: object required: - endpoint - auth - p256dh - topics properties: endpoint: type: string format: uri description: Push service endpoint URL auth: type: string description: Authentication secret p256dh: type: string description: P-256 ECDH key topics: type: array items: type: string description: List of topics to subscribe to responses: '200': description: Subscription registered successfully '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' delete: tags: - WebPush summary: Delete Web Push subscription description: Removes a Web Push subscription operationId: deleteWebPush security: - BearerAuth: [] - BasicAuth: [] requestBody: required: true content: application/json: schema: type: object required: - endpoint properties: endpoint: type: string format: uri responses: '200': description: Subscription deleted successfully '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /_matrix/push/v1/notify: get: tags: - Matrix summary: Matrix push gateway discovery description: Returns Matrix push gateway information operationId: matrixDiscovery security: [] responses: '200': description: Gateway info content: application/json: schema: type: object post: tags: - Matrix summary: Matrix push notification description: Receives push notifications from Matrix homeserver operationId: matrixPush security: [] requestBody: required: true content: application/json: schema: type: object properties: notification: type: object properties: devices: type: array items: type: object properties: pushkey: type: string pushkey_ts: type: integer data: type: object responses: '200': description: Notification processed successfully content: application/json: schema: type: object properties: rejected: type: array items: type: string description: List of rejected pushkeys /file/{messageId}: get: tags: - Publish summary: Download attachment description: Downloads a file attachment by message ID operationId: downloadAttachment security: [] parameters: - name: messageId in: path required: true description: Message ID schema: type: string pattern: ^[-_A-Za-z0-9]{12}$ responses: '200': description: File content content: application/octet-stream: schema: type: string format: binary image/*: schema: type: string format: binary '404': $ref: '#/components/responses/NotFound' head: tags: - Publish summary: Check attachment exists description: Checks if an attachment exists without downloading it operationId: headAttachment security: [] parameters: - name: messageId in: path required: true description: Message ID schema: type: string pattern: ^[-_A-Za-z0-9]{12}$ responses: '200': description: Attachment exists '404': $ref: '#/components/responses/NotFound' /metrics: get: tags: - Admin - **EXPERIMENTAL** summary: Prometheus metrics description: Returns Prometheus-compatible metrics operationId: getMetrics security: [] responses: '200': description: Metrics in Prometheus format content: text/plain: schema: type: string /: get: tags: - Subscribe summary: Web app root description: Returns the web application operationId: getRoot security: [] responses: '200': description: Web app HTML content: text/html: schema: type: string head: tags: - Subscribe summary: Server check description: Returns empty response to verify server is running operationId: headRoot security: [] responses: '200': description: Server is running /config.js: get: tags: - Subscribe summary: Web app configuration description: Returns JavaScript configuration for the web app operationId: getConfig security: [] responses: '200': description: Configuration JavaScript content: text/javascript: schema: type: string /manifest.webmanifest: get: tags: - Subscribe summary: Web app manifest description: Returns the Progressive Web App manifest operationId: getManifest security: [] responses: '200': description: Web app manifest content: application/manifest+json: schema: type: object components: securitySchemes: BasicAuth: type: http scheme: basic description: HTTP Basic Authentication using username and password BearerAuth: type: http scheme: bearer description: Bearer token authentication AdminAuth: type: http scheme: basic description: Admin-level authentication (requires admin role) parameters: XTitle: name: X-Title in: header description: Message title schema: type: string simple: value: Alert! with_url: value: Unauthorized access detected XPriority: name: X-Priority in: header description: 'Message priority level: - 1 (min): Low priority, may be hidden - 2: Low priority - 3: Default priority - 4: High priority - 5 (urgent/max): Urgent priority, bypasses quiet hours ' schema: type: integer enum: - 3 - 2 - 1 - 4 - 5 min: value: 1 urgent: value: 5 XTags: name: X-Tags in: header description: Comma-separated list of tags (may map to emojis) schema: type: string XClick: name: X-Click in: header description: URL to open when notification is clicked schema: type: string format: uri XIcon: name: X-Icon in: header description: URL to an image to use as notification icon schema: type: string format: uri XAttach: name: X-Attach in: header description: URL of a file to attach to the notification schema: type: string format: uri XFilename: name: X-Filename in: header description: Filename for the attachment schema: type: string XActions: name: X-Actions in: header description: 'Action buttons for the notification. Format: action,label,url[,clear=true] Actions: - view: Open URL - http: HTTP request - broadcast: Android broadcast intent Multiple actions separated by semicolon (;) ' schema: type: string XEmail: name: X-Email in: header description: Forward notification to email address schema: type: string format: email XCall: name: X-Call in: header description: 'Make phone call when notification is received. Set to "1" or "yes" to call verified phone number, or specify phone number in E.164 format (+1234567890) ' schema: type: string XDelay: name: X-Delay in: header description: 'Delay delivery of message. Supports: - Absolute timestamp: 2023-12-25 08:00:00 EST - Relative duration: 30m, 2h, 1d - Unix timestamp: 1703500800 ' schema: type: string XCache: name: X-Cache in: header description: 'Cache message for delayed subscribers (default: yes)' schema: type: string enum: - true - false - 1 - 0 XFirebase: name: X-Firebase in: header description: 'Forward to Firebase Cloud Messaging (default: yes)' schema: type: string enum: - true - false - 1 - 0 XMarkdown: name: X-Markdown in: header description: Render message as Markdown schema: type: string enum: - true - false - 1 - 0 XTemplate: name: X-Template in: header description: 'Template name from server templates directory, or "yes"/"true" for inline templating. When "yes", the message/title should be a Go template. ' schema: type: string XPollId: name: X-Poll-Id in: header description: 'Poll request ID. When set, this becomes a poll request message for UnifiedPush. The message body is ignored when this is set. ' schema: type: string XUnifiedPush: name: X-UnifiedPush in: header description: Enable UnifiedPush mode schema: type: string enum: - false - true - 1 - 0 - up Poll: name: poll in: query description: Return cached messages and close connection schema: type: boolean default: false Since: name: since in: query description: 'Return cached messages since: - Unix timestamp: 1635528757 - Duration: 10m, 30s, 1h - Message ID: nFS3knfcQ1xe - "all": All cached messages - "latest": Most recent message only - "none": No cached messages (default) ' schema: type: string enum: - all - latest - none default: none Scheduled: name: scheduled in: query description: Include scheduled/delayed messages in response schema: type: boolean default: false FilterId: name: id in: query description: Only return messages matching this exact message ID schema: type: string FilterMessage: name: message in: query description: Only return messages matching this exact message string schema: type: string FilterTitle: name: title in: query description: Only return messages matching this exact title string schema: type: string FilterPriority: name: priority in: query description: Only return messages matching any of these priorities (comma-separated) schema: type: string FilterTags: name: tags in: query description: Only return messages containing all these tags (comma-separated) schema: type: string responses: BadRequest: description: Bad request content: application/json: schema: $ref: '#/components/schemas/Error' error: invalid_request error_code: 40001 message: Invalid topic name Unauthorized: description: Authentication required or failed content: application/json: schema: $ref: '#/components/schemas/Error' error: unauthorized error_code: 40101 message: Invalid credentials Forbidden: description: Access denied content: application/json: schema: $ref: '#/components/schemas/Error' error: forbidden error_code: 40301 message: You do not have access to this topic NotFound: description: Resource not found content: application/json: schema: $ref: '#/components/schemas/Error' error: not_found error_code: 40401 message: User not found TooManyRequests: description: Rate limit exceeded content: application/json: schema: $ref: '#/components/schemas/Error' error: rate_limited error_code: 42901 message: Rate limit exceeded. Please try again later. schemas: Message: type: object description: A notification message required: - id - time - event - topic properties: id: type: string description: Random message identifier time: type: integer format: int64 description: Unix timestamp expires: type: integer format: int64 description: Unix timestamp when message expires (if cached) event: type: string enum: - open - keepalive - message - poll_request description: Message event type topic: type: string description: Topic name (or comma-separated list for open events) title: type: string description: Message title message: type: string description: Message body priority: type: integer minimum: 1 maximum: 5 description: Message priority (1=min, 5=max) tags: type: array items: type: string description: List of tags click: type: string format: uri description: URL to open on click icon: type: string format: uri description: Notification icon URL actions: type: array items: $ref: '#/components/schemas/Action' description: Action buttons attachment: $ref: '#/components/schemas/Attachment' content_type: type: string description: Content type (text/plain or text/markdown) encoding: type: string description: Message encoding (empty for UTF-8, or "base64") poll_id: type: string description: Poll request ID for UnifiedPush Action: type: object description: An action button required: - id - action - label properties: id: type: string description: Action identifier action: type: string enum: - view - http - broadcast description: Action type label: type: string description: Button label clear: type: boolean description: Clear notification after action url: type: string format: uri description: URL for view/http actions method: type: string description: HTTP method for http action default: POST headers: type: object additionalProperties: type: string description: HTTP headers for http action body: type: string description: HTTP body for http action intent: type: string description: Android intent for broadcast action extras: type: object additionalProperties: type: string description: Extra values for broadcast action Attachment: type: object description: A file attachment required: - name - url properties: name: type: string description: Filename type: type: string description: MIME type (if known) size: type: integer format: int64 description: File size in bytes expires: type: integer format: int64 description: Unix timestamp when attachment expires url: type: string format: uri description: Download URL PublishMessage: type: object description: Message for JSON publishing required: - topic properties: topic: type: string description: Topic name message: type: string description: Message body title: type: string description: Message title priority: type: integer minimum: 1 maximum: 5 description: Message priority tags: type: array items: type: string description: Tags click: type: string format: uri description: Click URL icon: type: string format: uri description: Icon URL attach: type: string format: uri description: Attachment URL filename: type: string description: Attachment filename actions: type: array items: $ref: '#/components/schemas/Action' description: Action buttons email: type: string format: email description: Forward to email call: type: string description: Phone call delay: type: string description: Delay delivery cache: type: string description: Cache message firebase: type: string description: Forward to Firebase markdown: type: boolean description: Render as Markdown Error: type: object description: Error response required: - error - error_code - message properties: error: type: string description: Error type error_code: type: integer description: ntfy error code message: type: string description: Human-readable error message Account: type: object description: User account information required: - username properties: username: type: string description: Username role: type: string enum: - user - admin description: User role sync_topic: type: string description: Account sync topic language: type: string description: Preferred language tier: $ref: '#/components/schemas/Tier' limits: $ref: '#/components/schemas/AccountLimits' stats: $ref: '#/components/schemas/AccountStats' subscriptions: type: array items: $ref: '#/components/schemas/Subscription' reservations: type: array items: $ref: '#/components/schemas/Reservation' tokens: type: array items: $ref: '#/components/schemas/Token' phone_numbers: type: array items: type: string pattern: ^\+\d{1,100}$ description: Verified phone numbers billing: $ref: '#/components/schemas/Billing' Tier: type: object description: Account tier properties: code: type: string description: Tier code name: type: string description: Tier name AccountLimits: type: object description: Account tier limits properties: basis: type: string enum: - ip - tier description: Limit basis messages: type: integer format: int64 description: Daily message limit messages_expiry_duration: type: integer format: int64 description: Message cache duration in seconds emails: type: integer format: int64 description: Daily email limit calls: type: integer format: int64 description: Daily call limit reservations: type: integer format: int64 description: Number of reserved topics allowed attachment_total_size: type: integer format: int64 description: Total attachment storage in bytes attachment_file_size: type: integer format: int64 description: Max attachment size in bytes attachment_expiry_duration: type: integer format: int64 description: Attachment retention duration in seconds attachment_bandwidth: type: integer format: int64 description: Daily attachment bandwidth limit in bytes AccountStats: type: object description: Account usage statistics properties: messages: type: integer format: int64 description: Messages sent today messages_remaining: type: integer format: int64 description: Messages remaining today emails: type: integer format: int64 description: Emails sent today emails_remaining: type: integer format: int64 description: Emails remaining today calls: type: integer format: int64 description: Calls made today calls_remaining: type: integer format: int64 description: Calls remaining today reservations: type: integer format: int64 description: Active reservations reservations_remaining: type: integer format: int64 description: Reservations remaining attachment_total_size: type: integer format: int64 description: Attachment storage used attachment_total_size_remaining: type: integer format: int64 description: Attachment storage remaining Subscription: type: object description: Topic subscription properties: topic: type: string description: Topic name display_name: type: string description: Display name Reservation: type: object description: Topic reservation properties: topic: type: string description: Reserved topic name everyone: type: string enum: - read-write - read-only - deny description: Access for other users Token: type: object description: API access token required: - token properties: token: type: string description: Token value label: type: string description: Token label last_access: type: integer format: int64 description: Last access timestamp last_origin: type: string description: Last access IP address expires: type: integer format: int64 description: Expiration timestamp provisioned: type: boolean description: Whether token was provisioned by server config Billing: type: object description: Billing information properties: customer: type: boolean description: Whether user is a Stripe customer subscription: type: boolean description: Whether user has active subscription status: type: string description: Subscription status interval: type: string enum: - month - year description: Billing interval paid_until: type: integer format: int64 description: Unix timestamp until paid cancel_at: type: integer format: int64 description: Unix timestamp when subscription cancels UserInfo: type: object description: User information (admin view) required: - username - role properties: username: type: string description: Username role: type: string enum: - user - admin description: User role tier: type: string description: Tier code grants: type: array items: type: object properties: topic: type: string description: Topic or pattern permission: type: string enum: - read - write - readwrite description: Permission level