Skip to content

Integrations

Apprise API is meant to be a single notification gateway. Instead of building direct webhooks to Discord, Slack, email, and SMS in every project, send to Apprise API and let it route the message.

For stateful notifications (recommended for most integrations), you call one endpoint:

  • POST /notify/{KEY}

Where {KEY} identifies a configuration saved on the server. Your client code stays small and stable, while the Apprise API instance holds the actual notification URLs and any routing tags.

If you cannot (or do not want to) store configuration server-side, you can also use stateless notifications:

  • POST /notify

Stateless calls include the destination Apprise URLs in the request payload.

See the endpoint reference for the full list of supported paths.

Given:

  • scheme: http or https
  • host: the Apprise API hostname or IP
  • port: optional, omit for 80 (http) or 443 (https)
  • key: your saved configuration key

Construct:

  • BASE = {scheme}://{host}
  • If a non-default port is used: BASE = {scheme}://{host}:{port}
  • NOTIFY = {BASE}/notify/{key}

Apprise API accepts both form and JSON payloads in many cases. For integrations, JSON is usually easiest.

  • body (required): message content
  • title (optional): message title
  • type (optional): info (default), success, warning, or failure
  • format (optional): text (default), markdown, or html
  • tag (optional, stateful): route to a subset of saved URLs

Tags are only meaningful for stateful calls (/notify/{KEY}), because the server already knows which URLs belong to that key.

Tag matching logic:

  • Space, +, or & means AND (intersection)
  • Comma or | means OR (union)

Examples:

  • "devops,admin" notifies URLs tagged devops OR admin
  • "devops critical" notifies URLs tagged devops AND critical

To send attachments, use multipart/form-data.

  • Use attach (recommended) or attachment as the field name
  • The attachment value can be:
    • a local file upload
    • a remote URL that Apprise API downloads and forwards

If a third-party tool cannot change its JSON keys, Apprise API can map incoming fields to Apprise fields using query parameters.

Syntax:

  • ?:incoming_field=apprise_field

Example:

  • A tool sends {"message": "Server Down"}
  • Map it to Apprise body with ?:message=body

See the API usage documentation for more details.

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpRequest.BodyPublishers;
public class AppriseNotifyStateless {
public static void main(String[] args) {
String url = "http://localhost:8000/notify";
// JSON payload with multiple URLs
String jsonPayload = """
{
"urls": [
"discord://TOKEN/CHANNEL",
"mailto://user:pass@example.com"
],
"body": "Hello from Apprise (stateless)"
}
""";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Content-Type", "application/json")
.POST(BodyPublishers.ofString(jsonPayload))
.build();
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println)
.join();
}
}

Here is an example using attachments:

// Note: We construct a manual multipart body here for standard Java 11+
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.UUID;
public class AppriseAttachment {
public static void main(String[] args) throws IOException, InterruptedException {
String url = "http://localhost:8000/notify";
String boundary = "---Boundary" + UUID.randomUUID().toString();
Path file = Path.of("/path/to/file.txt");
// Comma-separated list of URLs
String targetUrls = "discord://TOKEN/CHANNEL,mailto://user:pass@example.com";
// Build Multipart Body
String body = "--" + boundary + "\r\n" +
"Content-Disposition: form-data; name=\"urls\"\r\n\r\n" +
targetUrls + "\r\n" +
"--" + boundary + "\r\n" +
"Content-Disposition: form-data; name=\"body\"\r\n\r\n" +
"Artifact attached (Stateless)\r\n" +
"--" + boundary + "\r\n" +
"Content-Disposition: form-data; name=\"attach\"; filename=\"" + file.getFileName() + "\"\r\n" +
"Content-Type: application/octet-stream\r\n\r\n" +
Files.readString(file) + "\r\n" +
"--" + boundary + "--";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Content-Type", "multipart/form-data; boundary=" + boundary)
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
client.send(request, HttpResponse.BodyHandlers.discarding());
}
}