Send a message, alert, or reminder in one HTTP call
One endpoint. One Bearer token. Messages reach humans in a real-time chat UI and on their phone via web push — from a server, website, CLI, cron job, or plugin.
https://pingwire.dev/api/v1/messages.php with an Authorization: Bearer <api_key> header and a JSON body like
{"channel":"deploys","text":"Build #123 passed"}. You get a 201 and the message appears instantly everywhere.
Quickstart — your first message in 30 seconds
Pick your language. Every example sends "Build #123 passed" to a channel called deploys (auto-created on first send).
curl -X POST https://pingwire.dev/api/v1/messages.php \
-H "Authorization: Bearer pw_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"channel":"deploys","text":"Build #123 passed","priority":"high"}'#!/usr/bin/env bash
PINGWIRE_KEY="pw_live_xxxxxxxxxxxxxxxxxxxxxxxx"
curl -sS -X POST https://pingwire.dev/api/v1/messages.php \
-H "Authorization: Bearer $PINGWIRE_KEY" \
-H "Content-Type: application/json" \
-d '{"channel":"deploys","text":"Build #123 passed"}'import requests
requests.post(
"https://pingwire.dev/api/v1/messages.php",
headers={"Authorization": "Bearer pw_live_xxxxxxxxxxxxxxxxxxxxxxxx"},
json={"channel": "deploys", "text": "Build #123 passed", "priority": "high"},
)await fetch("https://pingwire.dev/api/v1/messages.php", {
method: "POST",
headers: {
"Authorization": "Bearer pw_live_xxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
body: JSON.stringify({ channel: "deploys", text: "Build #123 passed" }),
});<?php
$ch = curl_init("https://pingwire.dev/api/v1/messages.php");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer pw_live_xxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode(["channel" => "deploys", "text" => "Build #123 passed"]),
]);
curl_exec($ch);The send endpoint
| POST | /api/v1/messages.php | Send a message (the core endpoint) |
| POST | /api/v1/notify.php | Identical alias for one-liners |
| GET | /api/v1/messages.php?channel=deploys | List recent messages (paginated) |
How do I send to a person instead of a channel?
Use to with a username or a conversation UUID instead of channel:
curl -X POST https://pingwire.dev/api/v1/messages.php \
-H "Authorization: Bearer pw_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{"to":"alice","text":"Your report is ready"}'# Whole request body becomes the message. Channel rides in the query string.
curl -X POST "https://pingwire.dev/api/v1/notify.php?channel=alerts" \
-H "Authorization: Bearer pw_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: text/plain" \
--data "Disk usage at 92% on web-01"Message fields
| Field | Type | Description |
|---|---|---|
channel | string | Target channel slug. Auto-created if new. Use this or to. |
to | string | Username or conversation UUID for a direct message. |
text | string | The message body. Up to 16 KB. |
title | string | Optional bold headline (great for alerts). |
priority | enum | min · low · default · high · urgent |
tags | string | Comma-separated labels, e.g. ci,rocket. |
url | string | Click-through URL shown as a button and opened from push. |
Priority levels
Priority controls how loudly a message arrives. urgent pushes with require-interaction so the notification stays until acknowledged.
min low default high urgent
Incoming webhooks — for GitHub, CI & monitors
Create a webhook for a channel in Account → Webhooks. Then POST JSON, form data, or raw text to its URL. No auth header needed — the token is the secret. Pingwire maps common fields (text, message, content, body, title) automatically.
curl -X POST https://pingwire.dev/hook/your_webhook_token \
-H "Content-Type: application/json" \
-d '{"title":"Deploy","text":"v1.2.3 shipped to prod","priority":"high"}'echo "Nightly backup complete" | \
curl -X POST https://pingwire.dev/hook/your_webhook_token \
-H "Content-Type: text/plain" --data-binary @-The pingwire CLI
Install once, then send from any shell, cron job, or pipeline.
# After deploy, symlink the wrapper:
chmod +x cli/pingwire
sudo ln -s /home/pingwire.dev/public_html/cli/pingwire /usr/local/bin/pingwire
# Configure (or set PINGWIRE_API_KEY in your env):
echo 'PINGWIRE_API_KEY=pw_live_xxxxxxxxxxxxxxxxxxxxxxxx' >> ~/.pingwirercpingwire send --channel deploys "Build #123 passed"
pingwire send --channel deploys < build.log # pipe stdin
pingwire send --to alice --title "FYI" "ping"
pingwire remind "+10 minutes" "stand up" --channel team
pingwire remind --cron "0 9 * * 1-5" --channel team "Standup"
pingwire channels
pingwire whoamiScheduled & recurring reminders
| POST | /api/v1/reminders.php | Create a one-off or recurring reminder |
| GET | /api/v1/reminders.php | List your reminders |
| DELETE | /api/v1/reminders.php?id=N | Cancel a reminder |
curl -X POST https://pingwire.dev/api/v1/reminders.php \
-H "Authorization: Bearer pw_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{"channel":"team","text":"Release window","run_at":"2026-06-01T15:00:00Z"}'curl -X POST https://pingwire.dev/api/v1/reminders.php \
-H "Authorization: Bearer pw_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{"channel":"team","text":"Standup","cron":"0 9 * * 1-5","timezone":"America/New_York"}'Requires a key with the schedule scope. Recurring schedules use standard cron expressions.
Ready-to-use recipes
GitHub Actions — notify on deploy
# .github/workflows/notify.yml
name: Notify Pingwire
on: [deployment_status]
jobs:
ping:
runs-on: ubuntu-latest
steps:
- name: Send Pingwire alert
run: |
curl -X POST https://pingwire.dev/hook/${{ secrets.PINGWIRE_HOOK }} \
-H "Content-Type: application/json" \
-d '{"title":"Deploy","text":"${{ github.repository }} deployed ${{ github.sha }}"}'Cron server alert — disk space watchdog
# Alert if root disk usage exceeds 90%. Runs every 5 minutes.
*/5 * * * * [ $(df / | awk 'NR==2{print +$5}') -gt 90 ] && \
pingwire send --channel alerts --priority urgent "Disk >90% on $(hostname)""Is my site up?" monitor
#!/usr/bin/env bash
URL="https://example.com"
if ! curl -fsS --max-time 10 "$URL" >/dev/null; then
curl -X POST https://pingwire.dev/api/v1/messages.php \
-H "Authorization: Bearer pw_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-d "{\"channel\":\"alerts\",\"title\":\"DOWN\",\"text\":\"$URL is unreachable\",\"priority\":\"urgent\"}"
fiMinimal WordPress plugin
<?php
/* Plugin Name: Pingwire Notifier */
add_action('publish_post', function ($id) {
$post = get_post($id);
wp_remote_post('https://pingwire.dev/api/v1/messages.php', [
'headers' => ['Authorization' => 'Bearer pw_live_xxxxxxxxxxxxxxxxxxxxxxxx', 'Content-Type' => 'application/json'],
'body' => wp_json_encode([
'channel' => 'blog',
'title' => 'New post published',
'text' => $post->post_title,
'url' => get_permalink($id),
]),
]);
});Scopes & rate limits
| Scope | Allows |
|---|---|
send | Send messages |
schedule | Create reminders |
read | List messages & channels, identify |
admin | Account-wide automation (admins only) |
- Sends: 120 requests/min per key.
- Webhooks: 60 requests/min per token.
- Reminders: 60 creates/min per key.
- Exceeding a limit returns
429with aRetry-Afterheader.
Errors
Errors are JSON with a stable error code and the right HTTP status.
| Status | Code | Meaning |
|---|---|---|
| 401 | invalid_api_key | Missing/invalid/revoked key |
| 403 | insufficient_scope | Key lacks the required scope |
| 402 | payment_required | The account needs Supporter Access — manage your plan at /account.php#plan |
| 403 | forbidden_channel | Not a member of the target channel |
| 404 | user_not_found | to doesn't match any username (human-readable detail included) |
| 422 | missing_target | No channel or to provided |
| 429 | rate_limited | Slow down — see Retry-After |
llms.txt documents this API for AI coding assistants too.