Plugin Development
Introduction
Section titled “Introduction”Apprise plugins, also called services, are Python classes that inherit from NotifyBase. The fastest way to build a new one is to start from a working plugin that resembles your target integration, then adapt its URL shape, parsing, and send logic.
This pattern is ideal for:
- Writing to a local destination (stdout, file, syslog)
- Prototyping a URL schema before adding networking
from .base import NotifyBasefrom ..common import NotifyTypefrom ..locale import gettext_lazy as _
class NotifyDemo(NotifyBase): service_name = _("Apprise Demo Notification") protocol = "demo" setup_url = "https://appriseit.com/services/demo/"
# Disable throttling for a purely local plugin request_rate_per_sec = 0
templates = ( "{schema}://", )
def url(self, *args, **kwargs): params = self.url_parameters(*args, **kwargs) return "{schema}://?{params}".format( schema=self.protocol, params=self.urlencode(params), )
def send(self, body, title="", notify_type=NotifyType.INFO, **kwargs): self.throttle() print(f"{notify_type} - {title} - {body}") return True
@staticmethod def parse_url(url): # demo:// has no host, so verify_host must be False return NotifyBase.parse_url(url, verify_host=False)This pattern is ideal for:
- Webhook-style integrations
- REST APIs with tokens and optional authentication
import jsonimport requests
from ..common import NotifyTypefrom ..url import PrivacyModefrom ..utils import parse_boolfrom ..locale import gettext_lazy as _from .base import NotifyBase
class NotifyDemoHTTP(NotifyBase): service_name = _("Apprise Demo Notification") protocol = "demo" secure_protocol = "demos" setup_url = "https://appriseit.com/services/demo/"
templates = ( "{schema}://{host}/{apikey}", "{schema}://{host}:{port}/{apikey}", "{schema}://{user}@{host}/{apikey}", "{schema}://{user}@{host}:{port}/{apikey}", "{schema}://{user}:{password}@{host}/{apikey}", "{schema}://{user}:{password}@{host}:{port}/{apikey}", )
template_tokens = dict( NotifyBase.template_tokens, **{ "host": { "name": _("Hostname"), "type": "string", "required": True, }, "port": { "name": _("Port"), "type": "int", "min": 1, "max": 65535, }, "user": { "name": _("Username"), "type": "string", }, "password": { "name": _("Password"), "type": "string", "private": True, }, "apikey": { "name": _("API Key"), "type": "string", "private": True, }, }, )
def __init__(self, apikey, **kwargs): super().__init__(**kwargs)
self.apikey = apikey if not self.apikey: raise TypeError(f"An invalid API key ({apikey}) was specified.")
@property def url_identifier(self): """A stable tuple used by url_id() and persistent storage.
It should uniquely identify the URL configuration so stored/cached data does not clobber different configurations.
Do not include: - targets (channels, recipients, endpoints) - most GET parameters, unless they fundamentally change upstream behaviour """ default_port = 443 if self.secure else 80 return ( self.secure_protocol if self.secure else self.protocol, self.user, self.password, self.host, self.port if self.port else default_port, str(self.apikey), )
def url(self, privacy=False, *args, **kwargs): params = self.url_parameters(privacy=privacy, *args, **kwargs)
auth = "" if self.user and self.password: auth = "{user}:{password}@".format( user=self.quote(self.user, safe=""), password=self.pprint( self.password, privacy, mode=PrivacyMode.Secret, safe="" ), ) elif self.user: auth = "{user}@".format(user=self.quote(self.user, safe=""))
default_port = 443 if self.secure else 80 schema = self.secure_protocol if self.secure else self.protocol port = ( "" if self.port is None or self.port == default_port else f":{self.port}" )
return "{schema}://{auth}{hostname}{port}/{apikey}?{params}".format( schema=schema, auth=auth, hostname=self.host, port=port, apikey=self.quote(self.apikey, safe=""), params=self.urlencode(params), )
def send(self, body, title="", notify_type=NotifyType.INFO, **kwargs): headers = { "User-Agent": self.app_id, "Content-Type": "application/json", "Authorization": f"Bearer {self.apikey}", }
payload = { "type": notify_type.value, "title": title, "body": body, }
self.throttle()
# prepare our port formatting port = f":{self.port}" if self.port else ""
try: r = requests.post( f"http://{self.host}{port}", data=json.dumps(payload), headers=headers, verify=self.verify_certificate, timeout=self.request_timeout, ) if r.status_code < 200 or r.status_code >= 300: return False
except requests.RequestException: return False
return True
@staticmethod def parse_url(url): results = NotifyBase.parse_url(url) if not results: return results
try: results["apikey"] = NotifyDemoHTTP.split_path(results["fullpath"])[0] except IndexError: results["apikey"] = None
return resultsCopy and paste this as a starting point. Search for TODO: and fill in the blanks.
## TODO: Rename this file and class.# TODO: Add unit tests and update documentation.#import refrom typing import Any
from ..common import NotifyTypefrom ..locale import gettext_lazy as _from ..url import PrivacyModefrom .base import NotifyBase
class NotifyMyService(NotifyBase): """TODO: One line summary of the service."""
# TODO: Update these 3 fields service_name = _("My Service") protocol = "myservice" secure_protocol = "myservices"
# TODO: Add a public service landing page when available service_url = "https://example.invalid/" setup_url = "https://appriseit.com/services/myservice/"
# TODO: Update with valid URL shapes users can type templates = ( "{schema}://{host}/{token}", "{schema}://{host}:{port}/{token}", "{schema}://{user}:{password}@{host}/{token}", "{schema}://{user}:{password}@{host}:{port}/{token}", )
# Tokens must map to __init__ arguments (directly or via map_to) template_tokens = dict(NotifyBase.template_tokens, **{ "token": { "name": _("Access Token"), "type": "string", "private": True, "required": True, # Optional validation, must be a 2-tuple: (pattern, flags) "regex": (r"^.+$", None), }, })
# Optional query string arguments. # If you define an argument here, it should be consumed in parse_url(). template_args = dict(NotifyBase.template_args, **{ "mode": { "name": _("Mode"), "type": "choice:string", "values": ("a", "b", "c"), "default": "a", }, "batch": { "name": _("Batch"), "type": "bool", "default": False, }, # Example alias, it must point to a real template_token or template_arg: "t": { "alias_of": "token", }, })
# Optional key/value injection patterns: # ?+Header=Value&-param=value&:extra=value template_kwargs = { "+": {"name": _("Header"), "prefix": "+"}, "-": {"name": _("GET Parameter"), "prefix": "-"}, ":": {"name": _("Payload Extra"), "prefix": ":"}, }
def __init__( self, token: str, mode: str | None = None, batch: bool | None = None, headers: dict[str, str] | None = None, params: dict[str, str] | None = None, payload: dict[str, str] | None = None, **kwargs: Any, ) -> None: super().__init__(**kwargs)
# TODO: Store required token(s) self.token = token if not self.token: raise TypeError(_("An invalid access token was specified."))
# TODO: Apply defaults using template_args where reasonable self.mode = ( self.template_args["mode"]["default"] if mode is None else str(mode).lower() ) if self.mode not in self.template_args["mode"]["values"]: raise TypeError(_("Invalid mode specified."))
self.batch = ( self.template_args["batch"]["default"] if batch is None else parse_bool(batch) )
# TODO: Store any custom key/value injections self.headers = headers or {} self.params = params or {} self.payload = payload or {}
def __len__(self) -> int: """Return how many targets this plugin will notify.
If you do not override this, the base implementation returns 1. """ # TODO: If you support targets, return len(self.targets) or 1 return 1
@property def url_identifier(self) -> tuple[Any, ...]: """Return a tuple that uniquely identifies this URL configuration.
This powers persistent storage, caching, and stable url_id() values. Do not include: - targets (channels, recipients, endpoints) - most GET parameters """ default_port = 443 if self.secure else 80 return ( self.secure_protocol if self.secure else self.protocol, self.user, self.password, self.host, self.port if self.port else default_port, self.token, )
def url(self, privacy: bool = False, *args: Any, **kwargs: Any) -> str: """Return a URL that can recreate the same object.""" params: dict[str, Any] = { "mode": self.mode, "batch": "yes" if self.batch else "no", }
# Add common URL parameters (format, overflow, emojis, store, tz, verify, rto, cto, etc.) params.update(self.url_parameters(privacy=privacy, *args, **kwargs))
# Add key/value injections (optional) params.update({f"+{k}": v for k, v in self.headers.items()}) params.update({f"-{k}": v for k, v in self.params.items()}) params.update({f":{k}": v for k, v in self.payload.items()})
auth = "" if self.user and self.password: auth = "{user}:{password}@".format( user=self.quote(self.user, safe=""), password=self.pprint( self.password, privacy, mode=PrivacyMode.Secret, safe="" ), ) elif self.user: auth = "{user}@".format(user=self.quote(self.user, safe=""))
default_port = 443 if self.secure else 80 schema = self.secure_protocol if self.secure else self.protocol port = ( "" if self.port is None or self.port == default_port else f":{self.port}" )
return "{schema}://{auth}{host}{port}/{token}?{params}".format( schema=schema, auth=auth, host=self.host, port=port, token=self.pprint(self.token, privacy, mode=PrivacyMode.Secret, safe=""), params=self.urlencode(params), )
def send( self, body: str, title: str = "", notify_type: NotifyType = NotifyType.INFO, **kwargs: Any, ) -> bool: """TODO: Implement the upstream call(s).""" self.throttle()
# TODO: Replace with real implementation self.logger.debug( "Sending %s notification to %s", notify_type, self.host ) return True
@staticmethod def parse_url(url: str) -> dict[str, Any] | None: """Parse a URL into __init__ arguments.
Guideline: - Every template_args entry should be extracted here - Return keys should match __init__ parameters """ results = NotifyBase.parse_url(url) if not results: return results
# token is the first path element try: results["token"] = NotifyMyService.split_path(results["fullpath"])[0] except IndexError: results["token"] = None
# Example: consume query string args qsd = results.get("qsd", {}) if "mode" in qsd: results["mode"] = NotifyMyService.unquote(qsd.get("mode"))
if "batch" in qsd: results["batch"] = parse_bool(qsd.get("batch"))
# We allow for 't=' as defined in our kwargs as a token # The general rule of thumb is kwargs trump everything - always # so even if a token is defined above, we'll over-ride it now if "t" in qsd: results["token"] = NotifyMyService.unquote(qsd.get("t"))
# Consume key/value injections, if you support them results["headers"] = { NotifyMyService.unquote(k): NotifyMyService.unquote(v) for k, v in results.get("qsd+", {}).items() } results["params"] = { NotifyMyService.unquote(k): NotifyMyService.unquote(v) for k, v in results.get("qsd-", {}).items() } results["payload"] = { NotifyMyService.unquote(k): NotifyMyService.unquote(v) for k, v in results.get("qsd:", {}).items() }
return resultsModel Overview
Section titled “Model Overview”URL Parsing
Section titled “URL Parsing”Apprise determines what the schema:// it has been provided and then launches the Notification Plugin’s YourPlugin.parse_url() call to do the rest.
Usually the first call made in your parse_url() function is to call the parent one (from NotifyBase). Doing so allows Apprise to extract further common URL parts such as schema, host, port, user, password, and fullpath. Your parse_url() should focus on the pieces that are specific to your service, then return a dict whose keys match your __init__() signature.
A key rule that the unit tests enforce is that your template metadata must map cleanly to __init__() arguments, either directly (same name) or through map_to.
Throttling, Verification, and Timeouts
Section titled “Throttling, Verification, and Timeouts”URLBase defines common SSL verification and socket timeouts as URL arguments:
verifycontrolsverify_certificatertocontrols the socket read timeoutctocontrols the socket connect timeout
url_identifier
Section titled “url_identifier”The url_identifier property exists to uniquely identify one configuration from another so cached or persistent data does not clobber different configurations. It is also how Apprise generates a consistent, stable unique id from a URL.
- Include scheme or protocol, credentials, and upstream connection identity.
- Exclude targets (channels, recipients, endpoints).
- Exclude most GET parameters. Only include a GET parameter if it fundamentally changes how the upstream communication works.
If two URLs describe the same effective configuration, they should generate the same url_identifier, and therefore the same url_id().
Also note the storage switch:
- If
store=nois set,url_id()returnsNone, andurl()should preservestore=noin its output.
Example:
@propertydef url_identifier(self): return ( self.secure_protocol if self.secure else self.protocol, self.user, self.password, self.host, self.port if self.port else (443 if self.secure else 80), )Persistent storage opt-in (storage_mode)
Section titled “Persistent storage opt-in (storage_mode)”If your plugin performs repeated upstream lookups (OAuth tokens, discovery calls, resolved identifiers, capability checks), you should consider enabling persistent storage. It will save you from doing the check down the road and make your plugin that much faster!
To opt in, set a class-level storage_mode:
from apprise.common import PersistentStoreMode
class NotifyMyService(NotifyBase): # ... storage_mode = PersistentStoreMode.AUTOGuidance:
- Use
PersistentStoreMode.AUTOfor most plugins. - Use
PersistentStoreMode.FLUSHonly when the cached data is expensive to recompute and you want stronger durability. - Leave the default behaviour (memory-only) if your plugin should never persist state, or if caching provides little benefit.
When combined with a well-formed url_identifier (configuration identity only), multiple instances targeting different recipients can reuse the same cache for the same upstream configuration.
Targets and __len__
Section titled “Targets and __len__”__len__() allows authors and tooling to identify how many targets are loaded into a plugin.
- If you do not override it, the base implementation returns
1. - Override it in plugins that support multiple targets, usually returning
len(self.targets)with a minimum of1.
Requirements and Optional Dependencies
Section titled “Requirements and Optional Dependencies”If your plugin needs extra packages, declare them in requirements so Apprise can report what is required or recommended.
from ..locale import gettext_lazy as _
requirements = { "details": _("This plugin requires cryptography for message signing."), "packages_required": ["cryptography>=42"], "packages_recommended": ["orjson>=3"],}Plugin Base Defaults
Section titled “Plugin Base Defaults”The following identifies the default values of variables defined in your plugin automatically if not otherwise overridden.
URLBase Defaults
Section titled “URLBase Defaults”NotifyBase inherits from the URLBase object which sets these defaults:
| Attribute | Default | Purpose | When To Override |
|---|---|---|---|
request_rate_per_sec | 0 | Base throttle interval (seconds). 0 disables throttling at the URLBase level. | Typically override at NotifyBase or your plugin, not at URLBase. |
socket_connect_timeout | 4.0 | Default connect timeout, used when cto is not provided. | If your service routinely needs longer TCP handshakes. |
socket_read_timeout | 4.0 | Default read timeout, used when rto is not provided. | If your service returns slowly or streams responses. |
verify_certificate | True | SSL certificate verification, used when verify is not provided. | Only if your service runs in controlled networks with self-signed certs and you are comfortable allowing verify=no. |
templates | () | Documentation templates. | Almost always, so tooling and docs can describe the plugin accurately. |
template_tokens | {} | Metadata describing URL path tokens. | Almost always, for non-trivial schemas. |
template_args | { verify, rto, cto } | Common URL args and their defaults. | Usually extend rather than replace. |
template_kwargs | {} | Metadata for prefixed key/value arguments. | If you support +headers, :payload, -params, etc. |
NotifyBase Defaults
Section titled “NotifyBase Defaults”Your plugin should be configured to inherit from NotifyBase granting you these defaults
| Attribute | Default | Purpose | When To Override |
|---|---|---|---|
enabled | True | If False, the plugin is not used. | Disable for platform-specific or dependency-specific reasons. |
category | "native" | Classifies plugin origin (native vs custom). | Usually leave as-is. |
requirements.details | None | Human-friendly requirements text. | If you need to explain optional or required packages. |
requirements.packages_required | [] | Required packages for full function. | If your plugin requires extra libraries. |
requirements.packages_recommended | [] | Optional packages that improve function. | If you can run without them, but benefit from them. |
service_url | None | Vendor or upstream product URL. | For public services, set this. |
setup_url | None | Apprise setup page for your service. | Set this to your appriseit.com/services/<service>/ page. |
request_rate_per_sec | 5.5 | Default throttle interval (seconds). | Tune for vendor rate limits, or set to 0 for local-only. |
image_size | None | Preferred image size, for attachment pre-scaling. | Set when your service expects a specific size. |
body_maxlen | 32768 | Max body characters before truncation. | Set based on upstream constraints. |
title_maxlen | 250 | Max title characters. Set 0 if titles are not supported. | Set to 0 for title-less endpoints, or tune to vendor constraints. |
body_max_line_count | 0 | Max number of lines to keep. 0 disables line truncation. | If upstream is line-sensitive. |
persistent_storage | True | Allows the persistent store to be used. | If your plugin must never store identifiers or state. |
storage_mode | memory | Default persistent store mode. | Rare, but can be tuned for special behaviours. |
timezone | None | Uses server-detected timezone when None. | If your service must always operate in a specific timezone. |
notify_format | text | Default message format. | If your service is Markdown or HTML-first. |
overflow_mode | upstream | Default overflow strategy. | If you want Apprise to split, truncate, or alter overflow behaviour. |
interpret_emojis | False | Emoji interpretation. | If the upstream service benefits from emoji conversion. |
attachment_support | False | Attachment enablement. | Set to True if you accept attachments. |
default_html_tag_id | "b" | Used to inject title into body for title-less services. | Rare, unless you want different formatting. |
Templates and Metadata
Section titled “Templates and Metadata”Template types
Section titled “Template types”Apprise validates types using a strict pattern: ((choice|list):)?(string|bool|int|float).
| Type | Where used | Meaning | Required directives | Notes |
|---|---|---|---|---|
string | tokens, args | A single string | none | Common for hostnames, tokens, and names. |
int | tokens, args | A single integer | none | Use min and max to bound port values, counts, etc. |
float | tokens, args | A single float | none | Use min and max for bounds. |
bool | tokens, args | A boolean flag | default (required for args) | Boolean args must provide a default. |
choice:string | tokens, args | One value from a fixed set | values | Choice entries must provide values, and default must be one of them if specified. |
choice:int | tokens, args | One integer from a fixed set | values | Use for mode selectors or enumerations. |
choice:float | tokens, args | One float from a fixed set | values | Rare, but supported. |
list:string | tokens, args | A list of strings | delim | List entries must provide delimiters. |
list:int | tokens, args | A list of integers | delim | Split and then coerce to int. |
list:float | tokens, args | A list of floats | delim | Split and then coerce to float. |
Additional rules that matter:
choice:boolis not allowed, useboolinstead.regexmust be a 2-tuple(pattern, option), and patterns must start with^and end with$. |- If
requiredorprivateare not provided, they default toFalse. - If
valuesis a dictionary, it is converted to a list of keys.
Template layout patterns
Section titled “Template layout patterns”These examples focus only on how template metadata, __init__(), and parse_url() connect.
No tokens are required when the templates do not include custom {token} entries.
class MyPlugin(NotifyBase): ## Plugin variables here (intentionally omitted)
secure_protocol = "foobar"
templates = ("{schema}://",)
def __init__(self, *args, **kwargs): # Rest of code here super().__init__(*args, **kwargs)If you only use built-in tokens like host, port, user, and password, you can omit template_tokens. Those tokens are already known to the framework.
class MyPlugin(NotifyBase): ## Plugin variables here (intentionally omitted)
secure_protocol = "foobar"
templates = ("{schema}://",)
def __init__(self, host, *args, **kwargs): # Rest of code here super().__init__(host=host, *args, **kwargs)If you define a template_token, template_arg, or template_kwarg, you should handle it in parse_url(), because the dict returned from parse_url() is used to initialize the class.
import re
from apprise.utils import parse_bool # example helper
class MyPlugin(NotifyBase): ## Plugin variables here (intentionally omitted)
secure_protocol = "foobar"
templates = ("{schema}://{token}",)
template_tokens = dict( NotifyBase.template_tokens, **{ "token": { "name": _("Auth Token"), "type": "string", "private": True, "required": True, "regex": (r"^[a-z0-9]+$", "i"), }, }, )
template_args = dict( NotifyBase.template_args, **{ "image": { "name": _("Include Image"), "type": "bool", "default": True, "map_to": "include_image", }, }, )
def __init__(self, host, token, include_image, *args, **kwargs): # Rest of code here super().__init__(host=host, *args, **kwargs)
@staticmethod def parse_url(url): results = NotifyBase.parse_url(url, verify_host=False)
# Token is in the host position in this example results["token"] = MyPlugin.unquote(results["host"])
results["include_image"] = parse_bool(results["qsd"].get( "image", MyPlugin.template_args['image']['default']))
return resultsMultiple token names can map to the same __init__() argument using map_to. Tests ensure all map_to values are valid __init__() arguments (or one of the framework-recognized keywords).
import re
from apprise.utils import parse_bool # example helper
class MyPlugin(NotifyBase): ## Plugin variables here (intentionally omitted)
secure_protocol = "foobar"
templates = ("{schema}://{targets}",)
template_tokens = dict( NotifyBase.template_tokens, **{ "target_user": { "name": _("Target User"), "type": "string", "map_to": "targets", }, "target_stream": { "name": _("Target Stream"), "type": "string", "map_to": "targets", }, "targets": { "name": _("Targets"), "type": "list:string", "delim": ("/",), }, }, )
template_args = dict( NotifyBase.template_args, **{ "to": { "alias_of": "targets", }, }, )
def __init__(self, targets, *args, **kwargs): # Rest of code here super().__init__(*args, **kwargs)
@staticmethod def parse_url(url): results = NotifyBase.parse_url(url, verify_host=False)
# Store our targets results["targets"] = [MyPlugin.unquote(results["host"])] results["targets"].extend(MyPlugin.split_path(results["fullpath"]))
# Support an alias that is easier to express in YAML if "to" in results["qsd"] and len(results["qsd"]["to"]): results["targets"] += list( filter( bool, re.split(r"[ \t\r\n,#\\/]+", MyPlugin.unquote(results["qsd"]["to"])), ) )
return resultsTemplate directives Reference
Section titled “Template directives Reference”The unit tests enforce allowed keys and type constraints.
| Directive | Where used | Meaning |
|---|---|---|
name | tokens, args, kwargs | Human-friendly label, usually wrapped in gettext_lazy(). |
type | tokens, args | Value type, validated by the strict type regex. |
required | tokens, args | Marks an entry as mandatory. If omitted, defaults to False. |
private | tokens, args | Marks an entry as sensitive. If omitted, defaults to False. |
default | args | Default used when the URL does not specify a value. Required for bool args. |
values | choice types | Allowed values for choice types, required for any choice:* type. |
min, max | int, float | Bounds for numeric types. |
regex | tokens, args | Validation regex, always (pattern, option) with ^...$ anchoring. |
delim | list types | Delimiters used for list splitting, required for list:* types. |
prefix | kwargs | Required for kwargs, must be one of :, +, or -. |
map_to | tokens, args, kwargs | Maps a key to a different __init__() argument name. Tests enforce it maps to a function argument (or a framework keyword). |
alias_of | args, kwargs | Declares an alias for an existing token or arg, often used to make YAML configuration easier. |
group | tokens | Used for grouping when multiple tokens map into a list-style entry. |
Framework-recognized map targets include common URL fields and shared arguments, even if they are not in your plugin __init__(), such as user, password, host, port, schema, fullpath, format, overflow, emojis, tz, verify, cto, rto, and store.
Mapping Rules
Section titled “Mapping Rules”Apprise uses your template metadata as a contract, and tests enforce consistency:
- Every item in
template_tokensmust map to a real__init__()argument, either directly (same key name) or usingmap_to. - Aliases (
alias_of) are allowed in args and kwargs, not in tokens. - Every
alias_ofmust point to a real token or arg, and cannot just point to itself unless it also exists in tokens. - For kwargs entries,
prefixis required, and must be one of:,+, or-.
Round-Trip Requirements
Section titled “Round-Trip Requirements”Two functions should work together:
parse_url()should extract every argument you expose throughtemplate_argsandtemplate_kwargs.url()should emit a URL that can recreate the same object, and should generate the sameurl_identifierwhen re-instantiated.
Template Schema Reference
Section titled “Template Schema Reference”This table documents the most common directives supported by template_tokens, template_args, and template_kwargs.
| Directive | Where used | Meaning |
|---|---|---|
name | tokens, args, kwargs | Human-friendly label, usually wrapped in gettext_lazy(). |
type | tokens, args | Value type, such as string, int, bool, choice:string, list:string. |
required | tokens, args | Marks an entry as mandatory for initialization or validation. |
default | args | Default used when the URL does not specify a value. Required for bool types. |
private | tokens, args | Marks a value as sensitive and should be hidden or masked in privacy views. |
regex | tokens, args | A 2-tuple (pattern, flags) used to validate values. Patterns should be anchored with ^ and $. |
values | choice types | Allowed values for choice:* types. If a default is provided, it must be in values. |
delim | list types | Allowed delimiters for list:* types. |
prefix | kwargs | Required for kwargs entries, defines injection prefix :, +, or -. |
map_to | tokens, args, kwargs | Maps the directive key to a different __init__() argument name. |
alias_of | args, kwargs | Provides an alternative name that behaves exactly like another token or argument. |
templates
Section titled “templates”- A tuple of URL patterns (strings) showing valid forms.
- Use
{schema}in templates, and keep tokens consistent across templates.
It is documentation and structured metadata that can be used by tooling to describe supported URL shapes.
template_tokens
Section titled “template_tokens”Variables taken from the URL core structure such:
schema://credentials/direction/?options= | | | variables here |template_args
Section titled “template_args”Args describe query string arguments. NotifyBase already provides format, overflow, emojis, store, and tz. URLBase already provides verify, rto, and cto.
Common patterns:
- Use
alias_ofto add synonyms. - Use
map_toto map user-facing arg names onto your__init__()parameter names. - Use a
defaultto clearly document behaviour.
template_kwargs
Section titled “template_kwargs”Kwargs are for prefixed arguments that can appear multiple times, typically used for key/value injection:
+is often used for headers-is often used for URL parameters:is often used for payload extras
Requirements And Optional Dependencies
Section titled “Requirements And Optional Dependencies”If your plugin needs extra packages, declare them in requirements so Apprise can report what is required or recommended.
Example:
from ..locale import gettext_lazy as _
requirements = { "details": _("This plugin requires cryptography for message signing."), "packages_required": ["cryptography>=42"], "packages_recommended": ["orjson>=3"],}Attachments, Format, and Overflow
Section titled “Attachments, Format, and Overflow”Plugins can opt into attachment support by setting attachment_support = True. If you enable this, be prepared for calls where body or title may be empty.
Also note that NotifyBase provides URL-level behaviour flags like format, overflow, emojis, and persistent storage (store).