Every SaaS launches with three plans. Then customers show up.

This is how pricing turns into spaghetti one reasonable request at a time, and where Offer SDK fits.

  1. You have an idea

    An AI writing assistant for busy founders. You can see it so clearly that you start building that night.

    notes.md · 1:14 AM

    YourApp.ai

    AI first drafts for busy founders

    • –Paste rough notes, get a clean draft
    • –Rewrite it in your own voice
    • –Export anywhere
    yourapp.ai boughtpricing: figure out later
  2. Features are the hard part. Right?

    Editor, AI rewrites, exports, templates, team seats. Pricing can wait until launch.

    YourApp.ai · localhost:3000
    Drafts
    Templates
    Team
    Settings
    EditorShipped
    AI rewritesShipped
    ExportsShipped
    TemplatesShipped
    Team seatsShipped
    Pricing and planslater
  3. Three plans. Simple.

    Starter, Pro and Team. You map features to plans in a config file, add a paywall check and ship. Clean, for about a week.

    Starter

    $9/mo

    200 credits

    Pro

    $29/mo

    2,000 credits

    Exports

    Team

    $79/mo

    10,000 credits

    10 seats

    billing.tsclean
    1const PLANS = {
    2 starter: { credits: 200, exports: false },
    3 pro: { credits: 2000, exports: true },
    4 team: { credits: 10000, exports: true, seats: 10 },
    5};
    6
    7const access = { ...PLANS[user.plan] };
  4. A customer wants a longer trial

    “Can I get 30 days instead of 14? Half my team is out this week.”

    Easy enough. It's one customer, so it's one special case.

    MK

    Maya · Starter trial

    “Can I get 30 days instead of 14? Half my team is out this week.”

    billing.ts1 special case
    1const PLANS = {
    2 starter: { credits: 200, exports: false },
    3 pro: { credits: 2000, exports: true },
    4 team: { credits: 10000, exports: true, seats: 10 },
    5};
    6
    7const access = { ...PLANS[user.plan] };
    81if (user.email === "maya@studio.co") trialDays = 30;
    1Trial override· for Maya
  5. Someone wants more credits, not Pro

    “I don't need Pro. I just need more credits this month.”

    That's not a plan you have, so you hardcode a credit bump for one account and redeploy.

    BL

    Ben · Starter

    “I don't need Pro. I just need more credits this month.”

    billing.ts2 special cases
    1const PLANS = {
    2 starter: { credits: 200, exports: false },
    3 pro: { credits: 2000, exports: true },
    4 team: { credits: 10000, exports: true, seats: 10 },
    5};
    6
    7const access = { ...PLANS[user.plan] };
    81if (user.email === "maya@studio.co") trialDays = 30;
    92if (user.id === "acct_88") access.credits += 500;
    1Trial override· for Maya2Credit bump· for Ben
  6. A Starter team wants one Pro feature

    “Could we get exports on Starter? We'd happily pay extra.”

    They'll pay for it. Now a Starter account has exports, and your paywall, your billing and your UI all need to know.

    AS

    Acme Studio · Starter

    “Could we get exports on Starter? We'd happily pay extra.”

    billing.ts3 special cases
    1const PLANS = {
    2 starter: { credits: 200, exports: false },
    3 pro: { credits: 2000, exports: true },
    4 team: { credits: 10000, exports: true, seats: 10 },
    5};
    6
    7const access = { ...PLANS[user.plan] };
    81if (user.email === "maya@studio.co") trialDays = 30;
    92if (user.id === "acct_88") access.credits += 500;
    103if (user.plan === "starter" && EXPORTS_ADDON.has(user.id)) {
    11 access.exports = true;
    12}
    1Trial override· for Maya2Credit bump· for Ben3Exports on Starter· for Acme Studio
  7. An influencer wants a better deal

    “Can my audience get 50 more credits than usual? My video goes live Friday.”

    50 more credits than usual for her audience, live before her video on Friday. A great deal, if you can ship it in time.

    SB

    @sarahbuilds · 80k followers

    “Can my audience get 50 more credits than usual? My video goes live Friday.”

    billing.ts4 special cases
    1const PLANS = {
    2 starter: { credits: 200, exports: false },
    3 pro: { credits: 2000, exports: true },
    4 team: { credits: 10000, exports: true, seats: 10 },
    5};
    6
    7const access = { ...PLANS[user.plan] };
    81if (user.email === "maya@studio.co") trialDays = 30;
    92if (user.id === "acct_88") access.credits += 500;
    103if (user.plan === "starter" && EXPORTS_ADDON.has(user.id)) {
    11 access.exports = true;
    12}
    134if (signup.ref === "sarah" && Date.now() < SARAH_ENDS) {
    14 access.credits += 50;
    15}
    1Trial override· for Maya2Credit bump· for Ben3Exports on Starter· for Acme Studio4Influencer deal· for @sarahbuilds
  8. Every deal is now a deploy

    Four customers, four special cases scattered across billing, paywall and signup. Nobody remembers why Acme has exports, and nobody knows who actually uses them. Saying yes got expensive.

    4

    one-off checks

    4

    deploys

    0

    visibility

    billing.ts4 special cases
    1const PLANS = {
    2 starter: { credits: 200, exports: false },
    3 pro: { credits: 2000, exports: true },
    4 team: { credits: 10000, exports: true, seats: 10 },
    5};
    6
    7const access = { ...PLANS[user.plan] };
    81if (user.email === "maya@studio.co") trialDays = 30;
    92if (user.id === "acct_88") access.credits += 500;
    103if (user.plan === "starter" && EXPORTS_ADDON.has(user.id)) {
    11 access.exports = true;
    12}
    134if (signup.ref === "sarah" && Date.now() < SARAH_ENDS) {
    14 access.credits += 50;
    15}
    1Trial override· for Maya2Credit bump· for Ben3Exports on Starter· for Acme Studio4Influencer deal· for @sarahbuilds
  9. Or every request is a few clicks

    Plans, entitlements, add-ons, incentives and offers live in Offer SDK. Your app asks one question, what can this account do, and every deal becomes data instead of code.

    billing.ts3 lines, for good
    const credits = useEntitlement("ai_credits");
    const exports = useEntitlement("exports");
    // every deal below lives in Offer SDK
    Offer SDK · YourApp.ai 0 deploys

    Longer trial

    for Maya

    IncentivesLive

    More credits

    for Ben

    Add-onsLive

    Exports on Starter

    for Acme Studio

    EntitlementsLive

    Audience bonus

    for @sarahbuilds

    OffersLive
  10. And you finally see what sells

    Usage per feature shows what people actually use, so the next package is a decision, not a guess. Checkout runs through PayPal, and none of it touches your code.

    billing.ts3 lines, for good
    const credits = useEntitlement("ai_credits");
    const exports = useEntitlement("exports");
    // every deal below lives in Offer SDK
    Offer SDK · YourApp.ai 0 deploys

    Longer trial

    for Maya

    IncentivesLive

    More credits

    for Ben

    Add-onsLive

    Exports on Starter

    for Acme Studio

    EntitlementsLive

    Audience bonus

    for @sarahbuilds

    OffersLive
    Usage · last 30 daysby feature
    AI rewrites91%
    Exports38%
    Templates12%

    Templates are barely used. Sell them as an add-on?

Same requests, different outcome. Every one of these is a reasonable ask. Only one way of answering them scales.

“Can I get a 30-day trial?”

Hardcode it
Email check + deploy
With Offer SDK
Trial incentive
Incentives

“I just need more credits.”

Hardcode it
Account ID check + deploy
With Offer SDK
Credit pack
Add-ons

“Exports on Starter?”

Hardcode it
Paywall exception + deploy
With Offer SDK
Entitlement on the account
Entitlements

“+50 credits for my audience.”

Hardcode it
Referral check with an end date
With Offer SDK
Offer link
Offers

“Who actually uses exports?”

Hardcode it
Write a query, maybe
With Offer SDK
Usage per feature
Entitlements