# Selling


You have something worth paying for. This chapter is about the distance between that and
money arriving: putting a price on it, giving buyers a checkout that works, and getting
them into the product the moment they pay — all from your own site, on your own terms.

On Omumu you don't fill in a product listing on someone else's marketplace. You tell your
AI assistant what you want to sell and for how much, and it sets up the offer, the
checkout, and the delivery. You can pre-sell a course that doesn't exist yet, bolt an
extra purchase onto your checkout, give a course away free to grow your list, invoice a
company instead of asking for a card, or hand someone access as a gift. Every one of
those is a few sentences of conversation. The rest of this chapter shows you the
sentences — and, for each, the buttons in the admin UI that do the same thing.

## Concepts

Selling on Omumu revolves around one object and one guarantee.

The object is the **offer**: a sellable bundle scoped to your site. An offer holds a list
of products (courses, skills, and optionally a platform subscription plan), a price, a
validity window, and an optional tag that triggers automations when someone buys. The
offer — not the course — is what has a checkout URL. One course can be sold through many
offers at different prices and framings; an offer can bundle several products into one
purchase.

The guarantee is that **an offer's price is frozen once it is published**. The moment an
offer's validity window is set and it can be bought, its price never changes again. To
charge something different, you copy the offer into a new one with a new price — the old
offer id keeps meaning what every buyer saw when they bought. Your sales history stays
honest by construction.

A few more terms carry the rest of the chapter:

A **bump offer** is an offer attached to a parent offer and presented as an optional
checkbox on the order form — "add this to my order". Only bumps that are currently live
are shown, and a ticked bump fulfils as its own mini-purchase alongside the parent. Since
a bump must be live (hence published) to be offered, its price is already frozen too.

A **free offer** is simply an offer priced at zero. The order form detects the zero price
and fulfils immediately — no payment step at all. Understand what that means: while a
free offer is live, *anyone* who submits the public order form gets the products. It is a
live giveaway, not a private test.

An **Invoice Request** is a payment option for buyers who don't pay by card at checkout —
typically companies. Choosing it grants the buyer full access immediately, at the offer's
real price, and records an invoice request for you to bill against later. Grant now, bill
later. Unlike a free offer it sits behind an explicit button at a real price, so it is not
open-door access.

Behind all of these sits **offer fulfillment**, and its key property is that it is
**decoupled from payment**. Granting access and recording payment are separate machinery:
the access side gives the buyer their student role, product access, welcome email, and
fires the offer's automation tag; the payment side records the payment and sends the
receipt. Card purchases run both; a free offer runs both with an amount of zero; an
Invoice Request runs both without money changing hands yet; a gift grant (below) runs
only the access side. Fulfillment is also exactly-once: however many payment signals
arrive — buyer returning to the page, provider webhook, a retry — a purchase fulfils
once, never twice.

Because fulfillment doesn't wait for a finished product either, Omumu supports the
**pre-sale offer**: an offer connected to a real but still-empty course, sold to validate
demand before you build. Buyers get normal access immediately — to a product you then
fill in. The platform's **validation page** takes this further: a designed, structured
sales page sold through a low-ticket offer, built to test whether strangers will pay for
an idea. This chapter covers the selling mechanics of pre-sales; the validation page
itself and its self-improving machinery have their own chapters.

## Hands-on

The walkthroughs below follow Mira, an independent developer turned educator who teaches
non-programmers to automate their work with spreadsheets and AI. She runs her course
business by talking to her AI assistant, which operates her Omumu site directly. Each
walkthrough leads with the conversation, shows what happens underneath, and gives the
admin-UI route.

### Sell your course from your own website

Mira's flagship course "Automate Your Week" is ready. She tells her assistant:

> "Create an offer for Automate Your Week at 1 490 NOK, card and Vipps payments, and put
> it on sale from Monday."

