Statements
Everything in xAPI is a statement: an actor, a verb and an object, optionally with a result and context. A course sends statements to a Learning Record Store (LRS) over HTTPS as JSON.
{
"actor": {
"objectType": "Agent",
"name": "Ann Murphy",
"mbox": "mailto:ann@example.com"
},
"verb": {
"id": "http://adlnet.gov/expapi/verbs/passed",
"display": { "en-IE": "passed" }
},
"object": {
"id": "https://example.com/courses/fire-safety",
"definition": { "name": { "en-IE": "Fire Safety Basics" } }
},
"result": {
"score": { "scaled": 0.85 },
"success": true,
"completion": true,
"duration": "PT14M12S"
},
"context": {
"registration": "6a1d8c2e-58b4-4f0b-9a63-2f1d9c0c4b7e"
},
"timestamp": "2026-10-13T09:30:00Z"
}
- actor: who. Identified by exactly one of
mbox(email),mbox_sha1sum,openidoraccount(a user name on a system, given ashomePage+name). Can also be a Group. - verb: what happened, identified by an IRI. The display text is only for people.
- object: usually an Activity (a course, module, slide, question), identified by an IRI. Question activities
carry an
interactionType(choice, fill-in, matching…) and the correct responses in their definition. - result: score (
scaledfrom −1 to 1, or raw/min/max), success, completion, response and an ISO 8601 duration. - context: the
registrationUUID ties the statements of one attempt together; context activities give the parent course of a question, and more. - The LRS adds an
id,storedtime andauthority. Statements are never changed; a mistake is undone with a voiding statement.
Common verbs
Any IRI can be a verb, but reports work best with the well-known ADL verbs, which authoring tools use:
| Verb | Used for |
|---|---|
| launched / initialized | the course was opened, a session starts |
| experienced | a slide, page or video was seen |
| answered | a question was answered (with result.response and result.success) |
| completed | the learner finished the course or module |
| passed / failed | the course or test was passed or failed, usually with a score |
| suspended / resumed | the learner left and came back later |
| terminated | the session ended |
| voided | a statement is withdrawn (object: a StatementRef) |
All under http://adlnet.gov/expapi/verbs/.
The LRS API
An LRS is a small REST API under one base address, the endpoint. Every request needs HTTP Basic authentication (a key and
secret from the LRS) and the header X-Experience-API-Version: 1.0.3.
| Resource | Methods | What for |
|---|---|---|
| statements | POST, PUT, GET | store statements (one or a list); fetch one by id or query them |
| activities/state | PUT, POST, GET, DELETE | a course’s saved data per learner and registration: where to resume, bookmarks |
| activities/profile | PUT, POST, GET, DELETE | documents about an activity |
| agents/profile | PUT, POST, GET, DELETE | documents about a learner |
| activities | GET | the full definition of an activity, as the LRS knows it |
| agents | GET | a Person object with all known identifiers of an agent |
| about | GET | the versions the LRS supports (no authentication) |
Send a statement:
curl https://lrs.ie/xapi/statements \
-u "$KEY:$SECRET" \
-H "X-Experience-API-Version: 1.0.3" \
-H "Content-Type: application/json" \
-d '{"actor":{"mbox":"mailto:ann@example.com"},
"verb":{"id":"http://adlnet.gov/expapi/verbs/completed"},
"object":{"id":"https://example.com/courses/fire-safety"}}'
The LRS answers with the new statement id in a JSON list. Posting to the same id twice with different content is refused (409).
Querying
GET statements filters by query parameters and returns newest first:
curl -G https://lrs.ie/xapi/statements \
-u "$KEY:$SECRET" -H "X-Experience-API-Version: 1.0.3" \
--data-urlencode 'agent={"mbox":"mailto:ann@example.com"}' \
--data-urlencode 'verb=http://adlnet.gov/expapi/verbs/passed' \
--data-urlencode 'since=2026-10-01T00:00:00Z' \
--data-urlencode 'limit=50'
agent,verb,activity,registration: exact matches;related_activities/related_agentswiden them to context and sub-statements.since,until(stored time),ascending,limit.format:exact,idsorcanonical(one language).- Results come in pages: follow the
moreURL until it is empty. - There is no free-text search or aggregation in the standard. Reports are built by reading statements into your own tables.
Launching a course
A published xAPI course needs to be told where its LRS is and who the learner is. Storyline, Rise, Captivate and iSpring read the convention Rustici Software introduced with Tin Can: query parameters on the course’s start page.
index_lms.html?endpoint=https%3A%2F%2Flrs.example%2Fxapi%2F
&auth=Basic%20a2V5OnNlY3JldA%3D%3D
&actor=%7B%22name%22%3A%22Ann%22%2C%22mbox%22%3A%22mailto%3Aann%40example.com%22%7D
®istration=6a1d8c2e-58b4-4f0b-9a63-2f1d9c0c4b7e
&activity_id=https%3A%2F%2Fexample.com%2Fcourses%2Ffire-safety
The credential is visible to the learner’s browser, so it should never be the LRS’s main key: issue a short-lived one that can only write that learner’s statements. Keep the registration the same on every launch, so the course can resume from its saved state.
No course yet, or no time to build one?
The Learn Skills team builds courses from your content, ready to upload here, and can supply ready-made ones.
cmi5 and versions
- xAPI 1.0.3 (2016) is what authoring tools and LRSs use today. ADL publishes a conformance test suite for it.
- IEEE 9274.1.1-2023, often called xAPI 2.0, is the version published as an IEEE standard. It is largely compatible; adoption is gradual.
- cmi5 is a profile of xAPI for courses launched by an LMS: a standard launch handshake (no secrets in the URL), a fixed set of verbs and “moveOn” rules for when a course counts as done.
Questions
What is the difference between xAPI and Tin Can?
None: they are the same standard. Tin Can was the project name while Rustici Software developed it for ADL; version 1.0 was published in 2013 as the Experience API, xAPI for short.
What is an LRS endpoint?
The base address of a Learning Record Store’s REST API, such as https://lrs.ie/xapi/. The resources (statements, activities/state and the others) are paths under it. A course or system needs the endpoint plus a key and secret for HTTP Basic authentication.
Which header does every xAPI request need?
X-Experience-API-Version, set to the version the client speaks (1.0.3 today). An LRS refuses requests without it, except GET about.
How do I get statements out of an LRS?
GET the statements resource with filters such as agent, verb, activity, since and limit, and follow the “more” URL in each response until it is empty. The standard has no aggregation; reports are built from the statements you read.
Is cmi5 the same as xAPI?
cmi5 is built on xAPI: a profile that fixes how an LMS launches a course, which verbs it sends and when the course counts as complete. Every cmi5 statement is an xAPI statement.
Is xAPI 2.0 different from 1.0.3?
xAPI 2.0 is the version published as IEEE 9274.1.1-2023. It is largely compatible with 1.0.3, which is what authoring tools and LRSs use today.
Get an endpoint
Learn Skills LRS is a hosted xAPI 1.0.3 LRS, kept in Ireland. It passes all 1,365 tests of the ADL conformance suite, hosts and launches courses for you, and turns statements into reports. The free plan includes an endpoint and keys.
See Learn Skills LRS