> ## Documentation Index
> Fetch the complete documentation index at: https://docs.edpire.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Integration Runbook

> The end-to-end plan for putting Edpire assessments inside an e-learning platform: who does what, in what order, and how long it takes.

Every other page here answers a technical question. This one answers the operational one: **who does what, in which product, and in what order.**

It is written for the person running the integration, not only the developer building it.

***

## What you are actually adding

Edpire becomes the **exercise layer inside a lesson**. Your courses, your users, your UI and your mobile app stay exactly as they are. The only change to your product is that a lesson can now contain an assessment.

| We supply                                            | You supply                                                  |
| ---------------------------------------------------- | ----------------------------------------------------------- |
| The builder where assessments are written            | Your catalog, taxonomy and access control                   |
| The player that renders them inside your page or app | A field on your lesson table holding `edpire_assessment_id` |
| The grading engine, instant and deterministic        | A screen that mounts the player                             |
| Per-question analytics                               | A webhook receiver                                          |
| Webhooks pushing results into your database          | One or two named people who own assessment content          |

**What we do not do**, so it is said early: we do not write your content for you, we do not manage your users or rosters (learners reach us as a `learner_ref` you control), and we do not replace your LMS, your video, or your progress tracking.

***

## The one decision worth making up front

**Who writes the assessments?**

This is the question that decides whether an integration succeeds, and it is not a technical one. The common failure is assuming "our teachers will do it." Platforms that have already tried an in-house quiz tool usually discovered their teachers did not want to author, which is exactly why they are talking to us.

Name **one or two people who own assessment content**. Not the whole teaching staff. Those people get Edpire logins and work in our builder; everyone else carries on as before.

<Tip>
  If content is your bottleneck rather than engineering, ask us about an authoring workshop. Your
  team brings existing exercise documents and leaves the session with them built and the ability to
  build more. It is usually faster than hiring for it.
</Tip>

***

## The four loops

An integration is four repeating loops, not one project. Three of them are ours or automatic.

| Loop                    | Who runs it               | Where                        | How often           |
| ----------------------- | ------------------------- | ---------------------------- | ------------------- |
| **Setup**               | Us, with your developer   | Dashboard + your backend     | Once                |
| **Authoring**           | Your named content owners | `edpire.com` builder         | Ongoing, per lesson |
| **Linking**             | Your admin                | Your own lesson table        | Per assessment      |
| **Playing and results** | Automatic                 | Your app, then your database | Continuously        |

***

## Phase 1 — going live

### Step 1 · Provisioning (us, about a day)

We create your organization and send you:

* An **API key** (`Integrations` in the dashboard)
* Your registered domains in the two allow-lists (see below)
* A **webhook endpoint** pointed at your receiver
* Your quota band

<Warning>
  There are **two separate origin allow-lists** under **Integrations → Security**, and putting a
  domain in the wrong one is the single most common setup mistake:

  | List                               | Used for                                 |
  | ---------------------------------- | ---------------------------------------- |
  | **Allowed API & Redirect Origins** | Server-to-server calls and `return_url`  |
  | **Allowed Embed Origins**          | Pages that mount the player with our SDK |
</Warning>

### Step 2 · Name your content owners (you, blocking)

Nothing else is blocked by this, but the integration is worthless without it. See above.

### Step 3 · Authoring (your content owners)

They log in to `edpire.com`, build assessments in **My Assessments**, and publish. Each published assessment has a UUID and a share code.

### Step 4 · Linking (your developer, half a day)

Add an `edpire_assessment_id` column to your lesson or content table.

```sql theme={null}
ALTER TABLE lessons ADD COLUMN edpire_assessment_id TEXT;
```

Three ways to populate it, best first:

**Author links (recommended).** Your backend creates the draft and gets its ID immediately, so the UUID is never copy-pasted and your author lands straight in the builder:

```typescript theme={null}
const res = await fetch("https://edpire.com/api/v1/author-links", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.EDPIRE_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ title: lesson.title, folder_id: courseFolderId }),
}).then((r) => r.json())

// Store this now — the draft already exists.
await db.lessons.update(lesson.id, { edpire_assessment_id: res.data.assessment_id })

// Give this to whoever writes the content.
console.log(res.data.author_url)
```

Opening `author_url` drops that person into the Edpire builder for exactly that assessment. They sign in to Edpire as themselves the first time; after that the link just works.

<Note>
  The link carries **context, not access.** It identifies an assessment, not a person. Whoever
  opens it must be signed in to Edpire as themselves, be a member of your organization, and hold
  an author or admin role. Sending the link to the wrong person grants them nothing, and it can
  never be used to act as somebody else. It is valid for 24 hours.
</Note>

