Skip to content

Ad kit

One angle in, five headlines and texts, five images at each site’s sizes and a 6-second clip out, every claim checked, saved as Variants.

Kind
Agent task
Price
38¢ per angle
Your time
10 minutes
Approval
Runs on its own
Ad.make
You, to your agent

Make five ad images and one short clip for the renewals angle, spend up to $2, and show me the plan first.

curl -X POST "https://api.sb/leaseline.app/ads/make?mode=try" \
  -H "Authorization: Bearer $SB_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"goal":"Make five ad images and one short clip for the renewals angle, spend up to $2, and show me the plan first.","budget":{"amount":2,"currency":"USD"}}'
npx startup-builder do Ad.make --try --data '{"goal":"Make five ad images and one short clip for the renewals angle, spend up to $2, and show me the plan first.","budget":{"amount":2,"currency":"USD"}}'
{
  "name": "do",
  "arguments": {
    "mode": "try",
    "code": "return await $.Ad.make({ goal: 'Make five ad images and one short clip for the renewals angle, spend up to $2, and show me the plan first.', budget: { amount: 2, currency: 'USD' } })"
  }
}
import { $ } from 'startup-builder'

const result = await $.try.Ad.make({ goal: 'Make five ad images and one short clip for the renewals angle, spend up to $2, and show me the plan first.', budget: { amount: 2, currency: 'USD' } })
Response
{
  "mode": "try",
  "stored": false,
  "estimate": "About 38¢ an angle",
  "sample": {
    "variant": "v_5",
    "headline": "Never miss a lease renewal again",
    "text": "Leaseline reminds you 90, 60 and 30 days out.",
    "format": "feed 1080×1080",
    "review": "passed"
  }
}
Try mode reads, stores nothing and spends nothingAPI referenceIts Nouns

What you get

  • 1 angle · One angle in, five headlines and texts, five images at each site’s sizes and a 6-second clip out, every claim checked, saved as Variants. · Ad
  • variants[] · Each Variant: headline, primary text, image and format, ready for Ad test setup.
  • clip · The 6-second clip with its voiceover, made only from an image that passed.
  • review · Assets passed, and each cut with the reason, such as “the #1 rent app” with no source.

How long: About 3 minutes.

Trigger

It runs when you call it, and when message test names a winner.

TypeScript
on.Experiment.concluded((exp, $) => exp.decision.choice === 'ship' && $.Ad.make({ offer: exp.offer, angle: exp.winner.angle }))

Steps

Your agent does these steps, one row per step; each step’s check is part of its row and its price.

StepVerbReturnsPriceApproval
1. Read the angle and the offerCollection.queryThe angle, the buyer phrase behind it and what the offer can claimFreeRuns on its own
2. Write five headlines and textsContent.draftFive pairs at the site’s lengths: 40-character headlines, 125-character primary textAbout 1¢Runs on its own
3. Make the imagesFile.generateFive images at each format’s size, in your brandAbout 8¢Runs on its own
4. Make the clip from the best imageVideo.draftA 6-second clip from the image that passed with the highest scoreAbout 28¢Runs on its own
5. Record the voiceoverFile.generateThe headline read over the clipAbout 1¢Runs on its own
6. Save them as VariantsContent.draftVariants ready for Ad test setupFreeRuns on its own

Calls: Collection.query, then Content.draft, then File.generate, then Video.draft, then File.generate, then Content.draft.

About 38¢ an angle, each time it runs, capped at $1.00.

Example: give it a goal

Make five ad images and one short clip for the renewals angle, spend up to $2, and show me the plan first.

The plan it shows runs 6 steps, priced before it spends anything; Run it above shows the result it returns.

When something fails

Each failure, and what happens next
WhenThen
An image fails the brand checkIt is made again once, then dropped; the kit ships with the images that passed.
No image passesNo clip is made, and the kit returns the copy with the findings; the clip is not billed.
You call it twice for the same angle and formatsThe same Variants return: it is idempotent per offer, angle and formats.

Each step retries three times, then falls through to the next route; one item's failure lands in skipped with its reason, never failing the call. Before a step would cross maxCost it stops and returns what it has, with a resume link. Each step's idempotency key is the call's key plus the step and the item: leaseline-ad-make-1-<step>-<item>.

How it is graded

A second model checks each asset against the site’s specs, your brand and the angle. It passes when each asset meets its format’s size and length, matches the brand, carries the angle, and claims only what the offer does. A miss is redone at no charge.

Change it

