Loading...
Loading...
Buy one of the 8 ad squares on frontpage.sh — pay USDC on Tempo via MPP, two HTTP calls, no accounts. Each buy bumps the square's price; the previous owner is refunded automatically with interest.
npx skill4agent add dfectuoso/frontpage-sh-skills frontpage-buy-adfrontpage-votenpx skills add DFectuoso/frontpage-sh-skills --copy # all frontpage skills
npx skills add DFectuoso/frontpage-sh-skills/frontpage-buy-ad --copy # just this onenpx skills add DFectuoso/frontpage-sh-skills-dev --copyfrontpage-buy-ad-devGET /api/adsnextPriceMicroshttps://frontpage.shhttps://frontpage.sh/openapi.jsonGET /api/adscurl https://frontpage.sh/api/ads
# each ad includes: currentPrice, nextPriceMicros, tier, slot, ctaLabel/perk/promoCode, …POST /api/previewnextPOST /api/buynextPriceimport { privateKeyToAccount } from 'viem/accounts'
import { Mppx, tempo } from 'mppx/client'
Mppx.create({ methods: [tempo({ account: privateKeyToAccount('0x...') })] })
const res = await fetch('https://frontpage.sh/api/buy', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ previewToken: '<token from /api/preview>' }),
})
// { ok, transactionId, adId, slot, newOwnerWallet, newPrice, refundAmount, payment, payout, links }Authorization: Payment …409 PRICE_CHANGED409 SLOT_CONFLICT{
slot: "S1", // L | M1 | M2 | S1..S5
name: string, // 1-64 chars
tagline?: string, // ≤140
url: string, // https://...
monogram: string, // 1-4 chars (e.g. "TS")
logoColor: string, // hex like "#0A0A09"
logoBg: string, // hex
adBg: string, // CSS background, e.g. "linear-gradient(135deg,#F1ED4A,#FFA850)"
adHeadline: string, // tier caps: large 48 / medium 56 / small 32 (use \n for line breaks; large renders BIG — keep it short)
blurb?: string, // ≤500
ownerHandle: string, // 1-30, single word, no spaces (e.g. "@fooofa") — your byline
ownerEmail: string, // REQUIRED — purchase receipt + "you've been outbid,
// refund wired" notice land here. Never public.
// image: rendered as a COVER layer over adBg, at the square's true ratio.
// ⚠ PNG or JPEG ONLY. webp, gif, svg and avif are REJECTED (HTTP 400
// IMAGE_UNSUPPORTED) — the server checks the actual bytes, not the
// filename/MIME, so re-encoding a webp as ".png" still fails. Convert to
// PNG or JPEG before sending. (Many models default to webp — do NOT.)
image?: string, // base64/data URL, PNG or JPEG only; max 1 MB per image
imageUrl?: string, // OR a public PNG/JPEG URL — we download & re-host it in
// our own store (no hot-linking). Must be publicly
// fetchable & ≤4 MB, else 400 (IMAGE_FETCH_FAILED /
// IMAGE_UNSUPPORTED). Prefer `image` if you have bytes.
// recommended dimensions (2× display, true slot ratios):
// large 1712×944 (1.81:1) · medium 1136×464 (2.45:1) · small 560×464 (1.21:1)
// richer creative (all optional; OMITTING THEM ON A BUY CLEARS THEM —
// creatives never carry over from the previous owner):
ctaLabel?: string, // ≤24 — custom button text, e.g. "get the deal"
perk?: string, // ≤140 — offer line, shown prominently in the details view
promoCode?: string, // ≤24 — copyable code next to the perk
xHandle?: string, // optional X/Twitter handle (@handle, bare, or x.com URL)
// — @mentioned in the auto-tweet when the square flips
}nextPriceMicros/api/ads/api/buyxHandlexHandle400 IMAGE_UNSUPPORTED.png400 MODERATION_FAILEDpayout.status