Skip to main content

Registering a webhook

POST /api/v1/webhooks
Authorization: Bearer edp_live_<key>
Content-Type: application/json

{
  "url": "https://yourplatform.com/webhooks/edpire",
  "events": ["submission.graded", "assessment.published"]
}
The response includes a secretstore it securely. It is shown only once.

Signature verification

Every webhook delivery includes an X-Edpire-Signature header. Always verify it before processing:
import { createHmac, timingSafeEqual } from "crypto"

function verifySignature(
  rawBody: string,
  signature: string | null,
  secret: string
): boolean {
  if (!signature) return false
  const expected = `sha256=${createHmac("sha256", secret).update(rawBody).digest("hex")}`
  if (signature.length !== expected.length) return false
  return timingSafeEqual(Buffer.from(signature), Buffer.from(expected))
}

// Express example
app.post("/webhooks/edpire", express.raw({ type: "application/json" }), (req, res) => {
  const sig = req.headers["x-edpire-signature"] as string
  if (!verifySignature(req.body.toString(), sig, process.env.EDPIRE_WEBHOOK_SECRET!)) {
    return res.sendStatus(401)
  }
  res.sendStatus(200) // respond immediately
  const payload = JSON.parse(req.body.toString())
  // process event...
})

Available events

EventTriggered whenKey payload fields
submission.gradedLearner submits and assessment is gradedsubmission_id, assessment_id, learner_ref, score, max_score, percentage, passed, submitted_at, source
assessment.publishedAssessment published for the first timeassessment_id, share_code, title
assessment.content_updatedPublished assessment content is updated (republish or manual trigger)assessment_id, title
assessment.archivedAssessment archivedassessment_id
assessment.updatedAssessment title/description/settings changedassessment_id, title
collection.createdNew collection createdcollection_id, name
collection.updatedCollection name/description changedcollection_id, name
collection.deletedCollection deletedcollection_id
collection.item_addedAssessment added to a collectioncollection_id, assessment_id, assessment_title, share_code, position
collection.archivedCollection archivedcollection_id
collection.item_removedAssessment removed from a collectioncollection_id, assessment_id
collection.reorderedCollection items reorderedcollection_id, item_ids

Retry behavior

If your endpoint returns a non-2xx status, Edpire retries with exponential backoff:
AttemptDelay
1st retry1 minute
2nd retry5 minutes
3rd retry30 minutes
4th retry2 hours
5th retry8 hours
After 5 failed attempts, the delivery is abandoned and the webhook endpoint is marked as failing.

Best practices

Respond before processing. Move heavy logic to a background queue to avoid timeouts.
The same event can be delivered more than once. Always check whether you’ve already processed a given submission_id before writing to your database.
Log all incoming events for debugging. The X-Edpire-Event header tells you the event type without parsing the body.
New event types may be added in future versions. Ignore events you don’t recognize rather than erroring.