**Paste the ID.** Your admin copies the UUID from the dashboard. Fine to start with.

**Build a picker.** Call `GET /api/v1/assessments?status=published` and render a dropdown in your admin. Worth it once you have more than a handful.

### Step 5 · Mount the player (your developer, 1 to 2 days)

Use the [Embedded Player](/developer/sdk/embedded-player). Web and mobile share one token endpoint on your backend.

```typescript theme={null}
// Your backend — the API key never leaves this file
export const POST = createEdpireTokenHandler({
  apiKey: process.env.EDPIRE_API_KEY!,
  resolveLearner: async (req) => {
    // Resolve from YOUR session. Never from the request body.
    return await getUserIdFromRequest(req)
  },
})
```

```tsx theme={null}
// Your web app
<EdpireAssessmentPlayer
  tokenEndpoint="/api/edpire/token"
  assessmentId={lesson.edpire_assessment_id}
  onComplete={(r) => markLessonComplete(lesson.id, r.score, r.max_score)}
  style={{ width: "100%", height: "100vh" }}
/>
```

On mobile it is the same player in a WebView, calling the same token endpoint. See [Mobile](/developer/mobile).

`learner_ref` is **your** user ID. We never resolve it to a person, and every submission stays tied to it.

### Step 6 · Receive results (your developer, half a day)

Register a webhook for `submission.graded`, verify the signature, and write the result into your own tables. Your existing progress UI does not need to change.

```typescript theme={null}
app.post("/webhooks/edpire", express.raw({ type: "application/json" }), (req, res) => {
  if (!verifySignature(req.body.toString(), req.headers["x-edpire-signature"], SECRET)) {
    return res.sendStatus(401)
  }
  res.sendStatus(200)              // respond first, process after

  const e = JSON.parse(req.body.toString())
  if (e.event === "submission.graded") {
    if (await alreadyProcessed(e.submission_id)) return   // deliveries can repeat
    await saveResult(e)
  }
})
```

<Note>
  **Phase 1 should be auto-graded only.** Every question type except open-ended grades instantly, with
  no teacher involvement, which is the whole point for adoption. If an assessment contains open-ended
  questions, `submission.graded` arrives with `awaiting_manual_grading: true` and a **provisional**
  score covering only the auto-graded part. The real total arrives later on
  `submission.grading.completed`, after a teacher grades it in our dashboard. Handle that event before
  you enable open-ended questions.
</Note>

### Step 7 · Test without polluting your numbers

Use a second organization, as described in [Testing](/developer/testing). Quotas, analytics and active-learner counts are all scoped per organization, so development traffic never reaches your real reporting.

***

## Effort estimate

Give this to whoever is signing off the cost.

| Work                                             | Estimate                    |
| ------------------------------------------------ | --------------------------- |
| `edpire_assessment_id` column                    | 0.5 day                     |
| Admin picker (paste an ID, or list from the API) | 0.5 to 1 day                |
| Token endpoint on your backend                   | 0.5 day                     |
| Web player screen                                | 0.5 day                     |
| Mobile WebView screen                            | 1 day                       |
| Webhook receiver                                 | 0.5 day                     |
| Wiring results into your existing progress UI    | 1 day                       |
| **Total**                                        | **\~4 to 5 developer days** |

Authoring is not in this table because it is not developer work. It runs in parallel from Step 3.

***

## Phase 2 — once you are live

None of this is needed to launch. Ask when you want it.

* **Open-ended questions with teacher grading.** Works today over the API; grading happens in our dashboard.
* **Analytics in your product.** `GET /api/v1/assessments/{id}/analytics` returns per-question stats, score distribution and per-learner results, so you can render them in your own UI.
* **Catalog sync.** Mirror assessment titles and metadata into your database and keep them current with webhooks. See [Catalog Sync](/developer/catalog-sync).
* **Custom learner experience.** If you want a Duolingo-style drill rather than a standard assessment, that is [Custom Flow](/developer/sdk/custom-flow). More work, more control.

***

## Go-live checklist

* [ ] One or two named content owners, with logins, who have published at least one real assessment
* [ ] Production domains in the correct allow-list (embed pages in **Allowed Embed Origins**)
* [ ] API key server-side only, never in a browser bundle
* [ ] `learner_ref` is your stable internal user ID, not an email or username
* [ ] Webhook signature verification tested with a deliberately bad signature
* [ ] Webhook handler is idempotent on `submission_id`
* [ ] You handle `awaiting_manual_grading`, or you have confirmed no assessment uses open-ended questions
* [ ] Development traffic runs through a second organization
* [ ] Someone owns the relationship on your side and knows how to reach [support@edpire.com](mailto:support@edpire.com)