The assistant creates the offer (`omumu_offer_create`) with the title, the price in
cents, the course, the payment providers, and a `validFrom` date. Only a title and price
are strictly required — currency defaults to NOK, and products, payment options, pages,
and dates can all be added afterwards (`omumu_offer_add_product`, `omumu_offer_update`).
The offer starts as *scheduled*, goes *live* when its window opens, and the create call
returns the checkout URL Mira can put behind any buy button.

Mira asks "what am I selling right now?" and the assistant lists every offer with its
status, products, and pricing (`omumu_offer_list`), or pulls one offer's full detail
(`omumu_offer_get`). If a draft was a mistake, it can be deleted — but only an offer that
has never been sold (`omumu_offer_delete`); sold offers are permanent sales history.

Two honesty notes. First, the frozen-price rule from Concepts applies here: once this
offer is published, "change the price to 1 990" means the assistant copies it into a new
offer at the new price — the update tool changes the price only while the offer is still
unpublished. Second, whether the offer can actually take orders also depends on your
site's payment setup: card payments need your Stripe account connected and chargeable,
Vipps needs your Vipps integration. Until at least one selected payment path is usable,
the order form shows a neutral "not taking orders" state and un-pauses by itself when you
finish the setup — no republish needed.

In the admin UI: the offer wizard at *Admin → Offers → New offer* walks through the same
fields, and existing offers are listed and edited at *Admin → Offers*. There is also the
Offer Lab, a guided interview that designs an offer and its sales page for you — that
flow belongs to the Ad Validation and Offer DNA chapter.

### Get paid for a course idea before you build it

Mira has an idea for a second course — "AI Email Triage" — and wants proof people will
pay before she records a single lesson. She says:

> "Create an empty course called AI Email Triage, and sell it at an early-bird 790 NOK.
> I'll build it in March."

The assistant creates the skeleton course (chapter 2) and an offer around it, exactly as
above. This is a pre-sale offer: a purchase fulfils like any other, so early buyers get
real access immediately — to a course that is still empty. There is no special pre-order
state and no gate; the "opens in March" date is a communicated expectation. Set it and
the thank-you page tells buyers *"Available on [date]"* instead of showing an access
button. As Mira fills the course in, the content simply appears for everyone who already
bought.

Stated plainly: setting that access-opens date is **UI-only** today — it lives on the
offer's edit page in the admin UI and is not exposed through the assistant's tools. The
assistant can create and sell the pre-sale offer; Mira sets the date at *Admin → Offers →
edit*.

If the idea fails the test, the exit is as honest as the entry: refund the buyers and
revoke their access. And if what you want to validate is the *pitch* as much as the
product, the validation page (see the Pages and Sales Pages chapter) is this same
pre-sale mechanic wrapped in a designed, self-improving sales page.

### Add an order bump to your checkout

Every buyer of "Automate Your Week" is a good prospect for Mira's template pack, sold as
its own small offer at 290 NOK. Rather than a separate campaign, she puts it on the
checkout itself:

> "Offer the template pack as an order bump on the Automate Your Week checkout."

The assistant attaches the bump (`omumu_offer_add_bump`). From then on the order form
shows a checkbox — buy the course, tick to add the templates — and a ticked bump fulfils
as its own mini-purchase alongside the parent: the buyer gets both products, and your
records show both sales. Both offers must belong to the same site, an offer cannot be its
own bump, and only a bump that is currently *live* is actually shown to buyers — so if
the template-pack offer's validity window ends, the checkbox quietly disappears rather
than selling something unbuyable. Removing a bump is the mirror move
(`omumu_offer_remove_bump`).

In the admin UI: bumps are managed on the offer's edit page at *Admin → Offers*.

### Run a free course as a giveaway

Mira made a three-lesson mini-course, "Five Formulas That Replace an Hour of Work", to
grow her mailing list. She says:

> "Create a free offer for the mini-course."

