Learning Content Suggestions API

Every gap comes back with the courses that close it.

Upload a document, give a target role, or both. The API works out where the person falls short of the role, then returns ranked courses for each missing skill — each with its source, level and relevance score. The catalogue knows the skill. It does not know who is missing it.

✓Gap analysis and courses in one call ✓Levels 1–4, one scale ✓1000 free credits to start
Every course carries a score from 0 to 1 and an isPremium flag, so you can rank on relevance and filter on what your licences already cover.
LANGUAGE language="French" optional, defaults to English. 8 supported. FILE 10 MB max ROLE Software Engineer file or role, at least one Gap analysis + course match one call, both powered by OpenKnowra RESPONSE learnings "Docker" gap · needs 3 Docker Fundamentals YouTube · Beginner · 0.55 · free Docker Deep Dive Udemy · Intermediate · 0.48 · paid "Kubernetes" gap · needs 3 Kubernetes for Developers Coursera · Intermediate · 0.51 · paid plus the five skill arrays matched · additional · gap soft · gappedSoft
1
POST for the gap analysis and the courses together
0–1
Relevance score on every course returned
8
Output languages, set per request
1000
Free credits to start, no commitment
Two ways in

Bring a document, bring a role, or bring both.

One multipart request, two fields that matter. At least one of file or role is required — sending neither returns 400 invalid_input. You do not need to run a gap analysis first; this endpoint does that part itself and returns it alongside the courses.

multipart/form-data

Document plus role

The full path. The API extracts what the person demonstrates, compares it against the role, and returns the gap skills and the courses that close each one.

  • PDF, DOC or DOCX, 10 MB maximum per file
  • Returns the same five skill arrays as Skill Gap Identification, plus learnings
  • Courses are keyed by gap skill, so nothing has to be re-joined on your side
curl -X POST "$BASE/v1/learning-content/suggest" \
  -H "Authorization: Bearer $APIKEY" \
  -F "file=@resume.pdf" \
  -F "role=Software Engineer" \
  -F "language=English"
multipart/form-data

From a role alone

No document to hand? Send just the role. Every competency that role expects is treated as a gap, and courses come back for all of them — a ready-made curriculum for the role itself.

  • No file upload, no extraction step, lower latency
  • Useful for building a role onboarding path before anyone is hired into it
  • Billed at the base 1 MB tier, same as a small document
curl -X POST "$BASE/v1/learning-content/suggest" \
  -H "Authorization: Bearer $APIKEY" \
  -F "role=Software Engineer" \
  -F "language=French"
Results come back in English by default. Pass language to get them in French, Spanish, German, Italian, Portuguese, Hindi or Arabic — the course metadata is translated, not just the skill names.
The closure path

Every gap becomes a shortlist, not a search result.

This is the documented response for a resume assessed against Software Engineer. Each row is a key in the learnings object — the hatched band is the level the role expects for that skill. Select any row to see the courses returned for it, with source, level, relevance score and whether it is behind a paywall.

Skill
1 → 4  ·  level the role expects
Items
Level the role expects for this gap skill Level the person already demonstrates
Why a scored shortlist and not a keyword

Catalogue search returns everything about a skill. This returns what is missing, ranked.

Search a skill name and you get beginner content for an expert and expert content for a beginner. Four fields on every course are what make the difference between a search result and a plan.

score

Relevance, 0 to 1

How well this course closes that specific gap, not how popular it is. Sort on it and the top item is the one to assign.

level

Beginner → Expert

The difficulty of the course itself: Beginner, Intermediate, Advanced or Expert. Match it against the level the role expects.

isPremium

Paid or free

true if paid, false if free. Filter before you assign and no one hits a paywall you have not licensed.

courseSource

Where it comes from

The provider, for example Udemy, Coursera or YouTube. Drop the sources your organisation does not use before the plan reaches anyone.

Same 1 to 4 scale on every endpoint in the suite.
API specification

One multipart POST in, the gaps and the courses out.

learnings is an object keyed by gap skill, each key mapping to an array of ranked courses. The same five skill arrays as Skill Gap Identification come back alongside it, so one call covers the diagnosis and the plan.

