Learning Content Suggestions API
Upload a professional document, give a target role, or both. The API works out where the person falls short of the role, then recommends targeted courses - each with its source, level, and relevance score - to close every gap. Results come back in the language you choose.
When to use this API
Use this API to turn a skill gap into an actionable learning plan - a ranked set of courses for each skill the person is missing.
Send a document, a target role, or both. The API identifies the gap skills against
the role, then returns learnings - an object keyed by gap skill, each
mapping to recommended courses. It also returns the matched skills, additional
skills, and soft skills for the full picture. With just a role (no document), the
role's expected skills are treated as gaps and courses are recommended for them.
Results are returned in English by default. Pass an optional
language field (e.g. French, Spanish,
German, Hindi) to receive them in that language.
Authentication
All requests require a user-scoped API key passed as a bearer token.
Generate one in the platform under Settings → API Keys.
Keys are prefixed ok_ and expire after 90 days.
Authorization: Bearer ok_xxxxxxxxxxxxxxxxxxxxxxxx
401 unauthorized.
Parameters
Form fields
| Name | Type | Required | Description |
|---|---|---|---|
| file | file | conditional |
A single resume or document. Accepted formats:
.pdf, .doc, .docx. Up to 10 MB.
Either file or role (or both) must be provided.
|
| role | string | conditional |
Target role to identify gaps against, e.g. Software Engineer.
Sent with just a role (no file), the role's expected skills are treated as gaps.
Either file or role (or both) must be provided.
|
| language | string | optional |
Output language for the results. Defaults to English.
Examples: French, Spanish, German,
Italian, Portuguese, Hindi, Arabic.
|
file or role is required.
Sending neither returns 400.
Request
# Document + role
curl -X POST https://platform.openknowra.ai/api/bff/v1/learning-content/suggest \
-H "Authorization: Bearer $OPENKNOWRA_API_KEY" \
-F "file=@/path/to/resume.pdf" \
-F "role=Software Engineer" \
-F "language=English"
# Role only (no document)
curl -X POST https://platform.openknowra.ai/api/bff/v1/learning-content/suggest \
-H "Authorization: Bearer $OPENKNOWRA_API_KEY" \
-F "role=Software Engineer" \
-F "language=English"import os
import requests
API_KEY = os.environ["OPENKNOWRA_API_KEY"]
API_URL = "https://platform.openknowra.ai/api/bff/v1/learning-content/suggest"
with open("./resume.pdf", "rb") as f:
res = requests.post(
API_URL,
headers={"Authorization": f"Bearer {API_KEY}"},
files={"file": f},
data={"role": "Software Engineer", "language": "English"},
)
res.raise_for_status()
data = res.json()
for skill, courses in data["learnings"].items():
print(skill, "->", [c["courseTitle"] for c in courses])import fs from "fs";
const API_KEY = process.env.OPENKNOWRA_API_KEY!;
const API_URL = "https://platform.openknowra.ai/api/bff/v1/learning-content/suggest";
const form = new FormData();
form.append("file", new Blob([fs.readFileSync("./resume.pdf")]), "resume.pdf");
form.append("role", "Software Engineer");
form.append("language", "English");
const res = await fetch(API_URL, { method: "POST", headers: { Authorization: `Bearer ${API_KEY}` }, body: form });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
console.log((await res.json()).learnings);Response
200 OK - learnings is an object keyed by gap skill,
each mapping to an array of recommended courses. The skill lists
(matchedSkills, additionalSkills, gapSkills,
softSkills, gappedSoftSkills) are arrays of
{ skill, level } (level 1-4). role is echoed only when one
was provided.
{
"success": true,
"role": "Software Engineer",
"matchedSkills": [
{ "skill": "java", "level": 4 },
{ "skill": "sql", "level": 2 }
],
"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=docker-fundamentals",
"courseSource": "YouTube",
"level": "Beginner",
"score": 0.55,
"isPremium": false
},
{
"courseTitle": "Docker Deep Dive",
"courseUrl": "https://udemy.com/course/docker-deep-dive",
"courseSource": "Udemy",
"level": "Intermediate",
"score": 0.48,
"isPremium": true
}
],
"Kubernetes": [
{
"courseTitle": "Kubernetes for Developers",
"courseUrl": "https://coursera.org/learn/kubernetes-for-developers",
"courseSource": "Coursera",
"level": "Intermediate",
"score": 0.51,
"isPremium": true
}
]
},
"creditsUsed": 45,
"newBalance": 955
}
Course object fields
| Field | Type | Description |
|---|---|---|
| courseTitle | string | Title of the recommended course. |
| courseUrl | string | Link to the course. |
| courseSource | string | Provider, e.g. Udemy, Coursera, YouTube. |
| level | string | Course difficulty: Beginner, Intermediate, Advanced, or Expert. |
| score | number | Relevance score (0-1) for closing the gap skill. |
| isPremium | boolean | true if paid, false if free. |
Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_input | Neither a document nor a target role was provided. |
| 401 | unauthorized | Missing, invalid, expired, or revoked API key. |
| 402 | insufficient_credits | Account balance too low. Response includes required and balance. |
| 413 | file_too_large | The file exceeds the 10 MB per-file size limit. |
| 502 | upstream_error | The analysis engine returned an error. Safe to retry after a short delay. |
| 503 | service_unavailable | The analysis service is briefly unavailable or not configured. Safe to retry. |
{
"error": {
"code": "insufficient_credits",
"required": 25,
"balance": 10
}
}