Stripe billing and Resend email are optional for self-hosted installs. Core deployment: DEPLOYMENT.md. Plan limits and ingest auth: ENTITLEMENTS.md.
Without email configured, admins must share invite or reset links manually. In production the API logs a startup warning and /health reports "email": "not_configured".
| Variable | Description |
|---|---|
RESEND_API_KEY |
API key from Resend |
TELEMETRY_EMAIL_FROM |
Sender address, e.g. Telemetry Tracker <info@telemetry-tracker.com> |
Both are required for outbound email. Verify your sending domain in Resend for production.
Optional for the marketing contact form (POST /api/contact):
| Variable | Description |
|---|---|
TELEMETRY_EMAIL_REPLY_TO |
Optional Reply-To for all outgoing mail (none to omit). Defaults to info@telemetry-tracker.com when TELEMETRY_DASHBOARD_ORIGIN is on telemetry-tracker.com, otherwise unset. The contact form always replies to the submitter. |
CONTACT_INBOX_EMAIL |
Inbox for form submissions (default info@telemetry-tracker.com) |
The contact form uses the same Resend credentials as password reset. Resend will reject sends when:
TELEMETRY_EMAIL_FROMusesonboarding@resend.devbut the recipient is not your Resend account email- the domain in
TELEMETRY_EMAIL_FROMis not verified in Resend → Domains
Check API logs for [email] Resend failed: for the exact rejection reason.
| Flow | Trigger | Notes |
|---|---|---|
| Organization invite | Team settings → invite by email | Requires TELEMETRY_DASHBOARD_ORIGIN for invite URL |
| Password reset | POST /api/auth/forgot-password |
Same origin requirement for reset link |
| Notification email | Billing alerts, quota thresholds, new error groups, team joins | Respects per-user notification preferences |
| Contact form | POST /api/contact |
Delivers to CONTACT_INBOX_EMAIL with replyTo set to submitter |
| Product updates | Footer subscribe, registration opt-in | Stored in MarketingSubscriber; see MARKETING-EMAIL.md |
Use this checklist for telemetry-tracker.com on Railway (API service only — dashboard does not need Resend vars).
- Sign in at resend.com.
- API Keys → Create key (e.g.
telemetry-tracker-production) with Sending access. - Copy the key (
re_…) — shown once.
The hosted cloud sends from tacko.io (operator domain). telemetry-tracker.com is the app URL, not the mail-from domain.
- Domains → Add domain →
tacko.io. - Add the DNS records Resend shows (typically SPF, DKIM, and optionally DMARC) at your DNS host for
tacko.io. - Wait until Resend shows the domain as Verified.
Recommended sender:
TELEMETRY_EMAIL_FROM=Telemetry Tracker <info@telemetry-tracker.com>
CONTACT_INBOX_EMAIL=info@telemetry-tracker.comYou can use another verified domain if you prefer; TELEMETRY_EMAIL_FROM must match it exactly.
On the API Railway service (not dashboard), set:
| Variable | Example |
|---|---|
RESEND_API_KEY |
re_… |
TELEMETRY_EMAIL_FROM |
Telemetry Tracker <info@telemetry-tracker.com> |
CONTACT_INBOX_EMAIL |
info@telemetry-tracker.com |
TELEMETRY_DASHBOARD_ORIGIN |
https://telemetry-tracker.com |
Redeploy the API after saving variables.
# Health should show email configured
curl -sS https://api.telemetry-tracker.com/health
# → {"ok":true,"database":"ok","email":"configured"}
# Contact form (expect 200 ok:true when Resend accepts)
curl -sS -X POST https://api.telemetry-tracker.com/api/contact \
-H 'Content-Type: application/json' \
-d '{"name":"Test","email":"you@example.com","topic":"general","message":"Resend production verification — please ignore."}'
# Password reset (always 200; check inbox for link)
curl -sS -X POST https://api.telemetry-tracker.com/api/auth/forgot-password \
-H 'Content-Type: application/json' \
-d '{"email":"your-account@example.com"}'Also send a team invite from Settings → Team and confirm the invitee receives mail.
If delivery fails, check Railway API logs for [email] Resend failed: and confirm domain verification in the Resend dashboard.
Set these on the API service to enable checkout, billing portal, and webhooks:
| Variable | Description |
|---|---|
STRIPE_SECRET_KEY |
sk_live_… or test key |
STRIPE_WEBHOOK_SECRET |
whsec_… for POST /webhooks/stripe |
STRIPE_PRICE_PRO |
Stripe Price id for Pro (EUR, list price €15/mo). New checkouts use this Price; existing subscribers keep their prior Price until they change plan. |
STRIPE_PRICE_BUSINESS |
Stripe Price id for Business (EUR, list price €99/mo) |
TELEMETRY_DASHBOARD_ORIGIN or DASHBOARD_ORIGIN |
Dashboard URL for checkout return links |
- Webhook endpoint:
https://<your-api>/webhooks/stripe - Subscribe to events:
checkout.session.completedcustomer.subscription.updatedcustomer.subscription.deleted- When affiliates are enabled (see AFFILIATES.md):
invoice.paid,charge.refunded,charge.dispute.created,charge.dispute.updated,charge.dispute.closed
- API version: pin the endpoint to
2025-03-31.basilor later (basil or dahlia). The API constructsnew Stripe(key)with noapiVersionpin, so outbound calls use stripe v22’s SDK default (dahlia). Webhook payload shape follows the Dashboard pin, not the SDK. Affiliate commission linking uses InvoicePayment /payment_intentbecause basil removedInvoice.chargeandCharge.invoice; classic pins still work. - Checkout metadata on completed sessions:
organization_id(UUID),plan_tier(PROorBUSINESS). - For subscription-only plan changes, put the same
plan_tieron Subscription or Price metadata socustomer.subscription.updatedcan sync tier.
Do not rely on invoice.payment_failed alone for subscription status — use customer.subscription.updated (Stripe retries while status may still be active).
Test with Stripe CLI or Dashboard Send test webhook after deploy.
- Resend domain verified (
tacko.ioor your sending domain) — see Resend production setup -
RESEND_API_KEYandTELEMETRY_EMAIL_FROMset on Railway API;/healthshows"email":"configured" - Test invite, password reset, and contact form delivery
- Stripe webhook URL reachable from the internet
- Webhook secret matches
STRIPE_WEBHOOK_SECRET - Test checkout completes and org tier updates
See PRODUCTION-READINESS.md for the full go-live list.