Request

POST/v1/learning-content/suggest
Base URL https://platform.openknowra.ai/api/bff
Content-Type multipart/form-data
Auth Authorization: Bearer ok_<your-api-key>
One key works across every endpoint in the suite. Keys are prefixed ok_ and expire after 90 days. A request without a valid one returns 401 unauthorized.
FieldTypeRequiredDescription
filefileconditionalA single resume or document. .pdf, .doc, .docx. Up to 10 MB.
rolestringconditionalTarget role to identify gaps against, e.g. Software Engineer. Sent alone, the role’s expected skills are all treated as gaps and courses are recommended for them.
languagestringoptionalOutput language for the results. Defaults to English. Also French, Spanish, German, Italian, Portuguese, Hindi, Arabic.
At least one of file or role is required. Sending neither returns 400 invalid_input.

Response · 200 OK

{
  "success": true,
  "role": "Software Engineer",
  "matchedSkills":    [ { "skill":"java", "level":4 }, ... ],
  "additionalSkills": [ { "skill":"redis", "level":3 } ],
  "gapSkills": [
    { "skill":"Docker",     "level":3 },
    { "skill":"Kubernetes", "level":3 }
  ],
  "softSkills":       [ { "skill":"communication", "level":4 } ],
  "gappedSoftSkills": [ { "skill":"leadership", "level":4 } ],
  "learnings": {
    "Docker": [
      { "courseTitle":  "Docker Fundamentals",
        "courseUrl":    "https://youtube.com/watch?v=...",
        "courseSource": "YouTube",
        "level":        "Beginner",
        "score":        0.55,
        "isPremium":    false },
      { "courseTitle":  "Docker Deep Dive",
        "courseSource": "Udemy",
        "level":        "Intermediate",
        "score":        0.48,
        "isPremium":    true }
    ],
    "Kubernetes": [ /* ... */ ]
  },
  "creditsUsed": 45, "newBalance": 955
}
learnings is keyed by gap skill, so the key always matches an entry in gapSkills — nothing to re-join. Course titles, sources and URLs resolve against the live catalogue. There is no duration field; rank on score and filter on isPremium.
The course object

Six fields, and every one of them is a filter.

Each entry inside a learnings key is a course object. There is no duration and no content-type taxonomy — what you get instead is a relevance score you can sort on and a paywall flag you can filter on.

Course object fields
FieldTypeDescription
courseTitlestringTitle of the recommended course.
courseUrlstringLink to the course.
courseSourcestringProvider, e.g. Udemy, Coursera, YouTube.
levelstringCourse difficulty: Beginner, Intermediate, Advanced or Expert.
scorenumberRelevance score, 0 to 1, for closing that specific gap skill. Sort descending to get the course to assign first.
isPremiumbooleantrue if paid, false if free.
No duration field. If your LMS needs an estimated time on task, take it from your own catalogue metadata after matching on courseUrl — do not infer it from level.
Composability

Same request. This one just goes further.

Skill Gap Identification and this endpoint take the identical multipart body. This one returns everything that one does, and adds learnings on top. Run the cheaper endpoint when you only need the diagnosis; run this one when you need the plan. Nothing to transform between them, because nothing changes but the path.

POST /v1/skill-gap/analyze  ·  35 cr

-F "file=@resume.pdf"
-F "role=Software Engineer"

// diagnosis only
"gapSkills": [
  { "skill":"Docker", "level":3 }
]

POST /v1/learning-content/suggest  ·  45 cr

-F "file=@resume.pdf"
-F "role=Software Engineer"

// same body in, diagnosis plus
"gapSkills": [ /* identical */ ],
"learnings": {
  "Docker": [ { "score":0.55 } ]
}
Where it lands

Learning that moves capability, not completion rates.

Once content is tied to a measured distance, four decisions change first.

Learning

Direct the spend

Point budget at measured gaps instead of catalogue-wide coverage, and report against levels closed.

Internal mobility

Make readiness a path

Give a person the specific sequence that closes the distance to the role they want, not a reading list.

Onboarding

Ramp on what is missing

Skip what the person already demonstrates and target only the band they have yet to cover.

Succession

