theuniversal is the shared road network that Dialin, and any app you build, drives on: what people are tasting, signalling and looking for, right now, without anyone being singled out. The Dial Dictionary (CC BY 4.0) and DIOS (Apache 2.0, being published) are open, so anyone can build their own on-ramp. Accounts, trust, points and tastes stay governed on theuniversal — see the terms.
/api/v1, never cached, so it's live. Get a key (any Dialin account). The keyless endpoints below stay open while v1 settles.GET /api/v1
https://api.theuniversal.io/<route> is the same as https://dialin.io/api/v1/<route>.GET /api/v1/stream — every pulse as it happens, as server-sent events: dial (a category and its core four, e.g. Italian · Pizza), signal.lit / signal.dim, search (the words only), offer.open / offer.close and meet, each on a randomized ~2 km cell. Resume with Last-Event-ID. Browsers' EventSource can't send a key, so read it from your server. Or poll /api/v1/map/pulses?after=<last id>. Pulses are kept 24 hours.me · stream · map/pulses · dictionary · dictionary/dials · map/live · map/flow · map/searches · map/snapshot · map/pulse · map/axes · rank — the same answers as the keyless endpoints below, with the same blur. A key buys accountability and a budget, not a wider view.map/snapshot 20 a minute, 1,000 a day; making offers 10 a minute, 200 a day. Over that you get a 429 with Retry-After. Keep keys on your server; revoke one any time at your keys.offers:read and offers:write. A key made for one place only sees and makes offers there. Offers made here are ordinary Dialin offers: people find, reserve and redeem them in the app like any other.GET offers (?live=1) · POST offers · GET offers/:id · PATCH offers/:id (anything but points_cost and place; {"active":false} pauses) · DELETE offers/:id (closes; codes already out still redeem) · POST offers/reach.title (required), points_cost 1–1000, inventory (null = unlimited, default 1), place (fsq_id; a place key fills it in), item_id (something you own, offered from a place), starts_at, ends_at, min_trust 0–100, description, fine_print, photo_url (https), target. A target takes facets (who: {"age_band":["25-34"]}) and dials (tastes: "cuisine:Korean", or a bare slug for any). It can't name a person — that stays in the app. Unknown fields are refused, so typos don't fail quietly. Send Idempotency-Key to retry a create safely.POST offers/reach {"target":{…},"min_trust":0} answers how many real people match, in fives — or just "fewer than 5". 10 a minute, 100 a day.POST webhooks {"url":"https://…","events":["offer.reserved","offer.redeemed","offer.released"]} — sent the moment someone reserves, redeems, or gives a code back, for your offers (at the key's place, if it has one). The secret comes back once. Also GET webhooks, POST webhooks/:id/ping, DELETE webhooks/:id. Up to 5 per app; https to a public host name only.hex(hmac_sha256(secret, t + "." + raw_body)) == v1, on the raw bytes, before parsing, and refuse old t. ref is the same from reserve to redeem and different for every webhook — it's never a person. Answer 2xx within 5 seconds; otherwise we retry after 1 min, 5 min, 30 min, 2 h and 6 h, then stop.GET /api/dictionary
GET /api/exchange/dials?category=food
GET /api/exchange/rank?dial=spice&lat=41.88&lng=-87.63&radius=8000&q=egg%20roll&order=desc&limit=20
GET /api/commons/live
GET /api/commons/snapshot?tastes=food,pizza&facets={"age_band":["25-34"]}
GET /api/commons/flow?since=2026-10-01T00:00:00Z&limit=500
GET /api/commons/searches?hours=24
GET /api/commons/pulse · GET /api/commons/axes