Documentation

How the network works

Everything an advertiser or an operator needs: what can be bought, how it is priced, what happens to a payment, and what the station promises about the numbers it shows. The full engineering write-up lives in the repository README.

Buy your first spot

Nothing has to be installed and no account is created with a password. A wallet on Robinhood Chain is all that is required.

  1. 01Open the station and press Buy airtime. Every surface that can be bought lights up.
  2. 02Click a surface, or pick one from the inventory list.
  3. 03Connect a wallet and sign in. Sign-in is a signature, not a password, and the nonce is single use.
  4. 04Upload an image or video. It is validated on the server and rendered onto that exact surface so you can see it before paying.
  5. 05Read the asking price. It descends on its own clock, so waiting costs you nothing but risks somebody else taking the surface first.
  6. 06Take the surface at that price. The server signs a quote for it and holds the ask while you pay.
  7. 07Send the payment. The station verifies the on-chain event itself, then puts your creative up.
  8. 08Hold the surface until somebody pays more, and keep the AirLog receipt when the run ends.

The inventory model

No placement, price or surface is hardcoded anywhere in the interface. A placement is a database row, and the studio renders whatever rows exist. An operator can point a placement at any named mesh in the studio model and it becomes buyable immediately, with no code change and no deploy.

TypeWhat it isBehaviour
FULLSCREENA commercial in the breakReplaces the main picture for its duration
OVERLAYLower third, LED ticker, sponsor bugDrawn over the programme without interrupting it
ENVIRONMENTA display inside the studioOn screen whenever the room is on screen
SPONSORSHIPStation identification bumperAttaches to a recurring piece of the schedule
  • lane is the exclusivity group, so surfaces that must never carry two advertisers at once share one.
  • ownsMainStream decides whether an airing campaign takes over the main picture. That single column is what makes commercials, takeovers and sponsored bumpers work without special cases.
  • inventoryMode is either CONTINUOUS, meaning the surface is live whenever the station is, or AD_BREAK, meaning it only plays inside a commercial break.
  • auction carries the surface's own price clock: opening price, floor, how long the descent takes, the takeover premium, the minimum increment and the guaranteed hold.

How a price is calculated

Nobody buys a thirty-second spot here. A buyer takes a surface at the price it is asking right now and stays on it until somebody pays more, so each surface is a single descending price clock.

  • A surface nobody has bought asks its opening price and walks down toward its floor. The first buyer who thinks the current number is fair takes it.
  • A sale resets the clock. The ask jumps to a premium over what the buyer paid and starts descending again.
  • While a surface is occupied the ask can never fall below what the occupant paid plus the minimum increment, so a takeover is always a strictly higher bid.
  • For the first stretch of a run the surface is not for sale at all, so a buyer always gets the runtime they paid for.
  • When a run ends the clock resets from the last clearing price down to the floor, so an unwanted surface gets cheaper until somebody wants it.

The descent is linear, so anyone reading the placement row can reproduce it exactly: the ask is the anchor minus the anchor-to-floor distance times the elapsed fraction of the decay. Money is integer wei end to end and every multiplier is integer basis points, so no rounding drift is possible.

The server is the only thing that prices anything. The browser asks for a quote and receives a signed one back; it never computes a number that is trusted later.

Creative specifications

Advertiser content is treated as hostile input, because it is.

  • Accepted: still images, and MP4 video in H.264 or AV1. Text creatives are accepted where a placement allows them.
  • Never accepted: HTML, JavaScript, iframes. There is no code path anywhere in this product that renders advertiser markup.
  • The real type is sniffed from the file's magic bytes. The browser's declared MIME type and the file extension are not trusted.
  • Images are decoded and re-encoded on the server, which strips metadata and any embedded payload, then downscaled to the placement maximum.
  • Video is parsed for true duration, dimensions, codec and audio track presence before it is accepted.
  • Each placement carries its own limits: aspect ratio, maximum dimensions, maximum file size, whether audio is allowed and whether a click-through is allowed.

The hash of the re-encoded file is what gets signed into the quote and emitted on chain, so the creative that airs is provably the one that was paid for.

Content policy and ratings

This network is unrated. There is no TV rating system here, no age gate, and no viewer discretion advisory shown before anything plays. Nothing you see carries a classification of any kind.