Build the bench deliberately

Sequence development for each successor against the requirement of the role ahead of them.

Simple, transparent pricing

Billed on payload size, not on how many courses come back.

One rate per API call, covering the first 1 MB of input. Bigger documents step up a tier per whole MB. A call that returns thirty courses across eight gap skills costs the same as one that returns three — the document is what you pay for.

Base $4.50 · 45 credits +$4.50 per extra 1 MB 10 MB max
Pricing construct
Base rate
$4.50 / 45 credits per API call.
Base payload included
Up to 1 MB of input payload, included in the base rate.
Additional payload
$4.50 (45 credits) per additional 1 MB, rounded up to the next whole MB.
Role-only requests
A request with just a target role and no document is charged at the base 1 MB tier — $4.50 / 45 credits.
Maximum payload size
10 MB per API call. Beyond that the call returns 413 file_too_large.
Supported formats
.pdf .doc .docx
Cost = ceil(payload MB) × $4.50, with a minimum of one tier. Payload size is rounded up to the next whole MB for billing. At least one of a document or a target role is required. Failed calls are not charged.
Pricing tiers
Payload sizeCost (USD)Cost (credits)
Up to 1 MB$4.5045
1 – 2 MB$9.0090
2 – 3 MB$13.50135
3 – 4 MB$18.00180
4 – 5 MB$22.50225
5 – 6 MB$27.00270
6 – 7 MB$31.50315
7 – 8 MB$36.00360
8 – 9 MB$40.50405
9 – 10 MB (max)$45.00450
Note: payload size is rounded up to the next whole MB for billing. A 1.2 MB resume is billed at the 1–2 MB tier, not pro rata.
Worked example A · document-based
45 credits · $4.50 for one resume
  • One resume at 380 KB, plus role=Software Engineer
  • Payload rounds up to 1 MB → base tier
  • Returns the five skill arrays and learnings
  • Response returns creditsUsed: 45
1 tier × 45 = 45 credits · $4.50
10 credits more than Skill Gap Identification for the same request — that delta is the whole learning plan.
Worked example B · role-only
45 credits · $4.50, no document
  • Just role=Software Engineer, no file at all
  • No payload to measure → charged at the base 1 MB tier
  • Every competency the role expects is treated as a gap
  • Courses come back for all of them — a role curriculum
1 tier × 45 = 45 credits · $4.50
Build the onboarding path for a role once, before anyone is hired into it.
No commitment
1000 free credits

Generate a key, spend the 1000 credits on real learning plans, and decide after that. At the base rate that is 22 single-resume plans before you pay anything. For enterprise volumes, reach us at ok@spire.ai

Worked example C · choosing between the two endpoints
What you needEndpointCost per call
Just the named gaps, for a hiring or mobility decision/v1/skill-gap/analyze35 cr · $3.50
The gaps and the courses that close them/v1/learning-content/suggest45 cr · $4.50
Both, by calling the two endpoints separatelyboth80 cr · $8.00
Don’t call both. This endpoint already returns everything Skill Gap Identification does. Calling the pair costs 80 credits for a result this one delivers for 45 — a 44% overspend for a duplicated analysis.

Rates are configured per deployment and can change. creditsUsed in every response reflects what that specific call was actually billed, so don’t hardcode the numbers above.

Error handling

Every failure returns a code you can branch on.

Failed calls are not charged. A 402 tells you exactly how short you are, so a client can top up and retry without re-uploading the document.

Error responses
StatusCodeMeaning
400invalid_inputNeither a document nor a target role was provided.
401unauthorizedMissing, invalid, expired or revoked API key. Keys expire after 90 days.
402insufficient_creditsAccount balance too low. The body carries required and balance.
413file_too_largeThe file exceeds the 10 MB per-file size limit.
502upstream_errorThe analysis engine returned an error. Safe to retry after a short delay.
503service_unavailableThe analysis service is briefly unavailable or not configured. Safe to retry.
402 body: { "error": { "code": "insufficient_credits", "required": 25, "balance": 10 } }

Stop recommending the catalogue.

Return the content that closes a measured gap, aimed at the level the person actually has to reach, in one call.