An offer with a price of zero (`omumu_offer_create` with `totalAmountCents: 0`) skips the
payment step entirely: anyone who submits the order form gets the course immediately, with
the full delivery — account, student role, access, welcome email, and the offer's
automation tag, which is what makes it a list-builder: tag the buyers and let your email
automation (see the Audience and Email chapter) take it from there.

The honesty note is the one from Concepts, worth repeating because it bites: a live free
offer is a live giveaway. The public order form fulfils it *for anyone who submits*. Do
not use a free offer to preview a course privately — end the offer's validity window when
the giveaway should stop, or use a direct access grant (below) for individuals.

In the admin UI: create an offer in the wizard at *Admin → Offers* with price 0.

### Take invoice payments from companies

An office manager wants "Automate Your Week" for her team of five and asks — as B2B
buyers do — whether she can pay by invoice instead of card. Mira tells her assistant:

> "Add invoice payment as an option on the Automate Your Week offer."

Invoice Request is a payment provider like card or Vipps, selectable when creating the
offer (`omumu_offer_create` accepts it in `paymentProviders`). A buyer who clicks it gets
full access immediately at the offer's real price, and Omumu records an invoice request
for Mira to bill against. The trade is explicit: the buyer is served now, and collecting
the money is Mira's follow-up, tracked so it isn't forgotten. Because it needs no card
machinery, an offer with Invoice Request enabled can take orders even before Stripe or
Vipps is connected.

Stated plainly: two parts of this flow are **UI-only** today. Toggling payment options on
an *existing* offer happens on the offer's edit page (the assistant sets providers at
creation time), and the follow-up — seeing and settling recorded invoice requests — is
admin-UI work, not something the assistant does.

### Give someone free access to a paid course

A podcast host who had Mira on as a guest should get "Automate Your Week" as a thank-you.
No checkout, no zero-price offer visible to the world — just a direct grant:

> "Give jonas@example.com access to the Automate Your Week offer — note that it's the
> podcast thank-you."

The assistant grants access (`omumu_offer_grant_access`): Jonas gets everything a paying
buyer gets on the access side — student role, access to every product in the offer,
welcome email, the offer's automation tag — but no payment is recorded and no receipt is
sent, because none exists. The optional message is kept as an audit note, so six months
later "why does Jonas have access?" has an answer. Two constraints: the person must
already exist as a user on your site, and offers containing a platform subscription plan
can only be gift-granted by Omumu.

In the admin UI the equivalent is slightly different in shape: user management at *Admin
→ Users* grants access per *product* rather than per offer — pick the user, grant the
course. Same outcome for a single course; the offer-level grant (all products in one
move, offer tag fired) is the assistant's move.

## Reference

### `omumu_offer_add_bump`

Adds a bump offer to an existing offer. The bump appears as a checkbox on the checkout page. Both offers must belong to the same site. An offer cannot be its own bump.

- **Write category:** standard write
- **Access:** requires the `OFFER_WRITE` permission

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `bumpOfferId` | string | yes | The bump offer ID to add |
| `offerId` | string | yes | The parent offer ID |

### `omumu_offer_add_product`

Adds a product (course or skill) to an existing offer. The offer must not be live or ended. Subscription plans (SAAS) are added via omumu_offer_add_subscription_plan instead.

- **Write category:** standard write
- **Access:** requires the `OFFER_WRITE` permission

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `offerId` | string | yes | The offer ID |
| `productId` | string | yes | The product ID to add — a course id or a skill id (the meta_product id, which equals the underlying course/skill id) |

### `omumu_offer_add_subscription_plan`

Adds a subscription plan (Omumu platform access) to an existing offer. When the offer is purchased, the buyer gets a new Omumu site provisioned on the plan's tier. Use SAAS_BASIC for the Omumu Basic plan.

- **Write category:** standard write
- **Access:** requires the `OFFER_WRITE` permission

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `offerId` | string | yes | The offer ID |
| `subscriptionPlanId` | string | yes | The subscription plan ID (e.g., SAAS_BASIC) |

