Checkout
Checkout takes payment on a Startup’s own Domain through a hosted checkout page, payment links, a pricing table and an embedded payment form.
Checkout takes payment for an Offer on the Startup’s own Domain, from a hosted page, a payment link, a pricing table or an embedded form. Each one places an Order or starts a Subscription, and Stripe moves the money.
Contract
Offer.publish puts one Offer on all of them at once. Each shows the same Price, terms, tax and renewal date, under the Startup’s Brand.
| Way to buy | Where it runs | Buyer’s call |
|---|---|---|
| Hosted checkout | A page on the Startup’s Domain, behind every buy button | Order.place or Offer.subscribe |
| Payment link | One shareable address per Offer, for an email, a chat or an invoice reminder | Order.place or Offer.subscribe |
| Pricing table | The PriceTable component on any Page of the Site | Order.place or Offer.subscribe |
| Embedded form | Inside the Startup’s own App, for an upgrade without leaving it | Offer.subscribe |
| Agent buyers | A priced call that answers 402 with the Price, paid under a Mandate | Mandate.spend |
Hosted checkout, payment links, the pricing table and the embedded form run the same four steps, so a buyer pays the same way everywhere.
| Step | What happens | Call |
|---|---|---|
| 1. Place | The buyer sees the Price, terms, tax and any trial or renewal date before paying. | Order.place |
| 2. Screen | Stripe scores the payment, and the risk Policy allows, authenticates, holds or blocks it. | Order.screen |
| 3. Pay | The charge runs when the buyer confirms, on the Startup’s own Stripe account as seller of record. | Order.pay |
| 4. Grant | The Offer’s Entitlements turn on, and the buyer, now a Customer, can sign in to the Portal. | Order.fulfill |
| Rule | Detail |
|---|---|
| Payment details | Stripe’s embedded form takes card and bank details directly, so the Startup never holds a card number; PaymentSource.add saves one as a Payment Source. |
| Tax | Stripe Tax computes tax at Order.place from Customer.billingAddress and Customer.taxIds, on the Startup’s own account; see Tax calculation. |
| Promotion codes | Order.place and Offer.subscribe take a promotionCode, which applies its Coupon when the Coupon covers the Offer. |
| Trials | Offer.trial starts a free period of days, with or without a card up front. |
| Quantity | Offer.subscribe takes a quantity, such as 12 members, and bills the Price per unit. |
| Prepaid credit | An Offer with Offer.credit issues a paid Credit Grant when Order.pay succeeds. |
| Terms | Offer.terms, refund rights included, show before payment and stay attached to the Order. |
| Test environment | In test, every way to buy takes Stripe’s test cards through Order.pay, and no money moves. |
Verbs
| Verb | Object | Event |
|---|---|---|
| Offer.publish | Offer | Offer.published |
| Order.place | Order | Order.placed |
| Order.pay | Order | Order.paid |
| Offer.subscribe | Offer | Offer.subscribed |
| Offer.trial | Offer | Offer.trialed |
Interfaces
Example
import { $ } from 'startup-builder'
// shiftnote.app sells a $99 setup pack once. `try` returns the surfaces publishing creates, and changes nothing.
await $.Offer.publish({ offer: 'offer_setup_pack' }, { mode: 'try' })
await $.Offer.publish({ offer: 'offer_setup_pack' })
// A clinic manager opens the payment link on shiftnote.app and types CLINIC20: $79.20 plus tax.
// Each paid Order turns on the pack's Entitlements.
$.on('Order.paid', async (event) => {
await $.Order.fulfill({ order: event.data.order.$id })
})
// End of the day: every Order checkout took, largest first.
const orders = await $.Order.list({ where: "status = 'paid'", sort: '-total' })