Skip to Content

Reporting completion from a third-party tool

Prerequisites: an external content source already configured, and a provider able to call a URL at the end of a content.

On this page

Reporting completion from a third-party tool

Prerequisites: an external content source already configured, and a provider able to call a URL at the end of a content.

The callback is the route by which a third-party tool tells Beedeez that a learner finished a capsule. Beedeez calls nothing here: the provider calls Beedeez. The opposite direction is the webhook, and the two are not interchangeable.

Where it is set

Configuration › Integrations › LMS › External content configuration, field Method to get results, value Callback Url.

The setting belongs to the external content source, not to a capsule and not to the whole account. Every capsule served by that source reports back, or none does.

The URL is not something you copy once

It is displayed nowhere in the back office, and there is not one of it. Beedeez builds one per learner and per capsule, at launch time, and hands it to the provider. The values of the Authentication field are shown in capitals and untranslated, exactly as they appear on screen:

  • NONE and TALENTSOFT: appended to the launch URL in the CALLBACK_URL parameter;
  • LTI: sent as the custom parameter custom_callbackurl;
  • APIKEY: nothing is passed at all.

⚠️ The provider has to read the URL on every launch. A provider that asks you for one URL to paste once into its settings cannot do this mechanism.

The call

POST https://api.developers.beedeez.com/v1/callbacks/update-user-lesson-status/{CALLBACK_TOKEN}

GET is accepted on the same address: some tools can only issue a redirect at the end of a content. This entry is also in the OpenAPI reference, at doc.developers.beedeez.com .

Request body, JSON:

FieldTypeRequiredValues
statusstringyesnot-started, in-progress, succeeded, failed
progressnumberyes0 to 100
scorenumberno0 to 100

Response 200: UserID, LessonID, status, progress, plus score and absoluteScore when a score was sent. absoluteScore is the number of points actually credited.

Errors: 400 when score falls outside 0 to 100, and when status is not one of the four accepted values; 403 when the token is unknown, expired or of another type, or when the capsule is not external content; 404 when no activity matches the token, or when the source is not set to Callback Url.

⚠️ progress is not validated. An out-of-range value is stored as sent.

Completed is not passed

  • succeeded: capsule at 100 %, marked as passed.
  • failed: capsule at 100 %, marked as not passed. That too is a completion.
  • in-progress and not-started: capsule set to the progress value, not passed.

For an external content capsule Beedeez recomputes nothing. The capsule’s Success of the capsule block, with its validation mode and its percentage, does not apply: the provider alone decides success. That is the distinction to hold on to before building billing or compliance logic on this signal.

Points follow two different rules:

  • without score, a succeeded adds the capsule’s full bonus points to the points already held;
  • with score, the credited total is replaced by that percentage of the bonus points, rounded. This replacement applies whatever the status sent, including in-progress.

ℹ️ There is no track callback. A track completes through its capsules; nothing lets you declare one finished directly.

How Beedeez knows who this is about

Nothing in the request names the learner or the capsule: the token carries all of it, the account, the learner, the capsule and the attempt in progress. It is a random identifier, created on the first launch, reused on later ones, valid for 100 days.

The response returns Beedeez internal identifiers, 24 hexadecimal characters. No reference of your own is echoed back: if your receiver has to match against your own records, it must store that correspondence at launch time.

Authentication is the token, and nothing else

No API key, no authorisation header, no signature, no allowed-IP list. It is the one entry point of the public API in that situation. Whoever holds the URL can report a completion for that learner and that capsule. There is no revoke button in the interface either: to invalidate a token, go through your Beedeez contact.

⚠️ The token sits in the URL path. It therefore shows up in proxy logs, in referrer headers and in browser history. With authentication NONE it travels in the clear inside a URL opened by the learner’s own browser, where the learner can read it.

The trap: the first signal wins

As soon as the capsule is completed, every later call is ignored. The response is still 200 and carries the stored state, but nothing changes. Replaying the same call is therefore harmless, but this is not idempotency working for you: it is a lock.

The lock follows completion, not the reported progress: only succeeded and failed complete the capsule. A capsule left at in-progress, even with a progress of 100, still accepts later calls.

Two consequences:

  • a failed received first freezes the capsule on “completed, not passed”; a succeeded sent afterwards does not correct it;
  • ⚠️ the app can be that first signal. A learner who reaches the end of the capsule in the app completes it themselves, and the provider call arriving later changes nothing.

What it does not do

  • No catch-up. Beedeez does not send this call: if the provider fails or never calls, nothing repairs it, there is no queue and no replay. Ask the provider what it does on failure, and over how many attempts.
  • No reset. The callback cannot bring a completed capsule back to not completed.
  • No webhook event. A completion received through the callback fires no lesson_completed event: that event is not emitted.

Checking it works

End to end, with a real learner account: they launch the content, go all the way through at the provider, and the capsule moves to 100 % in Beedeez.

⚠️ Do not validate on a simulated call. A URL hit by hand proves that the entry point answers, not that the provider calls at the right moment. That is exactly what fails in production. Test the failure path too: send failed on a test account and look at what your statistics make of it.

Going further


Discutez avec nous