Skip to content

Creation order

What has to exist before each call, where each id comes from, the sequence of common flows and the errors that show up when a step is skipped.

Almost everything on Memberfy depends on something created earlier: a lesson needs a module, a module needs a course, a course needs a space. Calling the API out of order doesn't break anything, but every call made too early is refused. This guide shows the right order and the id that passes from one call to the next.

The dependency map

Structure and contentCommunity→Section→Space (module)→Post · Event · Image
CoursesCourses space→Course→Module→Lesson
SalesPayouts approved→Sell and withdraw
SubscriptionBilling option→Plan→Plan add-ons→Downsell
AccessPlan or product→Space access
DiscountProducts→Coupon

Put another way:

To create…You first need…And you pass
A spacea sectionsectionId
A post, event, course, imagea spacespaceId
A course modulea coursecourseId
A lessona modulemoduleId
A planthe billing options (SUBSCRIPTION products)productIds
An add-on on the planthe plan, and a monthly product that isn't a plan optionaddOnProductIds
Access to a space by plan or productthe plan or the productaccess.subscriptionGroupIds, access.productIds
A coupon for specific products onlythe productsapplicableProducts
Any sale or payoutBusiness Information and payout account approved—

Every call below carries Authorization and X-CommunityId. See Authentication and X-CommunityId.

Course

  1. Section (if there isn't one yet): POST /api/sections with title and visibility. Keep data.id as the sectionId.
  2. Courses space: POST /api/spaces with sectionId, title and module: "courses". Keep the spaceId.
  3. Course: POST /api/courses with communityId (the same as in the header), spaceId, title, slug and level (beginner, intermediate, advanced). It starts as a draft. Keep the courseId.
  4. Modules: POST /api/courses/module with courseId and title, one per module. Keep each moduleId.
  5. Lessons: POST /api/courses/lesson with moduleId, title and type (text, image, video, link).
  6. Publish: PUT /api/courses/{id} with status: "published". Only a published course accepts enrollments.

To adjust it later: PUT and DELETE /api/courses/module/{moduleId} rename, reorder and delete a module (along with its lessons); PUT and DELETE /api/courses/lesson/{lessonId} change a lesson's title, type, duration and order, move it to another module of the same course (moduleId) and delete it. Deleting keeps the progress of whoever already watched it.

To sell the course, continue with a product that opens the space (see Event, steps 3 and 4, which work the same way).

Mentoring

A cohort with its own board, sessions and monthly billing. (With contract length, the option in step 3 gains commitmentMonths.)

  1. The cohort's private space: POST /api/spaces with module: "feed" and visibility: "private". Keep the spaceId.
  2. Sessions: POST /api/events, one per session, with spaceId, title, slug, type: "online", startTime and endTime.
  3. Billing option: POST /api/products with type: "SUBSCRIPTION", title, price, billingInterval: "MONTHLY" and allowedPaymentMethods. Keep the product's id.
  4. Plan: POST /api/subscription-groups with name and productIds: [<id from step 3>]. Keep the plan's id.
  5. Open the space to the plan: PUT /api/spaces/{id} with access: { "subscriptionGroupIds": [<plan id>] }.

Step 5 only works after step 4: the plan has to exist before access can refer to it.

Event

An in-person event with a paid ticket and an announcement in the Feed.

  1. Events space: POST /api/spaces with module: "events".
  2. Event: POST /api/events with spaceId, title, slug, type: "in_person", startTime, endTime and the address (street, number, city…).
  3. Ticket: POST /api/products with type: "ONE_TIME", price, hasStock: true and stockQuantity. Then publish it.
  4. Open the space to buyers: PUT /api/spaces/{id} with visibility: "private" and access: { "productIds": [<ticket id>] }.
  5. Pinned announcement: POST /api/content in the Feed space, then PUT /api/feed/{type}/{id}/pin with the post's id.

Plan with add-ons

  1. The plan's billing options: one POST .../products per option (Monthly, Annual), type: "SUBSCRIPTION".
  2. The add-on: another POST .../products, type: "SUBSCRIPTION", billingInterval: "MONTHLY". It does not go into any plan's productIds.
  3. Plan: POST .../subscription-groups with the productIds from step 1.
  4. Add-ons on the plan: PUT .../subscription-groups/{id} with addOnProductIds: [<id from step 2>].

Before selling: payouts

An order that applies to any sale:

  1. POST .../business-information and .../submit.
  2. POST .../payout-settings and .../submit.
  3. Wait for both approvals (up to 7 business days). GET .../payout-settings/prerequisites tells you what's missing.

Products, billing options, plans, add-ons, coupons and downsell offers can be created and edited before approval: the product starts as DRAFT, in the currency of the Business Information's country (in any status), or BRL without it. Publishing (POST .../products/{id}/publish, or PUT .../products/{id} with status: ACTIVE), checkout and withdrawals wait for approval. An approved Business Information that gets edited goes back to PENDING and needs .../submit again; until it's approved again, checkout refuses.

The errors you get when you skip a step

CallWhat was missingResponse
POST /api/spacesthe section400 · Seção não encontrada ou não pertence a esta comunidade. (section not found or not in this community)
POST /api/spaces (or PUT)the section is more restricted400 · This space cannot be more open than the section "…", which is …
PUT /api/spaces/{id} with accessthe plan, product or group referred to400 · The access grant "…" does not exist in this community. (param: access)
POST /api/coursesthe space400 · ID do espaço é obrigatório. (space ID is required) or Espaço não encontrado ou não pertence a esta comunidade. (space not found or not in this community)
POST /api/courses/modulethe course404 · Curso não encontrado. (course not found)
POST /api/courses/lessonthe module404 · Module not found
POST .../subscription-groupsthe billing options400 · Product not found
PUT .../subscription-groups/{id} with addOnProductIdsthe add-on's product, or it's already a plan option400 · One of the add-ons does not exist in this community or was deleted. / A product that is a plan's billing option cannot be another plan's add-on.
Checkout configurationapproved payouts400 · Payment configuration has not been set up for this community
POST .../products/{id}/publish (or PUT with status: ACTIVE)approved Business Information403 · To publish and start selling, the community needs approved business information…
POST .../products/{id}/publishthe product in the approved country's currency400 · This product is priced in …, but the approved business information uses … (param: currency)
POST /api/checkoutapproved Business Information403 · Community must have approved business information to enable paid products
POST .../payoutsbalance for the amount plus the fee400 · Insufficient balance. Available: …
Any callthe header400 · X-CommunityId é obrigatório (X-CommunityId is required)

Some format validations still answer in English regardless of language (like Valid course ID is required when the id isn't a UUID).

Tips

  • Keep every id that comes back in data.id: it's what the next call asks for.
  • Send the same communityId in the body (when the route asks for it) and in the header.
  • Repeating doesn't undo: if a sequence stops halfway, continue from the step that failed instead of starting over (starting over creates duplicates).
  • In the MCP, the composite tools will follow this order on their own.