AskCompiles to
Make the story format only, with three images.Ad.make
Launch the five Variants on Meta at $20 a day.Campaign.launch
Make a kit for the second-best angle too.Ad.make
TypeScript
import { $, workflow } from 'startup-builder'

export default workflow({
  name: 'ad-make',
  verb: 'Ad.make',
  input: { offer: 'string', angle: 'string', formats: "('feed' | 'story' | 'search')[]", images: 'integer', clip: 'boolean' },
  maxCost: 1,
  grade: { evaluator: 'Venue specs, Brand, angle', passWhen: 'size and length met; on Brand; carries the angle; no claim past the Offer', remedy: 'redo' },
  execute: async (ctx, { offer, angle, formats = ['feed', 'story'], images = 5, clip = true }) => {
    const copy = await ctx.step('copy', () => $.Content.draft({ kind: 'ad-copy', offer, angle, count: images, maxCost: 0.02 }))
    const pics = await ctx.step('images', () => $.File.generate({ kind: 'image', from: copy, formats, count: images, maxCost: 0.08 }))
    const best = pics.filter((p) => p.grade.passed).sort((a, b) => b.grade.score - a.grade.score)[0]
    const video = clip && best ? await ctx.step('clip', () => $.Video.draft({ from: best.$id, seconds: 6, voiceover: copy[0].headline, maxCost: 0.3 })) : null
    return { variants: pairUp(copy, pics), clip: video }
  },
})

Extend it with extends: 'Ad.make' and base(), or compose your own from these steps.

Works with

Plays that order it: Account ads, Creator ads, House ads, Paid search, Paid social, Promote winners, Retargeting, Sponsorships, Video ladder.

It serves Make content, and runs in Paid. It deepens Experimentation.

For agents

For agents: the guide, its approvals, retries and lookups
FactValue
GuideAd.make
Guide approvalnone
GoalMake five ad images and one short clip for the renewals angle, spend up to $2, and show me the plan first. It may change counts, the order of steps, soft filters and the route a read takes, and it stops early when the goal is met. It never relaxes your words, raises its own budget, answers its own approval, calls a Play or acts outside your standing approval.
Triggeron.Experiment.concluded((exp, $) => exp.decision.choice === 'ship' && $.Ad.make({ offer: exp.offer, angle: exp.winner.angle }))
RetryThree times with backoff, then the next route; the same idempotency key never charges, sends or posts twice
Idempotency keyleaseline-ad-make-1
LookupsA find: input asks unless exactly one record fits
Step
1. Read the angle and the offer
2. Write five headlines and texts
3. Make the images
4. Make the clip from the best image
5. Record the voiceover
6. Save them as Variants

The amounts live once, on the hub (approvals).

Who does each step, and how it is checked
StepFunctionDoerCheckerAssuranceInputs
1. Read the angle and the offercodeCodeCode checks each result against its declared typemeasured$0.angle, $0.offer
2. Write five headlines and textsagenticThe Paid media agentA second model grades the outputgraded$1, $0.formats
3. Make the imagescodeCodeAdversarial review by a second model: Pass, or cut: an unsourced claim, an off-Brand image, text over the site’s limitmeasured$2, $0.formats
4. Make the clip from the best imagecodeCodeCode reads the result back from where it landedmeasured$3.passed
5. Record the voiceovercodeCodeCode reads the result back from where it landedmeasured$4.clip, $2.best
6. Save them as VariantscodeCodeCode reads the result back from where it landedmeasured$3.passed, $4, $5

The doer is never the checker, and the weakest assurance on the path is the whole call’s.

Under the hood

Under the hood: the Systems, Nouns and Events it touches
KindWhat it touches
SystemsMedia, sites and content
NounsCollection, Content, File, Action, Video
EventsCollection.queried, Content.drafted, File.generated, Action.evaluated, Video.drafted

Reference

Inputs, outputs, its Event and its errors
NameTypeDefaultMeaning
offerOfferRequiredThe offer the ads sell.
anglestringRequiredThe angle, from message test’s winner or in your words: “renewals you never miss”.
formats('feed' | 'story' | 'search')[]['feed', 'story']The placements to size for: 1080×1080 feed, 1080×1920 story, and search text only.
imagesinteger5Images made; each must pass the brand check.
clipbooleantrueMake one 6-second clip from the best image that passed.
maxCostnumber1.00The most this call spends each time it runs, in USD. It stops before a step would cross it and returns what it has, with a resume link.

Emits Ad.made. Refuses with max-cost before it spends, and with the Data calls and Accounts groups (refusals).

Contents