HR och medlemsregister
Matcha på vald identifierare, spara Eduvos interna ID och tilldela rätt publicerad kurs. Synka ändringar när de sker i källsystemet.
KOPPLA IHOP ERA SYSTEM
Koppla ert HR-system, medlemsregister eller CRM till Eduvo. Skapa deltagare, tilldela kurser och hämta resultat med REST eller GraphQL.
STEG 1
Du behöver API-adress, klient-ID och klienthemlighet. En organisationsadministratör hanterar API-klienter under Inställningar → Integrationer när funktionen är tillgänglig i miljön. Hemligheten visas när klienten skapas.
courses:read.
Exemplet körs på en server eller i en lokal terminal med Bash, curl och
jq. Ersätt exempeladressen och klient-ID:t. Ange hemligheten när terminalen
frågar.
API_BASE_URL='https://er-api-adress.example'
CLIENT_ID='ert-klient-id'
printf 'Klienthemlighet: '
read -r -s CLIENT_SECRET
printf '\n'
TOKEN_RESPONSE=$(curl --fail-with-body --silent --show-error \
"$API_BASE_URL/oauth/token" \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode "client_id=$CLIENT_ID" \
--data-urlencode "client_secret=$CLIENT_SECRET" \
--data-urlencode 'scope=courses:read')
ACCESS_TOKEN=$(printf '%s' "$TOKEN_RESPONSE" | jq -er '.access_token')
unset CLIENT_SECRET TOKEN_RESPONSE
curl --fail-with-body --silent --show-error \
"$API_BASE_URL/v1/courses?limit=25" \
-H "Authorization: Bearer $ACCESS_TOKEN"
Token gäller i 3 600 sekunder. Hämta en ny före utgången. Begär bara scopes som klienten redan har tilldelats. Organisationen bestäms av klienten; ett anrop kan inte välja en annan organisation.
| Uppgift | Scope |
|---|---|
| Läsa / skriva deltagare | users:read / users:write |
| Läsa kurser | courses:read |
| Läsa / skriva kurstilldelningar | enrollments:read / enrollments:write |
| Läsa slutföranden | completions:read |
| Läsa intyg | certificates:read |
| Hantera webhooks | webhooks:manage |
STEG 2
Organisationen kan välja e-post, anställnings-ID eller externt ID med egen benämning, exempelvis medlemsnummer. Valet används för register och matchning. Inloggningen fungerar som tidigare.
| Fält | Betydelse | Exempel |
|---|---|---|
id / userId |
Eduvos stabila interna deltagar-ID. Använd det i kurstilldelningar. | usr_… |
identifierType + identifierValue |
Organisationens identifierare: email, employeeId eller
customId.
|
employeeId + 00123 |
externalId |
Separat koppling till ert källsystem. Behåller sin betydelse när organisationen byter typ. | hr-987 |
E-post trimmas och omvandlas till gemener. Övriga ID:n trimmas, bevarar inledande nollor och skiljer på stora och små bokstäver. Skicka alltid ID:n som strängar. Identifieraren måste vara unik inom organisationen.
userId och email,
employeeId eller customId. Högst 100 deltagare per
kompletteringsimport.
Kurstilldelningar och resultat behålls. Nya deltagare behöver den valda identifieraren. E-post kan fortfarande användas för kontakt och inbjudningar. Befintliga organisationer behåller tidigare beteende tills valet aktiveras.
STEG 3
REST använder JSON under /v1. Hämta en token med users:write,
courses:read och enrollments:write för exemplen nedan. Ersätt
scope-värdet i tokenanropet ovan med dessa tre scopes separerade med mellanslag.
PUT /v1/users/external/{externalId} matchar på integrationsnyckeln. Använd
samma nyckel för samma person och URL-koda den vid behov. Exemplet förutsätter att
anställnings-ID är organisationens aktiva val.
USER_RESPONSE=$(curl --fail-with-body --silent --show-error \
-X PUT "$API_BASE_URL/v1/users/external/hr-987" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: hr-987-sync-v1' \
--data '{"displayName":"Exempeldeltagare","email":"person@example.test","employeeId":"00123"}')
USER_ID=$(printf '%s' "$USER_RESPONSE" | jq -er '.id')
Hämta ett courseId från GET /v1/courses. Tilldelningen kopplas
till kursens publicerade version. Byt exempelvärdet nedan till ert kurs-ID.
COURSE_ID='ert-publicerade-kurs-id'
ENROLLMENT_RESPONSE=$(curl --fail-with-body --silent --show-error \
"$API_BASE_URL/v1/enrollments" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: hr-987-kurs-tilldelning-v1' \
--data "$(jq -n --arg userId "$USER_ID" --arg courseId "$COURSE_ID" \
'{userId:$userId,courseId:$courseId}')")
ENROLLMENT_ID=$(printf '%s' "$ENROLLMENT_RESPONSE" | jq -er '.id')
En tilldelning skapar kopplingen till kursen. Anropet är inte i sig ett mejlutskick eller bevis på att deltagaren har öppnat kursen.
GET /v1/users?identifier=00123 – uppslag via organisationens aktiva
identifierare. Kräver users:read.
PATCH /v1/users/{id} – uppdatera en känd deltagare.DELETE /v1/enrollments/{id} – avbryt en tilldelning.DELETE /v1/users/{id} – köa ett raderingsjobb. HTTP 204 betyder
mottagen begäran, inte färdig radering.
STEG 4
Skicka POST /graphql med samma OAuth-token och scopes som för REST.
JSON-kroppen innehåller query, valfria variables och vid behov
operationName. Skicka Content-Type: application/json och
Authorization: Bearer ….
{
"query": "query Participants($cursor: String) { users(limit: 25, cursor: $cursor) { data { id displayName identifierType identifierValue } nextCursor } }",
"variables": { "cursor": null }
}
upsertUser skapar deltagaren om identifieraren saknas, annars uppdateras
samma deltagare. Exemplet kräver users:write och anställnings-ID eller
externt ID som aktiv typ.
{
"query": "mutation Sync($key: String!, $person: UserInput!) { upsertUser(identifier: $key, input: $person) { id identifierValue } }",
"variables": {
"key": "00123",
"person": { "displayName": "Exempeldeltagare", "email": "person@example.test" }
}
}
Skicka en stabil Idempotency-Key för mutationer och en mutation per
begäran. En upsert får inte samtidigt ändra värdet den matchar på; använd
updateUser(id: …) för sådana ändringar.
Frågor: users, user, courses,
course, enrollments, enrollment,
progress, progresses, completions och
completion.
Mutationer: createUser, updateUser, upsertUser,
createEnrollment och cancelEnrollment.
Högst 100 poster per sida, frågedjup 8, 20 rotfält och viktad komplexitet 2000. Dokument begränsas till 32 KiB och 5000 token. Introspektion är avstängd: använd det nedladdningsbara schemat.
STEG 5
Läs framsteg med GET /v1/enrollments/{id}/progress eller GraphQL
progress(id: …). Det kräver enrollments:read.
curl --fail-with-body --silent --show-error \
"$API_BASE_URL/v1/enrollments/$ENROLLMENT_ID/progress" \
-H "Authorization: Bearer $ACCESS_TOKEN"
Svaret innehåller state, percentComplete och
completedAt. Null betyder att uppgiften inte är registrerad. Tilldelningens
status: active betyder inte i sig att kursen är slutförd.
Slutföranden läses via GET /v1/completions eller GraphQL
completions med completions:read. Intyg läses via REST
/v1/certificates med certificates:read.
Listor returnerar data och nextCursor. Börja med
limit=25 och fortsätt med nästa cursor tills den är null. En tom sida kan
fortfarande ha en nästa cursor. URL-koda cursorvärdet i REST.
STEG 6
Skapa en HTTPS-mottagare och registrera den under
Inställningar → Integrationer eller med POST /v1/webhooks.
Det kräver webhooks:manage.
{
"url": "https://ert-system.example/hooks/eduvo",
"events": ["course.completed"]
}
X-Eduvo-Signature, i formatet sha256=<hex>, med en
jämförelse som tar konstant tid.
X-Eduvo-Timestamp och avvisa gamla leveranser enligt er
tidsgräns. Deduplicera med X-Eduvo-Delivery. Svara 2xx när händelsen
säkert tagits emot.
API-prenumerationer stöder user.created, user.updated,
enrollment.created, enrollment.cancelled,
course.started, course.completed och
certificate.issued.
Leveranser kan komma flera gånger. Efter ett misslyckat försök görs återförsök efter 5 minuter, 30 minuter, 2 timmar, 12 timmar och 24 timmar. Ping med HTTP 202 betyder att leveransen köats, inte att den nått mottagaren. Webhook-dispatchern måste vara konfigurerad i er miljö.
Matcha på vald identifierare, spara Eduvos interna ID och tilldela rätt publicerad kurs. Synka ändringar när de sker i källsystemet.
Använd skyddade HTTP-anrop för token, deltagare och kurstilldelning. Förvara hemligheter i en godkänd anslutning eller hemlighetslagring.
Välj REST för resurser eller GraphQL för att styra svarens fält. Kör kopplingen på serversidan; klienthemligheter hör inte hemma i webbläsarkod.
Använd samma Idempotency-Key för samma logiska skrivning med samma indata.
Byt nyckel för en ny ändring. Stödet gäller deltagarskrivningar samt skapande och
avbrytande av tilldelningar; anta inte att webhook-administrationsanrop dedupliceras av
headern.
| Fel | Åtgärd |
|---|---|
401 · unauthorized |
Kontrollera token, utgångstid och om klienten har återkallats. |
403 · insufficient_scope |
Tilldela och begär rätt scope för operationen. |
identifier_required |
Skicka organisationens valda identifierare. |
409 · identifier_conflict |
Kontrollera vilken deltagare som redan har värdet. Slå inte ihop personer automatiskt. |
409 · idempotency_conflict |
Nyckeln har använts med andra indata. Kontrollera om det är en ny ändring. |
| 429 eller tillfälligt 5xx | Försök igen med ökande väntetid och slumpmässig spridning. Behåll nyckeln för samma skrivning. |
query_too_complex |
Minska GraphQL-frågans fält, sidstorlek eller antal rotfält. |
Hastighetsgränsen är 120 begäranden per minut per klient och en separat gräns för
IP-adressen. REST-fel har error.code och requestId. GraphQL
använder errors[].extensions.code och kan returnera fel även med HTTP 200.
Kontrollera alltid både HTTP-status och svarskropp.
Spara begärans-ID från X-Request-Id, tidpunkt, status och felkod vid
felsökning. Undvik token, klienthemligheter och personuppgifter i loggar.
Ladda ned kontraktet för att kontrollera tillgängliga fält. API-adressen i OpenAPI är en platshållare som ska ersättas med er miljös adress.
Läser API-referensen…