Developers
Wislab API
Connect your academy to your systems: sync people from your HR system or CRM, read courses, progress, certificates, enrollments and payments, and send leads to your CRM.
- Base URL
https://wislab.app/api/v1- Version
v1 · 1.0.0
The API comes with the Cohorts and Enterprise plans.
Introduction
The Wislab API is REST: resource URLs, JSON in requests and responses, and standard HTTP status codes.
Every request acts on one academy: the one your API key belongs to. The academy never goes in the URL.
The full contract is in OpenAPI 3.0. Import it into Postman, Insomnia or your client generator.
https://wislab.app/api/v1Authentication
- 1In your academy's admin, go to Settings > Integrations > API keys. Only the owner or an admin can create one.
- 2Pick the scopes your integration needs. The key is shown only once: store it in your secrets manager.
- 3Send the key in the
Authorization: Bearerheader of every request.
Your key is a secret
Use it only from your server. Never put it in a browser, a mobile app or a repository. If it leaks, revoke it from the same screen and create a new one.
curl https://wislab.app/api/v1/academy \
-H "Authorization: Bearer $WISLAB_API_KEY"Scopes
Each key carries only the scopes you gave it. Use one key per integration so you can revoke one without touching the rest.
| Scope | What it allows |
|---|---|
users:read | Read the academy's people and their profile. |
users:sync | Create, update and deactivate people from your system. |
courses:read | Read the course catalog. |
progress:read | Read each person's progress in their courses. |
completions:read | Read who finished each course and when. |
certificates:read | Read issued certificates. |
bootcamps:read | Read bootcamps: dates, prices and seats. |
enrollments:read | Read who is enrolled in each bootcamp. |
payments:read | Read course and workshop purchases, and receipts. |
crm:read | Read CRM contacts and deals. |
crm:write | Create and update CRM contacts. |
fields:read | Read custom fields and their values. |
fields:write | Write custom field values. |
GET /academy needs no scope: any valid key can read it.
{
"error": "FORBIDDEN",
"message": "API key lacks required scope: users:read."
}Pagination
List endpoints take page (starting at 0) and limit (20 by default, up to 100).
The response has data with the results, plus total, page and pageCount. Keep requesting pages until page reaches pageCount - 1.
curl "https://wislab.app/api/v1/courses?page=1&limit=50" \
-H "Authorization: Bearer $WISLAB_API_KEY"{
"data": [
"…"
],
"total": 132,
"page": 1,
"pageCount": 3
}Errors
An error responds with an HTTP status and a JSON body with error (a stable code you can branch on), message and sometimes details.
| Code | HTTP | What it means |
|---|---|---|
VALIDATION_ERROR | 400 | A parameter or the body is invalid. details says which. |
UNKNOWN_FIELD | 400 | You wrote a custom field that has no definition. |
LIMIT_REACHED | 400 | The academy reached a limit of its plan. |
UNAUTHORIZED | 401 | The API key is missing, malformed or revoked. |
FORBIDDEN | 403 | The key lacks the scope, or the plan doesn't include the API. |
NAMESPACE_FORBIDDEN | 403 | You tried to write fields in another namespace. |
NOT_FOUND | 404 | The resource doesn't exist in this academy. |
CONFLICT | 409 | A resource with that key already exists. |
CRM_DISABLED | 409 | The academy has the CRM turned off. |
RATE_LIMITED | 429 | You hit the rate limit. Wait Retry-After seconds. |
INTERNAL | 500 | Something failed on our side. Retry in a few seconds. |
{
"error": "VALIDATION_ERROR",
"details": {
"errors": [],
"properties": {
"limit": {
"errors": [
"Too small: expected number to be >=1"
]
}
}
}
}Rate limits
Each key can make 120 requests per minute. Over that you get 429 RATE_LIMITED with a Retry-After header: wait that many seconds and retry.
HTTP/1.1 429 Too Many Requests
Retry-After: 18
{ "error": "RATE_LIMITED", "message": "Rate limit exceeded." }Reference
Academy
The academy behind the key or token.
/v1/academyRetrieve the academy
Needs no scope: any valid API key or installation token can read it. Name, slug, domain, languages, currency, plan and brand; never people.
Scope:No scope
Responses
- 200The academy.
- 401Missing, malformed or revoked API key.
- 403The key lacks the required scope, or the academy's plan doesn't include the API.
- 429Rate limit exceeded. Wait
Retry-Afterseconds.
curl https://wislab.app/api/v1/academy \
-H "Authorization: Bearer $WISLAB_API_KEY"{
"data": {
"id": "clx8k2m0p0001",
"name": "Academia Ejemplo",
"slug": "fundamentos-de-fotografia",
"domain": "string",
"url": "https://academia.example.com",
"defaultLocale": "string",
"supportedLocales": [
"string"
],
"currency": "USD",
"package": "string",
"logoUrl": "https://academia.example.com",
"primaryColor": "string"
}
}Reference
Users
People in the academy, and sync from your systems.
/v1/usersList users
Requires the users:read scope.
Scope:users:read
Query parameters
pageintegeroptionalPage number, starting at 0.
limitintegeroptionalPage size, up to 100.
rolestringoptionalFilter by role.
One of:
owner,admin,manager,teacher,moderator,studentsearchstringoptionalSearch first name, last name and email.
Responses
- 200A page of users.
- 400Invalid query parameters (see
details). - 401Missing, malformed or revoked API key.
- 403The key lacks the required scope, or the academy's plan doesn't include the API.
- 429Rate limit exceeded. Wait
Retry-Afterseconds.
curl https://wislab.app/api/v1/users \
-H "Authorization: Bearer $WISLAB_API_KEY"{
"data": [
{
"id": "clx8k2m0p0001",
"email": "ana@example.com",
"firstName": "Ana",
"lastName": "García",
"username": "anagarcia",
"role": "owner",
"isBanned": false,
"createdAt": "2026-10-27T15:00:00.000Z"
}
],
"total": 1,
"page": 0,
"pageCount": 1
}/v1/users/{id}Retrieve a user
Requires the users:read scope.
Scope:users:read
Path parameters
idstringrequiredThe user's ID.
Responses
- 200The user.
- 401Missing, malformed or revoked API key.
- 403The key lacks the required scope, or the academy's plan doesn't include the API.
- 404No user with that ID in this academy.
- 429Rate limit exceeded. Wait
Retry-Afterseconds.
curl https://wislab.app/api/v1/users/clx8k2m0p0001 \
-H "Authorization: Bearer $WISLAB_API_KEY"{
"data": {
"id": "clx8k2m0p0001",
"email": "ana@example.com",
"firstName": "Ana",
"lastName": "García",
"username": "anagarcia",
"role": "owner",
"isBanned": false,
"createdAt": "2026-10-27T15:00:00.000Z"
}
}/v1/users/syncSync users
Creates, updates and deactivates students from your HR system or CRM, up to 500 per request. Idempotent by email. status: inactive deactivates (reversible). It only manages students: an email that belongs to a team member is reported as skipped. Requires the users:sync scope.
Scope:users:sync
Body
usersobject[]requiredemailstringrequiredexternalIdstringoptionalThe ID in your source system (employee ID, tax ID). Stored in the user's metadata.
firstNamestringoptionallastNamestringoptionalrolestringoptionalOne of:
studentstatusstringoptionalinactivedeactivates the user (reversible) and keeps their history.One of:
active,inactive
optionsobjectoptionaldryRunbooleanoptionalValidate and report without writing anything.
sendWelcomeEmailbooleanoptional
Responses
- 200The sync result.
- 400Invalid body (see
details). - 401Missing, malformed or revoked API key.
- 403The key lacks the required scope, or the academy's plan doesn't include the API.
- 429Rate limit exceeded. Wait
Retry-Afterseconds.
curl -X POST https://wislab.app/api/v1/users/sync \
-H "Authorization: Bearer $WISLAB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"users": [
{
"email": "ana@example.com",
"externalId": "EMP-1042",
"firstName": "Ana",
"lastName": "García",
"role": "student",
"status": "active"
}
],
"options": {
"dryRun": false,
"sendWelcomeEmail": false
}
}'{
"data": {
"processed": 1,
"created": 1,
"updated": 1,
"deactivated": 1,
"skipped": 1,
"dryRun": false,
"errors": [
{
"index": 1,
"email": "ana@example.com",
"reason": "Invalid email."
}
],
"importLogId": "clx8k2m0p0002"
}
}Reference
Courses
The course catalog.
/v1/coursesList courses
Requires the courses:read scope.
Scope:courses:read
Query parameters
pageintegeroptionalPage number, starting at 0.
limitintegeroptionalPage size, up to 100.
isPublishedstringoptionalFilter by publication status.
One of:
true,false
Responses
- 200A page of courses.
- 400Invalid query parameters (see
details). - 401Missing, malformed or revoked API key.
- 403The key lacks the required scope, or the academy's plan doesn't include the API.
- 429Rate limit exceeded. Wait
Retry-Afterseconds.
curl https://wislab.app/api/v1/courses \
-H "Authorization: Bearer $WISLAB_API_KEY"{
"data": [
{
"id": "clx8k2m0p0001",
"title": "Fundamentos de fotografía",
"slug": "fundamentos-de-fotografia",
"description": null,
"courseType": "course",
"level": "basic",
"monetizationType": "free",
"priceInCents": 4900,
"currency": "USD",
"isPublished": true,
"totalCapsules": 1,
"createdAt": "2026-10-27T15:00:00.000Z"
}
],
"total": 1,
"page": 0,
"pageCount": 1
}Reference
Progress
Student progress.
/v1/users/{id}/progressRetrieve a user's progress
Progress per course. Requires the progress:read scope.
Scope:progress:read
Path parameters
idstringrequiredThe user's ID.
Responses
- 200The user's progress per course.
- 401Missing, malformed or revoked API key.
- 403The key lacks the required scope, or the academy's plan doesn't include the API.
- 404No user with that ID in this academy.
- 429Rate limit exceeded. Wait
Retry-Afterseconds.
curl https://wislab.app/api/v1/users/clx8k2m0p0001/progress \
-H "Authorization: Bearer $WISLAB_API_KEY"{
"data": {
"userId": "clx8k2m0p0002",
"lessonsCompletedTotal": 1,
"courses": [
{
"courseId": "clx8k2m0p0002",
"percentageProgress": 60,
"isEnrolled": true,
"updatedAt": "2026-10-27T15:00:00.000Z"
}
]
}
}Reference
Completions
Completed courses.
/v1/completionsList completions
Courses a student finished at 100%. Requires the completions:read scope.
Scope:completions:read
Query parameters
pageintegeroptionalPage number, starting at 0.
limitintegeroptionalPage size, up to 100.
fromdatetimeoptionalInclusive ISO 8601 date-time, compared with the completion date.
todatetimeoptionalInclusive ISO 8601 date-time.
Responses
- 200A page of completions.
- 400Invalid query parameters (see
details). - 401Missing, malformed or revoked API key.
- 403The key lacks the required scope, or the academy's plan doesn't include the API.
- 429Rate limit exceeded. Wait
Retry-Afterseconds.
curl https://wislab.app/api/v1/completions \
-H "Authorization: Bearer $WISLAB_API_KEY"{
"data": [
{
"userId": "clx8k2m0p0002",
"courseId": "clx8k2m0p0002",
"completedAt": "2026-10-27T15:00:00.000Z",
"certificateId": "clx8k2m0p0002"
}
],
"total": 1,
"page": 0,
"pageCount": 1
}Reference
Certificates
Issued certificates.
/v1/certificatesList certificates
Requires the certificates:read scope.
Scope:certificates:read
Query parameters
pageintegeroptionalPage number, starting at 0.
limitintegeroptionalPage size, up to 100.
statusstringoptionalFilter by status.
One of:
active,revokeduserIdstringoptionalFilter by user.
Responses
- 200A page of certificates.
- 400Invalid query parameters (see
details). - 401Missing, malformed or revoked API key.
- 403The key lacks the required scope, or the academy's plan doesn't include the API.
- 429Rate limit exceeded. Wait
Retry-Afterseconds.
curl https://wislab.app/api/v1/certificates \
-H "Authorization: Bearer $WISLAB_API_KEY"{
"data": [
{
"id": "clx8k2m0p0001",
"userId": "clx8k2m0p0002",
"courseId": "clx8k2m0p0002",
"pathId": "clx8k2m0p0002",
"bootcampId": "clx8k2m0p0002",
"programId": "clx8k2m0p0002",
"credentialCode": "WSL-7F3K-2Q9P",
"issuedAt": "2026-10-27T15:00:00.000Z",
"expiresAt": "2026-10-27T15:00:00.000Z",
"status": "active",
"certificateUrl": "https://academia.example.com/certificates/WSL-7F3K-2Q9P",
"recipientName": "Ana García"
}
],
"total": 1,
"page": 0,
"pageCount": 1
}Reference
Bootcamps
The academy's bootcamps.
/v1/bootcampsList bootcamps
Requires the bootcamps:read scope.
Scope:bootcamps:read
Query parameters
pageintegeroptionalPage number, starting at 0.
limitintegeroptionalPage size, up to 100.
isListedstringoptionalFilter by catalog visibility.
One of:
true,falseisActivestringoptionalFilter by active status.
One of:
true,false
Responses
- 200A page of bootcamps.
- 400Invalid query parameters (see
details). - 401Missing, malformed or revoked API key.
- 403The key lacks the required scope, or the academy's plan doesn't include the API.
- 429Rate limit exceeded. Wait
Retry-Afterseconds.
curl https://wislab.app/api/v1/bootcamps \
-H "Authorization: Bearer $WISLAB_API_KEY"{
"data": [
{
"id": "clx8k2m0p0001",
"title": "Fundamentos de fotografía",
"slug": "fundamentos-de-fotografia",
"cohortStartDate": "2026-10-27T15:00:00.000Z",
"cohortEndDate": "2026-10-27T15:00:00.000Z",
"enrollmentDeadline": null,
"isFree": false,
"regularPrice": 1,
"earlyBirdPrice": 1,
"currency": "USD",
"maxStudents": 1,
"isActive": true,
"isEnrollmentOpen": false,
"isListed": true,
"createdAt": "2026-10-27T15:00:00.000Z"
}
],
"total": 1,
"page": 0,
"pageCount": 1
}Reference
Enrollments
Bootcamp enrollments.
/v1/enrollmentsList bootcamp enrollments
Requires the enrollments:read scope.
Scope:enrollments:read
Query parameters
pageintegeroptionalPage number, starting at 0.
limitintegeroptionalPage size, up to 100.
bootcampIdstringoptionalFilter by bootcamp.
userIdstringoptionalFilter by user.
statusstringoptionalFilter by status.
One of:
active,expired,completed,refunded,removed
Responses
- 200A page of enrollments.
- 400Invalid query parameters (see
details). - 401Missing, malformed or revoked API key.
- 403The key lacks the required scope, or the academy's plan doesn't include the API.
- 429Rate limit exceeded. Wait
Retry-Afterseconds.
curl https://wislab.app/api/v1/enrollments \
-H "Authorization: Bearer $WISLAB_API_KEY"{
"data": [
{
"id": "clx8k2m0p0001",
"userId": "clx8k2m0p0002",
"bootcampId": "clx8k2m0p0002",
"status": "active",
"enrollmentDate": "2026-10-27T15:00:00.000Z",
"amount": 490,
"currency": "USD",
"isManualAssignment": false,
"createdAt": "2026-10-27T15:00:00.000Z"
}
],
"total": 1,
"page": 0,
"pageCount": 1
}Reference
Payments
Course and workshop purchases, and payment receipts.
/v1/paymentsList course and workshop purchases
Requires the payments:read scope.
Scope:payments:read
Query parameters
pageintegeroptionalPage number, starting at 0.
limitintegeroptionalPage size, up to 100.
kindstringoptionalFilter by what was bought.
One of:
course,workshopuserIdstringoptionalFilter by user.
statusstringoptionalFilter by status.
Responses
- 200A page of purchases.
- 400Invalid query parameters (see
details). - 401Missing, malformed or revoked API key.
- 403The key lacks the required scope, or the academy's plan doesn't include the API.
- 429Rate limit exceeded. Wait
Retry-Afterseconds.
curl https://wislab.app/api/v1/payments \
-H "Authorization: Bearer $WISLAB_API_KEY"{
"data": [
{
"id": "clx8k2m0p0001",
"kind": "course",
"itemId": "clx8k2m0p0002",
"userId": "clx8k2m0p0002",
"amount": 490,
"currency": "USD",
"status": "active",
"stripeSessionId": "cs_live_a1B2c3D4",
"refundedAt": "2026-10-27T15:00:00.000Z",
"createdAt": "2026-10-27T15:00:00.000Z"
}
],
"total": 1,
"page": 0,
"pageCount": 1
}/v1/payments/receiptsList payment receipts
Requires the payments:read scope.
Scope:payments:read
Query parameters
pageintegeroptionalPage number, starting at 0.
limitintegeroptionalPage size, up to 100.
userIdstringoptionalFilter by user.
enrollmentIdstringoptionalFilter by enrollment.
paymentStatusstringoptionalFilter by payment status.
Responses
- 200A page of receipts.
- 400Invalid query parameters (see
details). - 401Missing, malformed or revoked API key.
- 403The key lacks the required scope, or the academy's plan doesn't include the API.
- 429Rate limit exceeded. Wait
Retry-Afterseconds.
curl https://wislab.app/api/v1/payments/receipts \
-H "Authorization: Bearer $WISLAB_API_KEY"{
"data": [
{
"id": "clx8k2m0p0001",
"userId": "clx8k2m0p0002",
"enrollmentId": "clx8k2m0p0002",
"programEnrollmentId": "clx8k2m0p0002",
"amount": 490,
"currency": "USD",
"paymentStatus": "paid",
"paymentMethod": "card",
"paidAt": "2026-10-27T15:00:00.000Z",
"description": null,
"isRefunded": false,
"isCancelled": false,
"createdAt": "2026-10-27T15:00:00.000Z"
}
],
"total": 1,
"page": 0,
"pageCount": 1
}Reference
CRM
CRM contacts and deals.
/v1/crm/contactsList CRM contacts
Requires the crm:read scope.
Scope:crm:read
Query parameters
pageintegeroptionalPage number, starting at 0.
limitintegeroptionalPage size, up to 100.
lifecycleStagestringoptionalFilter by funnel stage.
sourcestringoptionalFilter by source.
updatedAfterdatetimeoptionalOnly contacts updated after this ISO 8601 date-time.
Responses
- 200A page of contacts.
- 400Invalid query parameters (see
details). - 401Missing, malformed or revoked API key.
- 403The key lacks the required scope, or the academy's plan doesn't include the API.
- 429Rate limit exceeded. Wait
Retry-Afterseconds.
curl https://wislab.app/api/v1/crm/contacts \
-H "Authorization: Bearer $WISLAB_API_KEY"{
"data": [
{
"id": "clx8k2m0p0001",
"email": "ana@example.com",
"phone": "+52 55 0000 0000",
"firstName": "Ana",
"lastName": "García",
"jobTitle": null,
"lifecycleStage": "SUBSCRIBER",
"source": "SIGNUP",
"sourceDetail": "Formulario del taller",
"score": 1,
"companyId": "clx8k2m0p0002",
"tenantUserId": "clx8k2m0p0002",
"lastContactedAt": "2026-10-27T15:00:00.000Z",
"createdAt": "2026-10-27T15:00:00.000Z",
"updatedAt": "2026-10-27T15:00:00.000Z"
}
],
"total": 1,
"page": 0,
"pageCount": 1
}/v1/crm/contactsCreate or update a CRM contact
Goes through the same intake as the academy's forms: dedupes by email, the funnel stage only moves forward, opens a deal if the academy creates them automatically, and emits lead.created when the contact is new. 201 when new, 200 when it already existed. 409 CRM_DISABLED when the academy has the CRM off. Requires the crm:write scope.
Scope:crm:write
Body
emailstringrequiredfirstNamestring | nulloptionallastNamestring | nulloptionalphonestring | nulloptionalsourcestringoptionalHow the person arrived. Kept from the first time the contact was seen.
One of:
SIGNUP,NEWSLETTER,WAITLIST,CONTACT_FORM,DEMO_REQUEST,COURSE_ENROLLMENT,MANUAL,IMPORT,OTHERsourceDetailstring | nulloptionalFree text about the origin, e.g. the form or campaign name.
lifecycleStagestringoptionalAn existing contact only moves forward in the funnel.
One of:
SUBSCRIBER,LEAD,MQL,SQL,OPPORTUNITY,CUSTOMER,EVANGELIST,OTHER
Responses
- 200The contact already existed and was updated.
- 201Contact created.
- 400Invalid body (see
details). - 401Missing, malformed or revoked API key.
- 403The key lacks the required scope, or the academy's plan doesn't include the API.
- 409The academy has the CRM off.
- 429Rate limit exceeded. Wait
Retry-Afterseconds.
curl -X POST https://wislab.app/api/v1/crm/contacts \
-H "Authorization: Bearer $WISLAB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "ana@example.com",
"firstName": "Ana",
"lastName": "García",
"phone": "+52 55 0000 0000",
"source": "OTHER",
"sourceDetail": "Formulario del taller",
"lifecycleStage": "LEAD"
}'{
"data": {
"id": "clx8k2m0p0001",
"email": "ana@example.com",
"phone": "+52 55 0000 0000",
"firstName": "Ana",
"lastName": "García",
"jobTitle": null,
"lifecycleStage": "SUBSCRIBER",
"source": "SIGNUP",
"sourceDetail": "Formulario del taller",
"score": 1,
"companyId": "clx8k2m0p0002",
"tenantUserId": "clx8k2m0p0002",
"lastContactedAt": "2026-10-27T15:00:00.000Z",
"createdAt": "2026-10-27T15:00:00.000Z",
"updatedAt": "2026-10-27T15:00:00.000Z"
}
}/v1/crm/dealsList CRM deals
Requires the crm:read scope.
Scope:crm:read
Query parameters
pageintegeroptionalPage number, starting at 0.
limitintegeroptionalPage size, up to 100.
statusstringoptionalFilter by status.
One of:
OPEN,WON,LOSTpipelineIdstringoptionalFilter by pipeline.
contactIdstringoptionalFilter by contact.
Responses
- 200A page of deals.
- 400Invalid query parameters (see
details). - 401Missing, malformed or revoked API key.
- 403The key lacks the required scope, or the academy's plan doesn't include the API.
- 429Rate limit exceeded. Wait
Retry-Afterseconds.
curl https://wislab.app/api/v1/crm/deals \
-H "Authorization: Bearer $WISLAB_API_KEY"{
"data": [
{
"id": "clx8k2m0p0001",
"title": "Fundamentos de fotografía",
"pipelineId": "clx8k2m0p0002",
"stageId": "clx8k2m0p0003",
"status": "OPEN",
"valueCents": 4900,
"currency": "USD",
"contactId": "clx8k2m0p0002",
"companyId": "clx8k2m0p0002",
"expectedCloseDate": "2026-10-27T15:00:00.000Z",
"wonAt": "2026-10-27T15:00:00.000Z",
"lostAt": "2026-10-27T15:00:00.000Z",
"createdAt": "2026-10-27T15:00:00.000Z",
"updatedAt": "2026-10-27T15:00:00.000Z"
}
],
"total": 1,
"page": 0,
"pageCount": 1
}Reference
Custom fields
Custom fields on courses, bootcamps and paths, and their values.
/v1/fieldsList custom field definitions
Includes the academy's fields (academy) and those of each installed app (app--<handle>). Requires the fields:read scope.
Scope:fields:read
Query parameters
pageintegeroptionalPage number, starting at 0.
limitintegeroptionalPage size, up to 100.
entitystringoptionalFilter by entity.
One of:
course,bootcamp,path
Responses
- 200A page of definitions.
- 400Invalid query parameters (see
details). - 401Missing, malformed or revoked API key.
- 403The key lacks the required scope, or the academy's plan doesn't include the API.
- 429Rate limit exceeded. Wait
Retry-Afterseconds.
curl https://wislab.app/api/v1/fields \
-H "Authorization: Bearer $WISLAB_API_KEY"{
"data": [
{
"id": "clx8k2m0p0001",
"entity": "course",
"namespace": "academy",
"key": "level",
"fieldId": "academy:level",
"type": "text",
"label": {
"en": "Level",
"es": "Nivel"
},
"options": [
{
"value": "string",
"label": "string"
}
],
"order": 1,
"createdAt": "2026-10-27T15:00:00.000Z"
}
],
"total": 1,
"page": 0,
"pageCount": 1
}/v1/fieldsDeclare an app field
Only with an external app's installation token: the field is created in that app's app--<handle> namespace. An academy API key gets 403; the academy defines its own fields in Admin > Custom fields. Requires the fields:write scope.
Scope:fields:write
Body
entitystringrequiredOne of:
course,bootcamp,pathkeystringrequiredtypestringrequiredOne of:
text,number,boolean,select,url,datelabelobjectrequiredoptionsobject[]optionalvaluestringrequiredlabelstringrequired
orderintegeroptional
Responses
- 201The new definition.
- 400Invalid body (see
details). - 401Missing, malformed or revoked API key.
- 403The key lacks the required scope, or the academy's plan doesn't include the API.
- 409A field with that key already exists for that entity.
- 429Rate limit exceeded. Wait
Retry-Afterseconds.
curl -X POST https://wislab.app/api/v1/fields \
-H "Authorization: Bearer $WISLAB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"entity": "course",
"key": "level",
"type": "text",
"label": {
"en": "Level",
"es": "Nivel"
},
"options": [
{
"value": "string",
"label": "string"
}
],
"order": 1
}'{
"data": {
"id": "clx8k2m0p0001",
"entity": "course",
"namespace": "academy",
"key": "level",
"fieldId": "academy:level",
"type": "text",
"label": {
"en": "Level",
"es": "Nivel"
},
"options": [
{
"value": "string",
"label": "string"
}
],
"order": 1,
"createdAt": "2026-10-27T15:00:00.000Z"
}
}/v1/courses/{id}/fieldsGet a course's custom field values
Returns fields keyed namespace:key. Requires the fields:read scope.
Scope:fields:read
Path parameters
idstringrequiredThe ID.
Responses
- 200The values.
- 401Missing, malformed or revoked API key.
- 403The key lacks the required scope, or the academy's plan doesn't include the API.
- 404No course with that ID in this academy.
- 429Rate limit exceeded. Wait
Retry-Afterseconds.
curl https://wislab.app/api/v1/courses/clx8k2m0p0001/fields \
-H "Authorization: Bearer $WISLAB_API_KEY"{
"data": {
"id": "clx8k2m0p0001",
"entity": "course",
"fields": {
"academy:level": "intermediate"
}
}
}/v1/courses/{id}/fieldsUpdate a course's custom field values
An academy API key writes only the academy namespace; an app installation token writes only its own app--<handle> (otherwise 403 NAMESPACE_FORBIDDEN). null clears a value; a field with no definition returns 400 UNKNOWN_FIELD. Requires the fields:write scope.
Scope:fields:write
Path parameters
idstringrequiredThe ID.
Body
fieldsobjectrequired
Responses
- 200The values after the change.
- 400Invalid body, unknown field or wrong value type (see
details). - 401Missing, malformed or revoked API key.
- 403The key lacks the required scope, or the academy's plan doesn't include the API.
- 404No course with that ID in this academy.
- 429Rate limit exceeded. Wait
Retry-Afterseconds.
curl -X PATCH https://wislab.app/api/v1/courses/clx8k2m0p0001/fields \
-H "Authorization: Bearer $WISLAB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"fields": {
"academy:level": "intermediate"
}
}'{
"data": {
"id": "clx8k2m0p0001",
"entity": "course",
"fields": {
"academy:level": "intermediate"
}
}
}/v1/bootcamps/{id}/fieldsGet a bootcamp's custom field values
Returns fields keyed namespace:key. Requires the fields:read scope.
Scope:fields:read
Path parameters
idstringrequiredThe ID.
Responses
- 200The values.
- 401Missing, malformed or revoked API key.
- 403The key lacks the required scope, or the academy's plan doesn't include the API.
- 404No bootcamp with that ID in this academy.
- 429Rate limit exceeded. Wait
Retry-Afterseconds.
curl https://wislab.app/api/v1/bootcamps/clx8k2m0p0001/fields \
-H "Authorization: Bearer $WISLAB_API_KEY"{
"data": {
"id": "clx8k2m0p0001",
"entity": "course",
"fields": {
"academy:level": "intermediate"
}
}
}/v1/bootcamps/{id}/fieldsUpdate a bootcamp's custom field values
An academy API key writes only the academy namespace; an app installation token writes only its own app--<handle> (otherwise 403 NAMESPACE_FORBIDDEN). null clears a value; a field with no definition returns 400 UNKNOWN_FIELD. Requires the fields:write scope.
Scope:fields:write
Path parameters
idstringrequiredThe ID.
Body
fieldsobjectrequired
Responses
- 200The values after the change.
- 400Invalid body, unknown field or wrong value type (see
details). - 401Missing, malformed or revoked API key.
- 403The key lacks the required scope, or the academy's plan doesn't include the API.
- 404No bootcamp with that ID in this academy.
- 429Rate limit exceeded. Wait
Retry-Afterseconds.
curl -X PATCH https://wislab.app/api/v1/bootcamps/clx8k2m0p0001/fields \
-H "Authorization: Bearer $WISLAB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"fields": {
"academy:level": "intermediate"
}
}'{
"data": {
"id": "clx8k2m0p0001",
"entity": "course",
"fields": {
"academy:level": "intermediate"
}
}
}/v1/paths/{id}/fieldsGet a path's custom field values
Returns fields keyed namespace:key. Requires the fields:read scope.
Scope:fields:read
Path parameters
idstringrequiredThe ID.
Responses
- 200The values.
- 401Missing, malformed or revoked API key.
- 403The key lacks the required scope, or the academy's plan doesn't include the API.
- 404No path with that ID in this academy.
- 429Rate limit exceeded. Wait
Retry-Afterseconds.
curl https://wislab.app/api/v1/paths/clx8k2m0p0001/fields \
-H "Authorization: Bearer $WISLAB_API_KEY"{
"data": {
"id": "clx8k2m0p0001",
"entity": "course",
"fields": {
"academy:level": "intermediate"
}
}
}/v1/paths/{id}/fieldsUpdate a path's custom field values
An academy API key writes only the academy namespace; an app installation token writes only its own app--<handle> (otherwise 403 NAMESPACE_FORBIDDEN). null clears a value; a field with no definition returns 400 UNKNOWN_FIELD. Requires the fields:write scope.
Scope:fields:write
Path parameters
idstringrequiredThe ID.
Body
fieldsobjectrequired
Responses
- 200The values after the change.
- 400Invalid body, unknown field or wrong value type (see
details). - 401Missing, malformed or revoked API key.
- 403The key lacks the required scope, or the academy's plan doesn't include the API.
- 404No path with that ID in this academy.
- 429Rate limit exceeded. Wait
Retry-Afterseconds.
curl -X PATCH https://wislab.app/api/v1/paths/clx8k2m0p0001/fields \
-H "Authorization: Bearer $WISLAB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"fields": {
"academy:level": "intermediate"
}
}'{
"data": {
"id": "clx8k2m0p0001",
"entity": "course",
"fields": {
"academy:level": "intermediate"
}
}
}Missing an endpoint?
Tell us what you want to integrate and we'll look at it with you.