Everything that runs during station time is a user submission that was paid for. A buyer takes a surface, supplies their own creative and it is shown as supplied. AIRTIME does not produce that material and does not endorse it.

  • Placements that carry requiresModeration are checked by a moderator against the network's rules before they can air. That is a policy check, not a rating, and it is not a judgement about who the material is suitable for.
  • Surfaces without that flag air as soon as the payment verifies, with no human in the loop.
  • House graphics and the example cards on unsold surfaces are the station's own, always badged EXAMPLE, and are never presented as paid campaigns.
  • Operators can end a run from master control. Every such action is written to the audit log.

Watch at your own discretion. If something breaks the rules, report it from the campaign page or the source repository.

Payment and verification

The browser never decides that something is paid.

  1. 01The server signs an EIP-712 quote binding the quote id, buyer, placement, creative hash, amount, expiry and nonce. The domain separator includes the chain id and contract address, so a quote cannot be replayed on another chain or deployment.
  2. 02The payment contract re-checks the signature, caller, expiry, quote id, buyer nonce, token and exact amount, marks the quote consumed, forwards the funds to the treasury and emits its purchase event.
  3. 03The browser may hint a transaction hash, but it is only ever a lookup key. The server fetches the receipt from its own node, finds the event emitted by the configured contract address, and re-checks every field against the quote it signed.
  4. 04The same check also runs from the scheduler every few seconds with no browser involved, so closing the tab cannot lose a payment.
  5. 05Only then does the buyer take the surface: the previous occupant's run ends, the new creative goes up and the price clock resets.

A pending transaction is never treated as paid, and unique indexes on the payments table make double-recording impossible.

Receipts and delivery

Every completed campaign gets an AirLog: a shareable page showing what aired, on which surface, for which seconds, and the payment that bought it. Payment facts come from the chain. Delivery numbers come from AIRTIME's own first-party analytics, which store only a daily-salted hash of a per-tab random id, with no cookies and no cross-day joins.

The two are always presented separately. Nothing in this product describes an application-side delivery number as a verified or on-chain impression, and no viewer count is ever invented.

Operating the station

Master control lives at /control-room and is authenticated. From there an operator schedules programming, creates and edits placements including picking their mesh in the live studio, moderates creatives, reviews payments and reads the audit log. Every administrative mutation is written to an audit table with actor, action, target and details.

A new placement can also be added in code by appending to BASE_PLACEMENTS in the seed. Either way the studio picks it up over the realtime bus and it becomes buyable without a restart.

Running it locally

pnpm dev                 # station on :3000, embedded database, seeded
pnpm studio:build        # regenerate the studio model
pnpm chain:local         # local chain
pnpm contract:build && pnpm contract:deploy:local
pnpm test                # unit and API integration
pnpm contract:test       # contract tests
pnpm test:e2e            # full purchase path in a real browser

The end-to-end suite deploys the payment contract to a fresh chain, builds and starts the production server, then drives a browser all the way through: open a billboard, sign in, upload a creative, preview it, take a quote, pay, verify, air it and render the receipt.

Security model

  • A strict content security policy with a per-request nonce. Creatives are served sandboxed, with no sniffing allowed.
  • Advertisers authenticate by wallet signature with single-use, expiring nonces. Operators use a password with a separate session.
  • Uploads need a short-lived ticket bound to the wallet and the placement, on top of the session.
  • All API input is schema-validated. State-changing endpoints check same-origin and are rate limited.
  • The quote signer key holds no funds, never reaches the browser, and the treasury is a separate address configured on the contract.

Routes and API

RoutePurpose
/The station: studio, live television and purchase
/watch2D station with guide and log, no WebGL needed
/guideProgram guide
/queuePublic broadcast log
/airtimeAll inventory, plus your campaigns
/campaign/[id]Campaign status, creative hash and payment
/airlog/[id]Shareable proof-of-air receipt
/treasuryIncome in, pre-stock bought and distributed
/control-roomMaster control, authenticated

Public read APIs include the server clock, the realtime event stream, broadcast state and guide, the queue, activations, placements and their availability, showcase cards, treasury and AirLog. The full list, along with environment variables and deployment notes, is in the README.

Runs on