Webhooks

Receive real-time notifications when events happen in your account.

Overview

Webhooks allow your application to receive real-time HTTP notifications when events occur, such as when an evaluation completes. Instead of polling the API, you register a URL and we'll send events to it.

Supported Events

EventDescription
evaluation.completedAn evaluation has been graded successfully
evaluation.failedAn evaluation failed to process
assessment.deployedReserved for future assessment deployment events
assessment.submittedReserved for future assessment submission events
course.deployedA course has been deployed
course.completedA course generation has completed
lti.launch_completedAn LTI launch flow completed successfully
lti.launch_failedAn LTI launch flow failed
lti.grade_syncedA grade was successfully synced to the LMS
lti.grade_sync_failedGrade sync to the LMS failed after all retries

Webhook Payload

{
  "evaluationId": "2f4ad455-1e8e-4b6c-9f3a-7ebf4cf6f483",
  "status": "COMPLETED",
  "evaluationType": "open_ended",
  "score": 8,
  "maxScore": 10,
  "normalizedScore": 80
}

Signature Verification

Every webhook request includes these headers:

  • X-Platform-Signature
  • X-Platform-Event

The signature is computed as HMAC_SHA256(payload, secret) where secret is the value returned when you created the webhook endpoint. Verify against the raw request body.

const crypto = require('crypto');
 
function verifyWebhook(payload, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
 
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

Retry Policy

If your endpoint returns a non-2xx status code, we retry with exponential backoff:

AttemptDelay
1st retry5 seconds
2nd retry25 seconds
3rd retry125 seconds

After the initial delivery attempt plus 3 retries (4 total attempts), the delivery is marked as failed.

Managing Webhook Endpoints

Use the management endpoints below to create, list, and delete webhook subscriptions.

These are internal management endpoints authenticated via TutorFlow admin auth, not via Platform API keys. For dashboard-level webhook management, use the Dashboard API endpoints.

Create a Webhook Endpoint

POST /v1/platform/webhooks
ParameterTypeRequiredDescription
urlstringYesThe HTTPS URL that will receive webhook events
eventsstring[]YesList of event types to subscribe to
secretstringNoA shared secret for HMAC signature verification. Auto-generated if omitted.
curl -X POST https://api.tutorflow.io/v1/platform/webhooks \
  -H "Authorization: Bearer tf_platform_..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://myapp.com/webhooks/tutorflow",
    "events": ["evaluation.completed", "evaluation.failed"]
  }'

Response:

{
  "id": "wh_abc123",
  "url": "https://myapp.com/webhooks/tutorflow",
  "events": ["evaluation.completed", "evaluation.failed"],
  "secret": "whsec_...",
  "createdAt": "2026-03-19T10:00:00Z"
}

Store the secret value securely. It is only returned once at creation time and is used for signature verification.

List Webhook Endpoints

GET /v1/platform/webhooks

Returns all webhook endpoints registered for your workspace.

curl https://api.tutorflow.io/v1/platform/webhooks \
  -H "Authorization: Bearer tf_platform_..."

Response:

[
  {
    "id": "wh_abc123",
    "platformWorkspaceId": "workspace-uuid",
    "url": "https://myapp.com/webhooks/tutorflow",
    "events": ["evaluation.completed", "evaluation.failed"],
    "status": "active",
    "createdAt": "2026-03-19T10:00:00Z",
    "updatedAt": "2026-03-19T10:00:00Z"
  }
]

Delete a Webhook Endpoint

DELETE /v1/platform/webhooks/:id
ParameterTypeDescription
idstringThe webhook endpoint ID
curl -X DELETE https://api.tutorflow.io/v1/platform/webhooks/wh_abc123 \
  -H "Authorization: Bearer tf_platform_..."

Returns 204 No Content on success.

Best Practices

  • Always verify the HMAC signature before processing.
  • Return 200 OK quickly and process the event asynchronously.
  • Handle duplicate events idempotently using the payload resource identifier.
  • Use HTTPS endpoints only.