Troubleshooting
Solutions to the most common problems you'll encounter when using Orqestra.
"I triggered an event but nothing was delivered"
This is the most common issue. Events are accepted immediately with a 200 response, but delivery requires all three of the following to be true:
Checklist
1. Is a delivery provider configured?
Go to Admin UI → Providers. If the list is empty or no provider shows as active, that's the issue. Add a Resend or SendGrid API key for email. Without a provider, Orqestra accepts events but cannot dispatch them.
2. Does an active template exist for your event type?
Go to Admin UI → Templates. Find a template where:
- The event type exactly matches the
eventTypeyou sent (case-sensitive, e.g.order.confirmed≠Order.Confirmed) - The channel matches what you're expecting (EMAIL, SMS, or PUSH)
- The status is Active — inactive templates are silently ignored
3. Is the tenant's channel policy compatible?
Your tenant may have a delivery_channels whitelist. If it's set to ["EMAIL"] and you expected an SMS, the SMS was silently skipped. Check with your platform operator.
4. Is the sender_email set?
For email delivery, Orqestra needs a sender email address. This comes from either:
- Your configured provider (recommended — set in Admin UI → Providers), or
- The tenant's
sender_emailfield
If neither is set, the delivery is short-circuited to FAILED with the error: "No provider configured and no sender_email set on this tenant".
How to confirm
Check Admin UI → Logs. Every event creates a log entry. If you see:
- FAILED with an error message — read the error. It explains the exact cause.
- No entry at all — the event type didn't match any template. Go to Logs and check the audit trail.
- PENDING — the event is queued. If it stays PENDING for more than a minute, check that the Gateway service is running.
"I see no logs at all"
If there's no log entry even in the audit trail:
-
Did the API return a success response? If you got
401or422, the event was rejected before processing. Check your API key and request body. -
Is the Kafka consumer running? The Worker must be connected to Kafka to process events. Check the Worker service logs for Kafka connection errors.
-
Does the event type match any template exactly? If there's no matching template, an audit log entry is created (
notification.no_template_matched) but nonotification_logrow. Check Admin UI → Logs — look for audit entries, not just delivery logs. -
Is the Worker service healthy? Check your Docker / Kubernetes deployment for the
notifications-workercontainer.
"I got a 429 error"
Your tenant has hit its rate limit.
Response body:
{
"statusCode": 429,
"error": "Too Many Requests",
"message": "Rate limit exceeded for tenant YourApp. Limit: 100/min",
"retryAfter": 45
}
What to do:
- Read the
retryAfterfield (also in theRetry-Afterheader) — this is how many seconds to wait before retrying. - Implement exponential backoff in your application for
429responses. - If you regularly hit the limit, ask your platform operator to increase your tenant's
rate_limit_per_minute.
"Sandbox login says too many sessions"
The sandbox environment limits concurrent sessions per IP address to prevent abuse. If multiple people are logging in from the same network (e.g. same office WiFi or ISP), you may hit this limit.
What to do:
- Wait for an existing session to expire (sandbox sessions last 2 hours).
- Log out from another browser/device that's using the sandbox with the same account.
- Use a different network (mobile hotspot) to create a separate session.
- Each browser generates a unique device ID — logging in from different browsers on the same machine should work independently.
Technical note: Session limits are configurable via SANDBOX_MAX_CONCURRENT_SESSIONS_PER_IP and SANDBOX_MAX_DAILY_SESSIONS_PER_IP environment variables. Ask your platform operator to raise them if needed for team testing.
"My webhook signature is rejected (401)"
If you have a webhook secret configured and your requests are being rejected:
-
Compute the signature over the raw JSON body string — not over a parsed and re-serialized object. Key ordering in JSON serialization can vary.
-
Use HMAC-SHA256 and hex-encode the output — not base64.
-
Send it in the
X-Orqestra-Signatureheader (notAuthorization). -
Use the correct secret — the secret is set by your platform operator. It's different from your API key.
Test with Node.js:
import { createHmac } from 'crypto';
const body = JSON.stringify(yourPayload);
const sig = createHmac('sha256', process.env.ORQESTRA_WEBHOOK_SECRET!).update(body).digest('hex');
console.log(sig); // paste this into curl to verify
"Real-time notifications aren't appearing in my app"
Checklist
-
Is the frontend subscribed to the correct channels? The
/api/v1/auth/realtime-tokenendpoint returns the channel names. LogtokenResponse.channelsand verify you're subscribing to all of them. -
Is the Push template active? Go to Admin UI → Templates and confirm a template exists for your event type with channel = PUSH and status = Active.
-
Is the Centrifugo connection established? Add a connection event handler to confirm:
centrifuge.on('connected', (ctx) => console.log('Connected to Centrifugo:', ctx));
centrifuge.on('disconnected', (ctx) => console.warn('Disconnected:', ctx.reason));
-
Is the token expired? Tokens expire after 2 hours. Make sure you're refreshing the token using Centrifugo's
getTokencallback. -
Is the WebSocket URL correct? The URL should be
wss://your-orqestra-host/connection/websocket.
"Template variables show as {{variableName}} in the rendered output"
This means the variable wasn't found in the render context.
Causes:
- The field is in
payloadinstead ofvariables. Routing fields (userId,recipientEmail,recipientPhone) live inpayload. Everything your template references by name should be invariables. - The key name in the template doesn't match the key in
variables(case-sensitive:{{userName}}≠{{username}}). - The field exists in a nested object. Use dot notation:
{{order.customerName}}. - The field was omitted from the request entirely. Add it to
variablesin the call your application makes.
Use the Playground in the Admin UI to test template rendering with sample data before activating a template.
"My email looks broken in Outlook / Gmail"
Email clients are inconsistent with CSS. Use MJML for email templates — it compiles to table-based HTML that renders correctly across clients. Avoid writing raw HTML <div> layouts in email templates.
See Templates Guide → Email templates (MJML).
Still stuck?
Check the audit logs in Admin UI → Logs for detailed error messages. If the issue isn't covered here, consult the Architecture page to understand which component handles each step of delivery, which can help narrow down where the failure is occurring.