Embeds & webhooks (Pro)
Both halves of the ERP/IMS story: the embed puts the test player inside your site, the webhook pushes results back to your server. No polling, no iframes-of-dashboards.
Embedding a test
<script src="https://siddhixsys.com/embed-test.js" data-test="TESTCODE" async></script>- Replace
TESTCODEwith the code from the test's share panel. - The player renders where the tag sits and auto-resizes its height.
- Optional
data-min-height="600". - Students sign in inside the frame exactly as they would on the direct link — personal links (
?c=codes) also work embedded. - Requires the organizer to have an active Pro plan; otherwise the frame shows an "open in full window" card.
- Heavy-proctored tests always open in their own window (fullscreen and camera cannot be enforced inside an iframe — we refuse rather than pretend).
Webhooks
Add endpoints in Agents & API → Webhooks. We POST JSON:
attempt.submitted— a student finished (or time expired).attempt.stateisevaluated(final score) orsubmitted(written answers pending).result.published— you published results; the payload carries every published row:{name, email, phone, score, max_score}.ping— the "Send test ping" button.
{
"event": "attempt.submitted",
"created_at": "2026-08-04T12:00:00.000Z",
"test": { "id": 12, "code": "aB3xY9zQ", "title": "Weekly test 4" },
"taker": { "name": "Asha", "email": "asha@example.com", "phone": null, "source": "roster" },
"attempt": { "id": 88, "state": "evaluated", "score": 42, "max_score": 60,
"submitted_at": "2026-08-04T11:59:31.000Z", "auto_submitted": false }
}Verifying the signature
Every delivery carries X-Amatya-Signature: t=<unix seconds>,v1=<hex> where v1 = HMAC-SHA256(secret, ${t}.${rawBody}):
const crypto = require('node:crypto');
function verify(header, rawBody, secret) {
const { t, v1 } = Object.fromEntries(header.split(',').map(p => p.split('=')));
const expect = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
const fresh = Math.abs(Date.now() / 1000 - Number(t)) < 300; // 5-minute window
return fresh && crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expect));
}Delivery rules
- Respond 2xx within 10 seconds; anything else counts as a failure.
- Retries: 6 attempts with growing backoff (1m → 5m → 30m → 2h → 12h).
- After 12 consecutively failed deliveries the webhook pauses itself — resume it from the panel once your endpoint is fixed.
- Endpoints must be public https — private/internal addresses are rejected at creation AND re-checked at every delivery.
- Redirects are not followed.
The same webhook fires for every test you run — filter on test.id or test.code in your handler.