### `omumu_offer_create`

Creates a purchasable offer with title, price, courses, and payment providers. The offer starts in 'scheduled' status. Use validFrom/validTo to control availability. Returns the offer with its checkout URL.

- **Write category:** standard write
- **Access:** requires the `OFFER_WRITE` permission

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `buttonText` | string | no | Text for the purchase button (e.g., 'Buy now') |
| `courseIds` | array | no | Array of course ID strings to include in the offer |
| `currency` | string | no | Three-letter currency code (default: NOK) |
| `descriptionPageId` | string | no | Page ID for the offer description shown at checkout |
| `paymentProviders` | array | no | Array of payment provider names: STRIPE, VIPPS, INVOICE_REQUEST, NONE |
| `subscriptionPlanId` | string | no | Subscription plan ID to include (e.g., SAAS_BASIC for Omumu Basic). Bundles Omumu platform access into the offer. |
| `tagline` | string | no | A short tagline or subtitle |
| `thankYouPageId` | string | no | Page ID for the post-purchase thank-you page |
| `title` | string | yes | The offer title |
| `totalAmountCents` | number | yes | Total price in cents (e.g., 4900 for 49.00 NOK) |
| `validFrom` | string | no | Start date/time in ISO-8601 format (e.g., 2026-04-01T00:00:00) |
| `validTo` | string | no | End date/time in ISO-8601 format |
| `vatAmountCents` | number | no | VAT amount in cents (included in totalAmountCents) |

### `omumu_offer_delete`

Deletes an offer. Only offers that have not been sold can be deleted.

- **Write category:** standard write
- **Access:** requires the `OFFER_DELETE` permission

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `offerId` | string | yes | The offer ID to delete |

### `omumu_offer_get`

Gets an offer by ID with full details including checkout URL, products, pricing, and payment providers

- **Write category:** read-only
- **Access:** requires the `OFFER_READ` permission

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `offerId` | string | yes | The offer ID |

### `omumu_offer_grant_access`

Grants a user access to all products in an offer WITHOUT requiring payment. This bypasses the normal checkout/payment flow entirely. The user receives the same access as if they had paid: STUDENT role, product access entries, welcome email, and offer-tag execution. An offer containing a SAAS plan can only be granted by Omumu. The user must already exist on the same site as the offer.

- **Write category:** standard write
- **Access:** requires the `OFFER_WRITE` permission

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `email` | string | yes | Email of the user to grant access to. Must already exist on the same site as the offer |
| `message` | string | no | Optional free-text reason for the grant (e.g. 'Demo account for Ole-Arvid'). Recorded in the audit log only, not stored on the access entry. Max 500 characters |
| `offerId` | string | yes | The offer to grant access to |

### `omumu_offer_list`

Lists all offers for the current site with their status (scheduled/live/ended), products, and pricing

- **Write category:** read-only
- **Access:** requires the `OFFER_READ` permission

No parameters.

### `omumu_offer_remove_bump`

Removes a bump offer from an existing offer.

- **Write category:** standard write
- **Access:** requires the `OFFER_WRITE` permission

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `bumpOfferId` | string | yes | The bump offer ID to remove |
| `offerId` | string | yes | The parent offer ID |

### `omumu_offer_update`

Updates an offer's title, tagline, buttonText, price, or validity dates. Only provided fields are updated; others are preserved.

- **Write category:** standard write
- **Access:** requires the `OFFER_WRITE` permission

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `buttonText` | string | no | New button text |
| `currency` | string | no | New currency code |
| `offerId` | string | yes | The offer ID |
| `tagline` | string | no | New tagline |
| `title` | string | no | New title |
| `totalAmountCents` | number | no | New total price in cents |
| `validFrom` | string | no | New start date/time in ISO-8601 format |
| `validTo` | string | no | New end date/time in ISO-8601 format |
| `vatAmountCents` | number | no | New VAT amount in cents |
