-
Notifications
You must be signed in to change notification settings - Fork 1
Home Assistant Integration
OpenMTG can push trade and wishlist price-alert events to Home Assistant, and let Home Assistant pull your live collection stats back, using per-user webhook credentials. An admin must enable the integration before anyone can use it as it is off by default.
Two independent directions, tied together by one credential:
- Push (OpenMTG -> Home Assistant): trade and wishlist-target events POST to a Home Assistant webhook URL you provide.
- Pull (Home Assistant -> OpenMTG): Home Assistant fetches your live collection stats from OpenMTG on its own schedule, authenticated with a bearer secret.
Each webhook credential you create pairs both: a generated inbound URL + secret (for pull), and a field for your own Home Assistant target URL (for push).
An admin must turn this on first in OpenMTG.
- Go to Admin > Settings > Feature Toggles.
- Toggle Home Assistant Integration on.
- Set Max webhook credentials per user (default 3).
When disabled: the Webhooks nav link is hidden for everyone, creating new credentials and sending test events is blocked, and the pull endpoint returns 503. Existing credentials stay visible and manageable.
Every OpenMTG user, including admins, manages their own credentials with no cross-user visibility.
- Go to Webhooks in the sidebar.
- Click New Credential.
- Give it a label (e.g. "Living Room HA").
- Optionally paste a Home Assistant webhook URL as the target URL. This URL is where push events go. Leave it blank for a pull-only credential.
- If that target URL is
https://with a self-signed certificate or an internal CA, check Skip TLS certificate verification. - Click Create.
A one-time modal shows the generated inbound URL and bearer secret. Copy both now as only a hash of the secret is stored, and can never be displayed again. If you lose it, regenerate a new one from the credential's row. This keeps the same inbound URL and only rotates the secret.
Every event POSTs JSON to the credential's target URL:
{
"event": "trade_accepted",
"timestamp": "2026-09-12T18:04:21.123Z",
"trade_id": 25,
"initiator": "tony",
"counterpart": "alice"
}| Event | Fires when | Extra fields |
|---|---|---|
trade_proposed |
A trade is proposed |
trade_id, initiator, counterpart
|
trade_updated |
Either side edits their offered items |
trade_id, initiator, counterpart
|
trade_engaged |
Trade moves from proposed to active (counterpart adds their first items) |
trade_id, initiator, counterpart
|
trade_accepted |
Both sides confirm and the transfer executes |
trade_id, initiator, counterpart
|
trade_rejected / trade_cancelled
|
Trade closed without completing |
trade_id, initiator, counterpart
|
wishlist_target_met |
A wishlisted card's live price drops to or below your target_price, checked right after a price refresh |
card_name, set_code, set_name, foil, target_price, current_price, currency
|
test |
You clicked Send Test Event on a credential | label |
Trade events can push to both participants' credentials, each trader can point their own credential at their own Home Assistant instance. Wishlist events push only to the entry owner.
wishlist_target_met fires once per crossing. It won't repeat on every refresh while the price stays at or below target, but it re-arms if the price rises back above target and later drops again, or if you edit the target price, foil flag, or swap the tracked card.
- In Home Assistant: Settings > Automations & Scenes > Create Automation.
- Add a trigger of type Webhook. Home Assistant generates a Webhook ID; the full URL is
http://<your-ha-host>:8123/api/webhook/<that-id>. - Paste that URL as the target URL on your OpenMTG credential.
- Add an action that uses the payload, e.g. a templated Persistent Notification:
action:
- action: persistent_notification.create
data:
title: "OpenMTG"
message: "{{ trigger.json.event }} - {{ trigger.json }}"- Save, then click Send Test Event on the OpenMTG credential to confirm it fires.
To branch on event type, use a choose: block with a condition: template checking trigger.json.event.
GET /api/webhook/<username>/<webhook_id>/stats
Authorization: Bearer <secret>
Returns the same JSON shape as the in-app Stats page (summary, rarity, colors, color_identity_pct, types, conditions, top_cards, top_sets) for whichever user owns the credential. Rate-limited to 30 requests/minute per IP address.
Add it as a Home Assistant REST sensor in configuration.yaml:
rest:
- resource: "http://<your-openmtg-host>:8080/api/webhook/<username>/<webhook_id>/stats"
headers:
Authorization: "Bearer <secret>"
scan_interval: 300
sensor:
- name: "OpenMTG Total Value"
value_template: "{{ value_json.summary.total_value }}"
- name: "OpenMTG Total Cards"
value_template: "{{ value_json.summary.total_cards }}"Reload with Developer Tools > YAML > Reload REST (no full restart needed), then check Developer Tools > States for the new sensors. This is a separate config surface from the Lovelace dashboard The rest: block only creates the entities, dashboard cards reference them by entity id afterward.
REST sensors poll on scan_interval. See the dashboard example below for a manual refresh button using homeassistant.update_entity.
Each credential has its own verify_tls flag, on by default. If the Home Assistant target URL is https:// with a certificate that isn't from a public CA (self-signed, or issued by an internal/private CA such as a reverse proxy's own root), OpenMTG's outbound push fails with a certificate verification error:
[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate
Fix it by toggling Skip TLS certificate verification either at credential creation or afterward via the shield icon next to the credential in the Webhooks list. Credentials without verification show a red Insecure badge next to their target URL as a standing reminder.
Only disable this for a URL on your own trusted network. It has no effect on the pull direction, Home Assistant calling into OpenMTG is authenticated by the bearer secret regardless of TLS settings on either side.
From the Webhooks page, each credential row supports:
| Action | Effect |
|---|---|
| Send test event | Fires a test event to the target URL, if one is set |
| Shield icon | Toggles TLS verification for that credential |
| Enable/disable toggle | Disabling stops all push and pull traffic for that credential without deleting it |
| Regenerate secret | Issues a new secret (shown once), keeps the same inbound URL |
| Delete | Permanently removes the credential, any Home Assistant automation or sensor using it stops working |
Trade notifier
- Create a Text helper: Settings > Devices & Services > Helpers > Create Helper > Text, named
OpenMTG Last Trade(input_text.openmtg_last_trade). - In the webhook automation, branch on event type and populate it:
action:
- choose:
- conditions:
- condition: template
value_template: "{{ trigger.json.event.startswith('trade_') }}"
sequence:
- action: input_text.set_value
target:
entity_id: input_text.openmtg_last_trade
data:
value: >-
{{ trigger.json.event }}: {{ trigger.json.initiator }} ↔ {{ trigger.json.counterpart }}
- action: persistent_notification.create
data:
title: "OpenMTG Trade Update"
message: "{{ trigger.json.event }} — {{ trigger.json.initiator }} ↔ {{ trigger.json.counterpart }}"
notification_id: "openmtg_trade_{{ trigger.json.trade_id }}"Reusing notification_id keyed on trade_id means a trade's later events (updated, engaged, accepted) replace the same notification instead of piling up separate ones.
- Add a dashboard card:
type: tile
entity: input_text.openmtg_last_trade
name: Latest OpenMTG TradeStats card with manual refresh
type: vertical-stack
cards:
- type: tile
entity: sensor.openmtg_total_cards
name: Total Cards
- type: tile
entity: sensor.openmtg_total_value
name: Total Value
- type: button
name: Refresh Stats
icon: mdi:refresh
tap_action:
action: perform-action
perform_action: homeassistant.update_entity
target:
entity_id:
- sensor.openmtg_total_cards
- sensor.openmtg_total_valueAdd either card via Edit Dashboard > Add Card > Manual (paste the YAML directly), or the dashboard's raw YAML editor. If you're on one of Home Assistant's default auto-generated dashboards, you may need Take Control first (dashboard's three-dot menu) before cards can be added.
For a true "refresh the instant the dashboard loads" behavior with no tap needed, you'd need the third-party browser_mod integration (via HACS), not required for anything above.
-
SSL: CERTIFICATE_VERIFY_FAILED, "unable to get local issuer certificate" - your target URL uses a self-signed or internally-issued certificate. Enable Skip TLS certificate verification on that credential. -
curl or the REST sensor returns
404: Not Found- double-check the host and port./api/webhook/...exists on OpenMTG, not Home Assistant. It's an easy mistake to point the pull request at your Home Assistant instance's own address (e.g.:8123) instead of OpenMTG's (:8080by default). -
Sensor state is
unknown- the REST fetch likely succeeded but the response didn't have the field thevalue_templateexpects. Curl the same URL directly to see the raw JSON. A bare{}response means that user's collection is empty (same as the in-app Stats page showing "No collection data yet") - thesummarykey only appears once there's at least one card. -
401 Unauthorizedfrom the pull endpoint - the bearer secret is wrong or was regenerated since the sensor was configured. Update theAuthorizationheader with the current secret. -
503from the pull endpoint - an admin has disabled the integration. - Push event never arrives in Home Assistant - confirm the credential is enabled, has a target URL set, and that the automation's webhook trigger URL matches exactly. Use Send Test Event to isolate whether the problem is OpenMTG-side or the automation itself.
| Method | Path | Description |
|---|---|---|
GET |
/webhooks/status |
Public, integration enabled status and per-user credential cap |
GET |
/webhooks |
List your own credentials |
POST |
/webhooks |
Create a credential, response includes the secret and inbound URL once |
PATCH |
/webhooks/{id} |
Update label, target URL, enabled, or verify_tls |
DELETE |
/webhooks/{id} |
Remove a credential |
POST |
/webhooks/{id}/regenerate-secret |
Rotate the secret, keeps the same inbound URL |
POST |
/webhooks/{id}/test |
Send a test push event |
GET |
/api/webhook/{username}/{webhook_id}/stats |
Pull endpoint, bearer-authenticated, not a normal session endpoint |
All /webhooks/* endpoints except /webhooks/status require a normal login session and are scoped to the current user. The pull endpoint uses the credential's bearer secret instead and ignores session auth entirely.