Production-grade Pretix payment-provider plugin that lets event organisers accept crypto payments through NodeRails.
The plugin talks to NodeRails Checkout Sessions, embeds the NodeRails hosted checkout in an iframe on Pretix's order-confirm screen, and uses the NodeRails native refund API to settle refunds on-chain.
- The customer picks "Pay with crypto" on the Pretix payment-method step.
- The plugin calls
POST /checkout-sessionson the NodeRails API and stashes the returnedsessionIdin the user's session. - On the order-confirm screen the plugin embeds an iframe pointing at
${PAYMENT_UI_URL}/checkout/${sessionId}and starts pollingGET /checkout-sessions/public/${sessionId}every 3 s. It also listens forpostMessageevents from the iframe to react instantly. - When the customer's payment is detected, Pretix's "Place order" button is
enabled. On click,
execute_paymentre-verifies the session server-side. - NodeRails sends
payment.authorized/payment.capturedwebhooks to/<organizer>/<event>/noderails/webhook/. The plugin verifies the HMAC signature, finds the matchingOrderPayment, and confirms it. This is idempotent and fires even if the customer closes the browser. - Refunds: organisers click Pretix's normal refund button → plugin calls
POST /payments/intents/{id}/refund→ NodeRails settles the refund on-chain →payment.refundedwebhook flips theOrderRefundto done.
- Install the plugin into your Pretix instance:
pip install pretix-noderails # or, from a checkout pip install -e .
- Restart Pretix.
- In the Pretix backend, open your event → Settings → Plugins → enable NodeRails Payments.
- Open Settings → Payment → expand Pay with crypto and fill in:
- NodeRails App ID (live) — from the NodeRails dashboard
- NodeRails API Secret Key (live) — must include
PAYMENTS_VIEWandREFUNDS_MANAGEpermissions - Webhook signing secret (live) — created and shown once when you register the webhook in the NodeRails dashboard
- Optional
*_testequivalents for when the event is in test mode
- In the NodeRails dashboard register a webhook:
- URL:
https://YOUR-PRETIX/<organizer>/<event>/noderails/webhook/ - Events:
payment.authorized,payment.captured,payment.refunded - Copy the secret into the Webhook signing secret field above.
- URL:
- Save. The provider is now live.
| Setting | Required | Notes |
|---|---|---|
api_base_url |
yes | Defaults to https://api.noderails.com |
payment_ui_url |
yes | Origin embedded in the checkout iframe |
app_id |
yes | Live NodeRails App UUID |
api_key |
yes | Live secret API key |
webhook_secret |
yes | Live HMAC secret |
app_id_test |
no | Used when event.testmode is true |
api_key_test |
no | " |
webhook_secret_test |
no | " |
currency |
yes | ISO currency, default USD |
- Webhook signing. Every inbound webhook is verified with HMAC-SHA256
over
${timestamp}.${rawBody}using the per-event signing secret. Replays more than 5 minutes old are rejected. - Idempotency. Webhook redeliveries (NodeRails sends 3× by design) are
no-ops once an
OrderPaymentis already confirmed. We also keyIdempotency-Keyon outbound checkout-session and refund calls. - CSP. The plugin merges
frame-src/img-src/connect-srcentries for the configured NodeRails origins on customer-facing responses, leaving the rest of Pretix's CSP intact. - Timeouts. All external calls use a 10 s timeout so a slow upstream cannot wedge a Pretix worker.
Tests cover the security-critical units (HMAC verify, replay window, HTTP shaping, payload extractors) without needing a full Pretix dev stack:
python3 -m venv .venv && source .venv/bin/activate
pip install -e .[test]
pytest -vEnd-to-end testing should be done in a real Pretix dev instance with the plugin installed in editable mode and a NodeRails staging app.
pretix_noderails/
apps.py — Django AppConfig + PretixPluginMeta
signals.py — register provider + CSP merge
payment.py — NodeRailsPay(BasePaymentProvider)
client.py — REST client (10 s timeout, idempotency)
webhook.py — HMAC signature compute + verify
views.py — webhook receiver + status-refresh
urls.py — event-scoped URL patterns
templates/... — confirm iframe, control panels, error/pending pages
tests/ — pytest unit tests
The hosted checkout at ${PAYMENT_UI_URL}/checkout/{sessionId}:
-
Sends
Content-Security-Policy: frame-ancestors *so it can be embedded from arbitrary merchant origins. -
Posts the following messages to
window.parentfor instant in-iframe feedback (the plugin listens for these intemplates/pretix_noderails/checkout_payment_confirm.html):{ type: 'noderails:checkout-complete', sessionId, intentId, status } { type: 'noderails:checkout-failed', sessionId, intentId, status }
-
The
payment.authorizedandpayment.refundedwebhooks include bothpaymentIntentIdandcheckoutSessionIdfor matching back to the PretixOrderPayment/OrderRefund.
Apache-2.0 — see LICENSE.