# API reference All paths are relative to `https://`. This page is the complete client-facing route inventory covered by this guide. ## Discovery API These 14 endpoints accept an authenticated user or the server-side `clientapisecret`, except where the identity column states both are required. | Method | Endpoint | Purpose | Identity | | --- | --- | --- | --- | | `GET` | `/blendxapi/discovery/courses/` | List, search, filter, and order all published courses. | User or client secret | | `GET` | `/blendxapi/discovery/course/{openedx_course_id}/` | Get one course and its full or summary data. | User or client secret | | `GET` | `/blendxapi/discovery/course-outline/{openedx_course_id}/` | Get a course’s section and subsection outline. | User or client secret | | `POST` | `/blendxapi/discovery/courses/effort/` | Calculate effort for up to 50 course keys. | User or client secret | | `POST` | `/blendxapi/discovery/courses/is-new/` | Check new-course status for up to 100 course keys. | User or client secret | | `GET` | `/blendxapi/discovery/check-enrollment/{openedx_course_id}/` | Check the current learner’s enrollment and mode. | Learner session for a meaningful result | | `GET` | `/blendxapi/discovery/programs/` | List, search, filter, and order all published programs. | User or client secret | | `GET` | `/blendxapi/discovery/program/{program_id}/` | Get one program and its child courses. | User or client secret | | `GET` | `/blendxapi/discovery/tags/` | List tags and optionally their courses and programs. | User or client secret | | `GET` | `/blendxapi/discovery/organisations/` | List organisation identity and branding data. | User or client secret | | `GET` | `/blendxapi/discovery/marketing-page-metadata/` | Get organisation-defined marketing metadata. | User or client secret | | `GET` | `/blendxapi/discovery/user/` | Determine whether the forwarded LMS session is signed in. | Client secret; optional learner session | | `POST` | `/blendxapi/discovery/guest/checkout/` | Check out for an email address without an LMS session. | Client secret; signed-in users rejected | | `POST` | `/blendxapi/discovery/checkout/` | Check out for the signed-in learner. | Client secret and learner session | ## Related checkout and enrollment APIs | Method | Endpoint | Purpose | Identity | | --- | --- | --- | --- | | `POST` | `/blendxapi/payment/checkout/` | Process the signed-in learner’s existing server-side cart. | Learner session and `orgName` | | `GET` | `/blendxapi/payment/capabilities/` | Inspect the organisation’s payment capabilities. | Learner session and `orgName` | | `POST` | `/blendxapi/enrollments/client/enroll/` | Grant course access by learner email. | Client secret | | `POST` | `/blendxapi/enrollments/client/unenroll/` | Remove or cancel course access by learner email. | Client secret | Platform administration, deployment, internal triggers, and payment webhooks are operated by Blend-ed and are intentionally outside this client guide. ## Data guides - [Courses](/blendx-discovery/courses/) documents list and detail fields, outlines, effort, and enrollment checks. - [Programs](/blendx-discovery/programs/) documents program list and detail payloads and tag discovery. - [Organisations](/blendx-discovery/organisations/) documents organisation identity, branding, and marketing metadata. - [Checkout](/blendx-discovery/checkout/) and [Enrollment](/blendx-discovery/enrollment/) document request and response flows for commerce integrations. # Authentication Every client-facing route in this guide requires an accepted identity. A request without one receives `401`. ## Choose the correct credential | Credential | Intended caller | Where it is accepted | | --- | --- | --- | | Session cookie, JWT, or OAuth2 bearer token | Signed-in learner or staff client | User-facing routes, subject to each route’s permissions. | | `clientapisecret` | Trusted storefront backend, CRM, or partner service | `/blendxapi/discovery/`, `/blendxapi/enrollments/client/`, and `/blendxapi/banner/list/`. | An authenticated user can read most catalog endpoints without a client secret. Machine storefront calls use: ``` clientapisecret: ``` The configured value is compared in constant time and fails closed when it is empty. The credential is instance-wide and is not scoped to one organisation, course, or learner. > **Do not expose the client secret** > Keep `CLIENT_API_SECRET` in the storefront server or integration platform. Never send it to browser JavaScript, a mobile client, or a third-party user. ## Browser and server-side storefront calls Use a backend-for-frontend pattern: 1. The browser calls your storefront server. 2. Your server validates the public request and applies its own abuse controls. 3. Your server calls the LMS with `clientapisecret` . 4. Your server returns only the required response data. Forward a signed-in user’s session cookies only to endpoints that need learner identity. The authenticated discovery checkout requires both the client secret and the user’s LMS session. ## Organisation context Organisation-scoped learner and payment routes resolve the tenant from one of: ``` Cookie: orgName=acme ``` or, for the native mobile client: ``` orgName: acme ``` The value selects a tenant; it is not proof of access. Protected endpoints join it with the authenticated user’s organisation claims. Web integrations should prefer the cookie channel used by the learner web application. Catalog list and detail endpoints can span multiple organisations. Their regional pricing is resolved independently for each item’s owning organisation. ## Common authentication failures | Status | Cause | Action | | --- | --- | --- | | `401` | Missing or invalid user identity or machine credential. | Check the exact header name and configured secret. | | `403` | The user is authenticated but lacks access to the selected organisation or operation. | Check organisation membership and role permissions. | | `400 Organisation not found` | An organisation-scoped route cannot resolve `orgName`. | Set the expected tenant cookie or header. | Do not retry `401` or `403` responses without changing credentials or access. # Checkout BlendX supports 3 checkout entry points. All prices are calculated again on the server from published items and configured modes. Never send or trust a price from the browser. | Flow | Endpoint | Identity | | --- | --- | --- | | Guest storefront | `POST /blendxapi/discovery/guest/checkout/` | `clientapisecret`; authenticated users are rejected. | | Authenticated storefront | `POST /blendxapi/discovery/checkout/` | `clientapisecret` and the learner’s LMS session. | | Existing learner cart | `POST /blendxapi/payment/checkout/` | Authenticated learner plus `orgName` organisation context. | ## Choose guest or authenticated checkout The storefront can inspect the forwarded LMS session before choosing a flow: ``` GET /blendxapi/discovery/user/clientapisecret: Cookie: sessionid= ``` An active session returns `authenticated: true` with the user’s email, username, and name. A machine-authenticated request without a learner session returns: ``` {"authenticated": false} ``` ## Request items Guest and authenticated discovery checkout accept: ``` { "organisation_id": "organisation-uuid", "items": [ {"type": "course", "id": "course-uuid", "mode": "verified"}, {"type": "program", "id": "program-uuid", "mode": "honor"} ], "billing_address": { "name": "Amina Khan", "line1": "10 Market Street", "line2": "", "city": "Dubai", "state": "Dubai", "postal_code": "00000", "country": "AE" }} ``` `billing_address` is optional in the API shape but may be required by the configured payment provider or local payment rules. Item IDs are BlendX UUIDs, not Open edX `course-v1:` keys. Course modes must exist and be visible for purchase. Items must be published. ## Guest checkout Add `email` to the common request body: ``` curl -X POST "https:///blendxapi/discovery/guest/checkout/" \ -H "Content-Type: application/json" \ -H "clientapisecret: $BLENDX_CLIENT_API_SECRET" \ -d '{ "email": "learner@example.com", "organisation_id": "organisation-uuid", "items": [{"type":"course","id":"course-uuid","mode":"verified"}] }' ``` For a free basket, the response has `status: "free"`. An existing account is enrolled; an unknown email receives a registration link and its enrollment is held until registration with that address. For a paid basket, `status` is `success` and the response is gateway-specific: - Stripe: `client_secret` , `publishable_key` , and optionally `customer_session_client_secret` . - PayTabs: `redirect_url` and `payment_id` . - Razorpay or Geidea: `order_id` , `key_id` , and the amount in subunits as `amount` . All variants also return `gateway`, `total_price`, `currency`, and `items_detail`. Complete payment with the provider’s client integration. Access is granted only after a signed success webhook is processed. ## Authenticated discovery checkout Send the same body without `email`. Your server must forward the learner’s LMS session cookie and add `clientapisecret`: ``` POST /blendxapi/discovery/checkout/Content-Type: application/jsonCookie: sessionid=clientapisecret: ``` The server creates cart records before starting payment. If the learner already holds another course mode, checkout charges only the non-negative difference between the selected and current mode prices. Regional pricing is applied after that upgrade difference is calculated. A free basket returns `status: "free"` and queues the cart for enrollment without requiring payment-provider credentials. ## Learner-cart checkout decision Use this route when the learner already built a server-side cart: ``` POST /blendxapi/payment/checkout/Cookie: sessionid=; orgName=acme ``` The request has no price or item body. The server loads the cart for the signed-in user and selected organisation. A free cart returns: ``` { "status": "enrollment_pending", "total_price": 0, "currency": "usd", "redirect_url": "https:///blendxapi/payment/stripe/payment_status_free/"} ``` A paid cart returns `status: "payment_required"`, `gateway`, `total_price`, `currency`, and a gateway `redirect_url`. Open that URL to continue through the existing hosted payment flow. ## Inspect payment capabilities Use the signed-in learner’s organisation context to decide which payment UI to show: ``` GET /blendxapi/payment/capabilities/Cookie: sessionid=; orgName=acme ``` ``` { "gateway": "razorpay", "configured": true, "supports_subscriptions": true, "supports_billing_portal": false, "currency": "inr"} ``` `configured` reports whether the selected gateway has its required organisation credentials. Capability flags describe the gateway even when configuration is incomplete. ## Regional pricing Checkout resolves the visitor’s region once, applies the configured per-item discount, and records `region`, `discountPct`, and `originalPrice` with the transaction. The checkout total is authoritative even if catalog data was cached earlier. ## Production controls - Rate-limit guest checkout at the storefront edge by IP and, where practical, normalized email. - Verify payment webhooks and keep gateway secrets server-side. - Treat timeouts as unknown outcomes: query provider/payment state before creating another charge. - Use idempotency controls supplied by the configured gateway. - Monitor `400` , `401` , `429` , and webhook-processing failures separately. # Courses Catalog routes accept an authenticated user identity or a valid `clientapisecret`. Examples below use the server-side client credential. ## List courses ``` GET /blendxapi/discovery/courses/ ``` | Query parameter | Default | Description | | --- | --- | --- | | `limit` | `8` | Page size, clamped to 1–100. | | `page` | `1` | 1-indexed page number. | | `search` | empty | Search course name, short description, or overview. | | `org` | empty | Comma-separated organisation names. | | `tags` | empty | Comma-separated tags; a match on any tag is included. | | `order_by` | `created_at.desc` | `{field}.{direction}`, for example `display_name.asc`. | | `fields` | `light` | `light` for cards or `full` for all supported fields. | ``` curl "https:///blendxapi/discovery/courses/?search=safety&org=Acme&tags=compliance&order_by=display_name.asc" \ -H "clientapisecret: $BLENDX_CLIENT_API_SECRET" ``` The envelope contains `courses`, `total_count`, `has_more`, `limit`, `page`, and `offset`. If one item cannot be serialized, the request can still succeed and include `partial_errors`. ### Course list fields The default `light` fieldset contains every field below. | Field | Description | | --- | --- | | `id` | BlendX/Hasura course UUID used by checkout and client enrollment. | | `openedx_course_id` | Open edX course key used by detail, outline, effort, and enrollment-check routes. | | `display_name`, `display_image`, `short_description` | Course card content. | | `price`, `currency`, `course_mode` | Lowest visible mode price, currency, and mode. | | `originalPrice`, `discountPct` | Original price and applied regional discount. | | `nativeCurrency`, `nativeAmount` | Optional local-currency display hints. | | `start`, `end` | Course availability dates. | | `org`, `org_name` | Open edX organisation key and learner-facing organisation name. | | `org_logo_url`, `org_favicon_url` | Organisation branding URLs. | | `tags` | Assigned tag-name array. | | `is_invite_only`, `is_published` | Catalog visibility flags. | | `avg_rating`, `review_count` | Rating summary. | With `fields=full`, each list item also contains: | Field | Description | | --- | --- | | `overview` | Course overview HTML. | | `effort` | Configured course-effort value. | | `enrollment_start`, `enrollment_end` | Enrollment window. | | `certificate_available_date` | Certificate availability date. | | `has_any_active_web_certificate` | Whether an active web certificate is configured. | | `link_to_course` | Learner-dashboard course link. | | `language`, `self_paced`, `number` | Language, pacing flag, and course number. | | `course_video_url` | Course promotional video URL. | | `available_course_modes` | All visible purchase/enrollment modes. | | `is_new` | New-course status. | ## Regional price fields Catalog prices are evaluated under each item’s owning organisation policy: | Field | Meaning | | --- | --- | | `price` | Price after the applicable regional discount. | | `originalPrice` | Price before that discount. | | `discountPct` | Applied discount percentage, or `0`. | | `nativeCurrency` | Optional local-currency display hint. Omitted when unavailable. | | `nativeAmount` | Optional converted display amount. It is not the settlement amount. | Always use the checkout response as the authoritative amount to charge. ## Get course details ``` GET /blendxapi/discovery/course/{openedx_course_id}/ ``` The response contains the following fields: | Field | Description | | --- | --- | | `id`, `openedx_course_id` | BlendX UUID and Open edX course key. | | `display_name`, `short_description`, `overview` | Course copy; `overview` is HTML. | | `course_image_url`, `course_video_url` | Course media URLs. | | `start`, `start_display`, `end` | Course dates and display-ready start value. | | `effort`, `total_minutes` | Configured effort and computed content duration. | | `enrollment_start`, `enrollment_end` | Enrollment window. | | `certificate_available_date`, `has_any_active_web_certificate` | Certificate availability. | | `language`, `self_paced` | Language and pacing. | | `is_invite_only`, `is_published`, `is_new` | Catalog status flags. | | `price`, `course_mode`, `available_course_modes` | Lowest visible offer and all visible modes. | | `originalPrice`, `discountPct`, `nativeCurrency`, `nativeAmount` | Regional price fields; native fields are optional. | | `organisation`, `organisation_id` | Organisation short name and UUID. | | `organisation_logo_url`, `organisation_favicon_url` | Organisation branding URLs. | | `course_structure` | Hierarchical content structure, or `null` for `fields=summary`. | | `avg_rating`, `reviews` | Rating and review data. | Each entry in `available_course_modes` contains `modeSlug`, `minPrice`, `modeDisplayName`, `currency`, `expirationDatetime`, `visible`, `description`, `upsellableCourseModes`, and `hasCertificate`. Add `?fields=summary` to set `course_structure` to `null` and skip the effort traversal, so `total_minutes` is `0`: ``` curl "https:///blendxapi/discovery/course/course-v1%3AAcme%2BSAF101%2B2026_T1/?fields=summary" \ -H "clientapisecret: $BLENDX_CLIENT_API_SECRET" ``` The course-detail cache defaults to 300 seconds. Regional price fields are applied after the cached base response so one visitor’s location is not reused for another. > **Note** > The list uses `display_image`; the detail response uses `course_image_url`. Plan for this naming difference in a shared client model. ## Get an outline ``` GET /blendxapi/discovery/course-outline/{openedx_course_id}/ ``` The top level contains `sections`, `total_sections`, `total_subsections`, and `course_info`. - Each section contains `name` , `usage_key` , `hide_from_toc` , `visible_to_staff_only` , and `subsections` . - Each subsection contains `name` , `usage_key` , `inaccessible_after_due` , `hide_from_toc` , `visible_to_staff_only` , `exam` , and `units` . - Each unit contains `name` and `usage_key` . - `exam` , when present, contains `is_practice_exam` , `is_proctored_enabled` , and `is_time_limited` . - `course_info` contains `course_key` , `title` , `published_at` , `published_version` , `days_early_for_beta` , `entrance_exam_id` , `self_paced` , and `course_visibility` . This is catalog structure, not a learner-specific courseware-access response. ## Bulk effort and new-course status ``` POST /blendxapi/discovery/courses/effort/Content-Type: application/json {"course_ids":["course-v1:Acme+SAF101+2026_T1"]} ``` Returns a map from course key to `total_minutes`. Up to 50 IDs are processed; results are cached for 1 hour. ``` POST /blendxapi/discovery/courses/is-new/Content-Type: application/json {"course_ids":["course-v1:Acme+SAF101+2026_T1"]} ``` Returns a map from course key to boolean. Up to 100 IDs are processed. ## Check learner enrollment ``` GET /blendxapi/discovery/check-enrollment/{openedx_course_id}/ ``` With a valid learner session, the response identifies enrollment and the current mode: ``` {"enrolled": true, "mode": "honor"} ``` Without a learner identity, the route returns `{"enrolled": false}` even when the server-side storefront credential is valid. # Enrollment Use the client enrollment endpoints when payment happens outside Blend-ed. Call them from a trusted server after the external system has confirmed the payment or refund. Both routes require: ``` clientapisecret: Content-Type: application/json ``` ## Grant course access ``` POST /blendxapi/enrollments/client/enroll/ ``` ``` { "email": "learner@example.com", "course_id": "267ce96d-1454-4292-aa42-1a0487c7eaaa", "mode": "honor"} ``` | Field | Required | Description | | --- | --- | --- | | `email` | Yes | Learner email and the join key for pending registration. | | `course_id` | Yes | BlendX/Hasura course UUID returned by discovery. | | `mode` | Yes | Valid Open edX enrollment mode. | For an existing account: ``` { "message": "User enrolled successfully", "status": "success", "enrollment_state": "enrolled"} ``` For an email without an account: ``` { "message": "User has no account; auto-enrollment queued and registration email sent", "status": "success", "enrollment_state": "pending_registration"} ``` The learner must register with the same email address. Blend-ed then resolves the pending enrollment automatically. The operation is safe to retry. Repeating an existing enrollment updates its mode rather than adding a duplicate; repeating a pending enrollment leaves one pending record. ## Remove course access ``` POST /blendxapi/enrollments/client/unenroll/ ``` ``` { "email": "learner@example.com", "course_id": "267ce96d-1454-4292-aa42-1a0487c7eaaa"} ``` For a registered learner, the API removes the Hasura enrollment record and its trigger requests the matching Open edX unenrollment. For an unregistered email, it cancels the pending auto-enrollment. The route returns `200` when the course exists even if there was nothing to remove. This makes refund and chargeback retries safe. > **Note** > Open edX unenrollment still respects the platform’s `safe_to_unenroll` policy. For example, access retained through another product relationship may remain in place even though the client request completed successfully. ## Error handling | Status | Meaning | | --- | --- | | `400` | Invalid body, unsupported mode, or enrollment operation failed. | | `401` | Missing or invalid `clientapisecret`. | | `404` | The course UUID does not exist in BlendX. | | `500` | Required server configuration, such as the service account, is missing. | Retry network failures and `5xx` responses with backoff. Do not retry `401` or `404` until configuration or identifiers change. # BlendX discovery APIs ## What you can build ### Course discovery List and search published courses, load course details and outlines, filter by organisation or tag, and display modes, reviews, and regional prices. ### Programs and organisations Discover programs and their courses, browse organisations, and load the branding and marketing metadata required by a multi-organisation catalog. ### Storefront checkout Start checkout for a guest or signed-in learner. Free items bypass the payment provider; paid items use the organisation’s configured gateway. ### Enrollment integrations Let a trusted partner system grant or remove course access by email after it confirms payment outside Blend-ed. ## Base URL All routes in this guide are relative to the LMS: ``` https:///blendxapi/ ``` The APIs are provided by the `blendxapi` Django app, version **4.0.0** in the documented checkout. They depend on the BlendX Hasura metadata service for catalog, organisation, cart, transaction, and enrollment records. ## Storefront lifecycle 1. Load organisations, tags, courses, or programs from `/discovery/` . 2. Use the returned course or program UUID and organisation UUID in checkout. 3. Check `/discovery/user/` to choose guest or authenticated checkout. 4. Complete payment using the gateway-specific values returned by checkout. 5. Let the signed payment webhook mark the purchase and create enrollment. 6. For an external checkout, call `/enrollments/client/enroll/` only after the external system confirms payment. > **Keep machine credentials on the server** > `CLIENT_API_SECRET` is instance-wide. A browser must call your storefront backend, which adds `clientapisecret` when it calls Blend-ed. Never embed the secret in client-side JavaScript, a mobile bundle, or a public repository. ## Choose a guide [Quickstart](/blendx-discovery/quickstart/) Make a first catalog request and understand the identifiers. [API reference](/blendx-discovery/api-reference/) See every supported discovery, checkout, and client-enrollment endpoint. [Authentication](/blendx-discovery/authentication/) Use a learner identity or the server-side client credential. [Courses](/blendx-discovery/courses/) List, filter, and load course details, outlines, effort, and enrollment state. [Programs](/blendx-discovery/programs/) List programs, load program details, and discover their courses and tags. [Organisations](/blendx-discovery/organisations/) Build organisation filters and branded marketing pages. [Checkout](/blendx-discovery/checkout/) Integrate guest, authenticated, and cart-backed checkout flows. [Enrollment](/blendx-discovery/enrollment/) Grant or revoke access from a trusted external system. # Organisations Organisation discovery routes accept an authenticated user or the server-side `clientapisecret`. ## List organisations ``` GET /blendxapi/discovery/organisations/ ``` | Query parameter | Default | Description | | --- | --- | --- | | `fields` | `full` | Use `basic` for identity fields only or `full` for branding. | | `search` | empty | Match the display name; basic mode also matches `short_name`. | The response contains an `organisations` array. It is not paginated. ### Basic fields | Field | Description | | --- | --- | | `id` | Organisation UUID required by discovery checkout. | | `name` | Learner-facing organisation display name. | | `short_name` | Stable Open edX/Hasura tenant key. | | `created_at` | Organisation creation timestamp. | ### Full fields The default `full` response contains every basic field plus: | Field | Description | | --- | --- | | `logo_url` | Organisation logo URL, or `null` when not configured. | | `favicon_url` | Organisation favicon URL, or `null` when not configured. | | `trademark_url` | Organisation trademark asset URL, or `null` when not configured. | ``` curl "https:///blendxapi/discovery/organisations/?fields=basic&search=acme" \ -H "clientapisecret: $BLENDX_CLIENT_API_SECRET" ``` ## Load marketing page metadata ``` GET /blendxapi/discovery/marketing-page-metadata/ ``` The response is an array—not an envelope—and includes only organisations with non-empty metadata: ``` [ { "organisation_id": "organisation-uuid", "marketing_page_metadata": { "headline": "Develop practical safety skills" } }] ``` `marketing_page_metadata` is organisation-defined. Treat it as an extensible object and tolerate unknown keys. > **Note** > Organisation administration is operated by Blend-ed and is intentionally not part of this client-facing discovery API guide. # Programs Program routes accept an authenticated user or the server-side `clientapisecret`. ## List programs ``` GET /blendxapi/discovery/programs/ ``` | Query parameter | Default | Description | | --- | --- | --- | | `limit` | `8` | Page size, clamped to 1–100. | | `page` | `1` | 1-indexed page number. | | `search` | empty | Search `name`, `description`, or `about`. | | `org` | empty | Comma-separated organisation names. | | `tags` | empty | Comma-separated tags; a match on any tag is included. | | `order_by` | `created_at.desc` | `{field}.{direction}`; `display_name` maps to `name`. | ``` curl "https:///blendxapi/discovery/programs/?org=Acme&tags=leadership&page=1" \ -H "clientapisecret: $BLENDX_CLIENT_API_SECRET" ``` The response envelope contains `programs`, `total_count`, `has_more`, `limit`, `page`, and `offset`. It can include `partial_errors` if a child course could not be serialized. ### Program list fields | Field | Description | | --- | --- | | `id` | BlendX program UUID used by detail and checkout requests. | | `name` | Display name. | | `description` | Short program description. | | `about` | Longer program information. | | `achievements` | Outcomes or achievements associated with the program. | | `duration`, `duration_metric` | Duration value and its unit. `duration_metric` is present on filtered-query results. | | `image` | Program image reference. | | `price` | Regionally adjusted program price. | | `originalPrice`, `discountPct` | Original price and applied regional discount. | | `nativeCurrency`, `nativeAmount` | Optional local-currency display hints. | | `organisation` | Object containing the organisation name and, when available, `logo_url` and `favicon_url`. | | `tags` | Tag-name array. | | `avg_rating` | Average program rating. | | `courses` | Serialized child-course array, including catalog modes, metadata, and regional pricing. | Each list response child course contains `id`, `openedx_course_id`, `display_name`, `short_description`, `course_image_url`, `start`, `end`, `effort`, `enrollment_start`, `enrollment_end`, `price`, `course_mode`, `available_course_modes`, `organisation`, `organisation_logo_url`, `organisation_favicon_url`, `is_invite_only`, `is_published`, `overview`, and regional price fields. See [Courses](/blendx-discovery/courses/) for the mode and regional-price shapes. ## Get program details ``` GET /blendxapi/discovery/program/{program_id}/ ``` The response is an object with these top-level fields: | Field | Description | | --- | --- | | `programs` | Array containing the matching program record. | | `program_courses` | Serialized child-course array. | | `avg_rating` | Average rating for the program UUID. | | `reviews` | Program review array. | | `partial_errors` | Optional details when some child courses could not be loaded. | Each record in `programs` contains `id`, `name`, `price`, `about`, `achievements`, `description`, `duration`, `duration_metric`, `image`, `invite_only`, `published`, `organisation`, and `organisation_id`. The `organisation` object contains `id` and `name`. Regional pricing adds `originalPrice`, `discountPct`, and, when available, `nativeCurrency` and `nativeAmount` to the program record. Use the BlendX program UUID—not a course key—in this URL and in a checkout item whose `type` is `program`. ## Discover tags ``` GET /blendxapi/discovery/tags/ ``` | Query parameter | Default | Description | | --- | --- | --- | | `search` | empty | Filter tag names. | | `include_courses` | `true` | Include courses assigned to each tag. | | `include_programs` | `true` | Include programs assigned to each tag. | The response has a `tags` array. Each entry contains `tag`, `courses`, and `programs`; a disabled relationship is returned as an empty array. A directly tagged course contains `id`, `openedx_course_id`, `display_name`, `short_description`, `overview`, `course_image_url`, `start`, `end`, `effort`, `enrollment_start`, `enrollment_end`, `price`, `organisation`, `language`, `self_paced`, `org`, `number`, `link_to_course`, and regional price fields. A program entry contains `id`, `name`, `description`, `about`, `organisation`, `courses_count`, and `courses`. When both relationship flags are enabled, each program’s `courses` array contains its course catalog data. For a lightweight filter menu, set both include flags to `false`. # Quickstart ## 1. Collect your Blend-ed connection details You need: - The LMS base URL, such as `https://learn.example.com` . - The `CLIENT_API_SECRET` supplied for server-to-server storefront calls. Store the credential in your deployment’s secret manager. In the examples, `$BLENDX_CLIENT_API_SECRET` represents that protected value. ## 2. List courses ``` curl "https:///blendxapi/discovery/courses/?fields=light&limit=8&page=1" \ -H "clientapisecret: $BLENDX_CLIENT_API_SECRET" ``` The response contains a page of published courses: ``` { "courses": [ { "id": "267ce96d-1454-4292-aa42-1a0487c7eaaa", "openedx_course_id": "course-v1:Acme+SAF101+2026_T1", "display_name": "Safety fundamentals", "price": 0, "currency": "usd", "course_mode": "honor", "is_published": true } ], "total_count": 1, "has_more": false, "limit": 8, "page": 1, "offset": 0} ``` ## 3. Keep both course identifiers The APIs use 2 identifiers for different jobs: | Field | Example | Used by | | --- | --- | --- | | `id` | `267ce96d-...` | Checkout and external enrollment. This is the BlendX/Hasura UUID. | | `openedx_course_id` | `course-v1:Acme+SAF101+2026_T1` | Course detail, outline, effort, and enrollment-status routes. | Do not substitute one for the other. ## 4. Load the course page URL-encode the Open edX course key when constructing a URL in application code: ``` curl "https:///blendxapi/discovery/course/course-v1%3AAcme%2BSAF101%2B2026_T1/?fields=summary" \ -H "clientapisecret: $BLENDX_CLIENT_API_SECRET" ``` `fields=summary` omits the expensive course structure. Load the dedicated outline route only when the page needs it. ## 5. Continue to checkout Use the returned course UUID, selected mode, and owning organisation UUID in a [guest or authenticated checkout request](/blendx-discovery/checkout/). If a separate commerce platform already charged the customer, use the [external enrollment API](/blendx-discovery/enrollment/) instead. > **Tip** > Use `fields=light` for card grids and `fields=summary` for a fast detail-page shell. Fetch full content only where it will be rendered. # Ask your AI about these docs These docs are available as a public, read-only MCP server. Connect it to the AI tool you already use, then ask questions such as *“How do I enrol learners with a CSV file in Blend-ed?”*. Your AI searches the docs, reads the relevant pages, and answers with links back to them. ``` https://docs.blend-ed.com/mcp ``` No account or key is needed. The server speaks streamable-http. > **Note** > This is the **docs** MCP server: it only searches and reads documentation. To let an AI manage an Open edX site, see the [Open edX MCP](/openedx-mcp/). ## Claude (claude.ai and Claude Desktop) 1. Open **Settings → Connectors** and choose **Add custom connector** . 2. Name it `Blend-ed Docs` and paste `https://docs.blend-ed.com/mcp` as the URL. 3. In a chat, enable the connector from the tools menu and ask your question. ## Claude Code ``` claude mcp add --transport http blend-ed-docs https://docs.blend-ed.com/mcp ``` ## Cursor Add the server to `~/.cursor/mcp.json` (or `.cursor/mcp.json` in a project): ``` { "mcpServers": { "blend-ed-docs": { "url": "https://docs.blend-ed.com/mcp" } }} ``` ## VS Code Add the server to `.vscode/mcp.json`: ``` { "servers": { "blend-ed-docs": { "type": "http", "url": "https://docs.blend-ed.com/mcp" } }} ``` ## Other MCP clients Any client that supports remote streamable-http servers can use the URL directly. Clients that only start local stdio servers can bridge with `mcp-remote`: ``` { "mcpServers": { "blend-ed-docs": { "command": "npx", "args": ["-y", "mcp-remote", "https://docs.blend-ed.com/mcp"] } }} ``` ## Tools | Tool | What it does | | --- | --- | | `search_docs` | Searches every page and returns the most relevant sections with their URLs. | | `get_page` | Returns the full Markdown of one page, from a URL or a path such as `/openedx-mcp/keys/`. | | `list_pages` | Lists pages with one-line descriptions, optionally for one section. | Each IP address can make up to 60 requests per minute. The docs are also published as [`llms.txt`](/llms.txt) and [`llms-full.txt`](/llms-full.txt) for tools that read documentation directly. # Blend-ed Docs ## Product Documentation [Getting Started](/product/getting-started/) Set up your account, sign in, and find your way around Blend-ed. [Browse all product guides](/product/) Manage your platform, build and publish courses, support learners, and understand your reports. [Ask your AI about these docs](/docs-mcp/) Connect Claude, ChatGPT, Cursor, or any MCP client to search and read Blend-ed docs while it answers. ## Tools [Open edX MCP](/openedx-mcp/) Give AI agents safe, scoped access to Open edX administration, enrollment, authoring, certificates, and reporting. [Interactive Content XBlock](/interactive-content-xblock/) Create self-contained HTML, CSS, and JavaScript activities in Open edX with interaction tracking, grading, completion, and optional AI-assisted authoring. [BlendX discovery APIs](/blendx-discovery/) Build a Blend-ed storefront with course and program discovery, organisation branding, regional pricing, checkout, and enrollment APIs. ## One home for Blend-ed documentation This site brings Blend-ed’s product guides and tool documentation together with consistent navigation, search, and stable links. # AI generation AI generation is optional and off by default. When configured, Studio authors can describe an activity and generate HTML, CSS, JavaScript, a display name, and grading metadata. They can also refine the current content. Generated fields are placed in the editor for review. Nothing is persisted until the author selects **Save**. ## Configure an OpenAI-compatible endpoint Add the setting to both LMS and CMS configuration under `XBLOCK_SETTINGS`: ``` XBLOCK_SETTINGS: InteractiveContentXBlock: ai: api_url: "https://api.openai.com/v1/chat/completions" api_key: "${INTERACTIVE_CONTENT_AI_API_KEY}" model: "gpt-4.1" timeout: 120 temperature: 0.7 max_tokens: 8192 extra_headers: {} ``` The endpoint must implement the OpenAI-compatible chat completions response shape. `api_url` or a custom `provider` enables the Studio section. No AI SDK or additional Python dependency is installed by the XBlock. > **Caution** > Keep credentials in your deployment’s secret store. The example uses a placeholder environment reference; do not commit a real API key to Tutor config or source control. ## Use a custom provider Deployments can route generation through their own gateway, credential system, or usage accounting by configuring a dotted Python callable: ``` XBLOCK_SETTINGS: InteractiveContentXBlock: ai: provider: "myplugin.ai.generate_for_interactive_xblock" model: "deployment-specific-model" ``` The function receives keyword arguments: ``` def generate_for_interactive_xblock(*, prompt, config, context): # context contains usage_id, user_id, and username return raw_model_response ``` Return the raw model text in the format requested by the prompt: fenced `html`, `css`, `js`, and `json` blocks. The JSON metadata can include `display_name` and `correct_answers`. ## Author workflow 1. Open **Generate with AI** in the Studio editor. 2. Describe one focused inline learning interaction. 3. Select **Refine current content** when you want to preserve and modify the current component. 4. Generate, then review all HTML, CSS, JavaScript, and grading fields. 5. Run **Test Grading** . 6. Save and test the published unit as a learner. AI generation automatically enables grade publication because generated JavaScript is required to call `submitInteraction()` with correctness data. ## Security and cost controls - Only a user with course write permission in Studio can call the generation handler. It fails closed in the LMS, XBlock Workbench, and runtimes without the Studio permissions service. - The API key stays on the server and is not sent to the browser. - Author prompts are capped at 8,000 characters. Each current content field is capped at 40,000 characters during refinement, and the current title at 1,000. - The generated response must contain HTML and JavaScript, call `submitInteraction()` , and keep `