Skip to content

notifier: emit Apprise-compatible body/title in webhook payload#888

Open
nathang21 wants to merge 1 commit into
vavallee:mainfrom
nathang21:apprise-webhook-body-v2
Open

notifier: emit Apprise-compatible body/title in webhook payload#888
nathang21 wants to merge 1 commit into
vavallee:mainfrom
nathang21:apprise-webhook-body-v2

Conversation

@nathang21
Copy link
Copy Markdown
Contributor

Problem

Webhook notifications can't reach an Apprise instance. Apprise's REST API requires a body field and rejects any payload without one:

HTTP 400 {"error": "Payload lacks minimum requirements"}

Bindery's payloads only carry event-specific keys (title, message, size, …) and never a body, so every POST to an Apprise /notify/<key> endpoint fails — even with BINDERY_NOTIFICATIONS_ALLOW_PRIVATE=1 set (this is separate from #870; the request does reach Apprise, it's just rejected on shape).

Reproduce

# Bindery's test payload → rejected
curl -X POST -H 'Content-Type: application/json' \
  -d '{"eventType":"test","message":"Bindery notification test"}' \
  http://apprise:8000/notify/<key>
# → HTTP 400 {"error": "Payload lacks minimum requirements"}

# Same payload + a "body" → accepted, notification delivered
curl -X POST -H 'Content-Type: application/json' \
  -d '{"eventType":"test","message":"Bindery notification test","title":"Bindery","body":"Bindery notification test"}' \
  http://apprise:8000/notify/<key>
# → HTTP 200

Apprise ignores the extra eventType/message keys, confirming the fix can be purely additive.

Change

In notifier.send(), enrich a copy of the payload before marshaling:

  • add body when absent — from message, falling back to title (covers grab/import which carry title, and test/health/failure which carry message);
  • default title to "Bindery" when absent.

This is additive — the original keys are preserved, so ntfy / Home Assistant / Discord-proxy consumers are unaffected. A copy is used because Send reuses one payload map across every configured notification.

Tests

TestSend_AppriseFields covers the three cases (title-only, message-only, explicit-body-preserved) and asserts the caller's original keys survive untouched. Existing notifier tests still pass.

If you'd prefer to gate this on a notification "type" (e.g. type == "apprise") rather than always emitting body/title, happy to adjust.

Apprise's REST API (apprise-api) requires a "body" field and rejects any
payload without one with HTTP 400 "Payload lacks minimum requirements".
Bindery's webhook payloads only carry event-specific keys (title, message,
size, ...), so pointing a notification at an Apprise /notify/<key> endpoint
always failed.

Enrich a copy of the payload in send() with "body" (from message, falling
back to title) and a default "title" of "Bindery" when absent. The change is
additive: original keys are preserved, so ntfy / Home Assistant / Discord
proxy consumers are unaffected. Copying avoids mutating the shared payload
map that Send reuses across notifications.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented May 31, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant