Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.hawkings.education/llms.txt

Use this file to discover all available pages before exploring further.

Anywhere you can author content by hand, you can also generate it. The generation API is async-first because most of it takes 10s–60s.

The lifecycle

       ┌──────────────────────────────────────┐
       │ 1. Call *.generate*()                │
       │    → returns { id, status: "pending" }│
       └──────────────────────────────────────┘


       ┌──────────────────────────────────────┐
       │ 2. Backend runs the generation       │
       │    (research → outline → write → QA) │
       └──────────────────────────────────────┘


       ┌──────────────────────────────────────┐
       │ 3. Resource transitions to "ready"   │
       │    or "error"                        │
       └──────────────────────────────────────┘
You learn about completion by polling or by webhooks.

Polling

The SDK ships a tiny poll() helper:
const course = await hk.courses.create({ name: "Intro to SR", language: "en" });

await hk.courses.generateSyllabus(course.id, {
  brief: "An introductory course on special relativity...",
});

const ready = await hk.poll(
  () => hk.courses.retrieve(course.id),
  { until: c => c.status === "ready", interval_ms: 2000, timeout_ms: 120_000 },
);
For batch operations, every resource that supports generation also has a getStatus(ids[]) call so you can poll many at once:
const statuses = await hk.courses.getStatus([id1, id2, id3]);
// → [{ id: id1, status: "ready" }, { id: id2, status: "pending" }, ...]

Webhooks

Recommended in production. Subscribe to events in the dashboard:
  • course.syllabus_generated
  • lesson.content_generated
  • activity.generated
  • submission.graded
Hawkings POSTs to your URL with:
{
  "id": "evt_01HX9...",
  "type": "course.syllabus_generated",
  "data": { "course_id": "crs_01HX9...", "status": "ready" },
  "created_at": "2026-05-10T12:34:56Z"
}
Verify the signature with hk.webhooks.verify(body, signature, secret).

What you can generate

MethodProduces
courses.generateSyllabus(id, ...)Units, lessons, learning objectives.
courses.adaptSyllabus(id, ...)Re-tailors an existing syllabus to a new audience.
courses.generateImage(id, ...)Cover image for the course.
lessonContents.generate(...)Long-form HTML reading for a lesson.
lessonContents.generateImages(...)Inline diagrams and illustrations.
activities.generate(...)A mix of activities for a lesson.
activities.create({ type: ..., })A specific activity (also async).
tags.generate({ source })Tags extracted from a body of text.
submissions.gradeWithAi(id)Score + rationale for a submission.

Grounded research (advanced)

By default, generation uses the model’s training. You can ground it in specific sources for higher factual accuracy:
await hk.research.create({
  query: "Recent (2024-2026) experimental tests of special relativity",
  sources: [
    { type: "url", url: "https://arxiv.org/abs/2403.12345" },
    { type: "pdf", file_id: "fil_..." },
  ],
});

// Then attach the research to a generation
await hk.lessonContents.generate({
  lesson_id: "lsn_123",
  research_id: "res_...",
});
Research artefacts are reusable across generations. They expire after 30 days unless pinned.

Cost & quotas

Every generation method consumes credits (see your dashboard for the per-call cost). Calls can be capped via per-key quotas; exceeding a quota throws RateLimitError with code: "quota_exceeded".

When generation fails

status: "error" resources carry an error object:
{
  "status": "error",
  "error": {
    "type": "generation_failed",
    "code": "model_refusal",
    "message": "The model refused to generate content for this prompt.",
    "retriable": true
  }
}
If retriable: true, calling the same *.generate*() again with the same parameters is safe. If it’s false, fix the input and try again.