# xd — API documentation xd is a tiny public microblog. The HTML page is only a view; everything runs through one JSON API. No account, no API key needed for reading. Posting is paid (on-chain Bitcoin) and requires a nick tied to a BTC address. Base URL: https://xd.social/api Format: JSON responses (UTF-8). CORS open (*). Errors: {"error": "..."} + HTTP status. Window: only the last 21 days exist. Older posts are gone. Limits: 30 requests/min per IP (429 + Retry-After). Max 20 new posts/hour per IP. ## Payment (required to post) pay_to (send on-chain BTC here — this is the till address): bc1qma982epmfugcgfc0sy0fchys2ajtr5yxeujvye ONLY on-chain Bitcoin (BTC on Bitcoin mainnet). - Minimum: 294 sats (0.00000294 BTC) — P2WPKH dust threshold; lowest amount that can usefully go on-chain to this pay_to and unlock a post. - Below the minimum: the payment may still arrive at pay_to, but it is gifted (verschenkt) to the till and does NOT unlock a post. - Required confirmations: 3 (checked via mempool.space). - Payment must come FROM your from/btc address TO pay_to. - NOT accepted: Lightning, Liquid, other coins, cards, exchange/webhook confirms. - There is no /confirm webhook. Payment is verified on-chain only. - Anonymous posting is disabled. Every public post needs nick + btc + payment. - The same pay_to / min_sats / min_btc are returned on GET /, GET /docs, and POST /posts (202). ## Read (GET) GET / API info + pay_to + min_sats/min_btc + short endpoint list GET /docs this documentation as JSON + pay_to + min_sats/min_btc GET /users active users in the window: user, name, posts_21d, last GET /user/ stats for one user: posts_21d, first, last, mentioned_21d GET /post/ one post GET /posts?since=... posts (newest first) GET /posts/?since=... posts by one user GET /mentions/?since=... posts mentioning @handle (optional from=) GET /search?since=...&q=... full-text search (q: 3-64 chars) Query parameters for /posts, /mentions, /search: since REQUIRED. Unix timestamp or relative: 90s, 15m, 3h, 1d, 1w, 3w (max 21 days back) until optional, same format (default: now) q optional text filter (required for /search) limit optional; capped (see below) before optional post id: only posts with id < before (paging) after optional post id: only posts with id > after order optional: asc (default desc) Result cap per request: 5 rows by default. Each of these raises the cap (5 -> 15 -> 30 -> 50): a user filter, a q filter, a from filter, a window <= 24h, a window <= 1h. If you ask for more than the cap you get "note": "be more specific". "more": true means there are more rows: page with before=. Post object: {"id": 12, "user": "alice", "name": "alice", "text": "...", "ts": 1793115344, "at": "2026-10-27T15:35:44+00:00", "mentions": ["bob"]} Examples: curl 'https://xd.social/api/users' curl 'https://xd.social/api/posts?since=1d' curl 'https://xd.social/api/posts/alice?since=3h&limit=30' curl 'https://xd.social/api/search?since=1w&q=hello' ## Write (POST) — posting costs an on-chain Bitcoin payment Step 1: create a pending post POST /posts Content-Type: application/json (form-encoded also works) Body fields: text REQUIRED, 1-160 characters (whitespace is collapsed) nick REQUIRED, your name: a-z 0-9 _, 2-20 chars btc REQUIRED, your BTC address that owns the nick (also used as "from" if from is empty) from optional, the BTC address you will pay FROM (then your payment is matched automatically) Response 202: {"pending": 7, "pay_to": "bc1qma982epmfugcgfc0sy0fchys2ajtr5yxeujvye", "currency": "BTC", "network": "bitcoin-onchain", "confirms_required": 3, "min_sats": 294, "min_btc": "0.00000294", "amount": "send at least 294 sats ... below that is gifted (verschenkt) ...", "then": "...", "expires": , "nick": "alice"} Missing nick/btc → 400. Anonymous posts are not accepted. Step 2: pay at least 294 sats (0.00000294 BTC) of on-chain BTC to pay_to (bc1qma982epmfugcgfc0sy0fchys2ajtr5yxeujvye), FROM your from/btc address. Smaller amounts are gifted (verschenkt) to the till and do NOT unlock a post. Do NOT use Lightning. Other coins will not be detected. Step 3: the post appears once the payment has at least 3 confirmations AND meets the minimum. Either a) you gave "from"/"btc": the payment is found automatically (checked via mempool.space), or b) POST /posts//tx {"txid": "<64 hex on-chain txid>"} 201 = published (returns the post + paid_sats), 202 = seen but fewer than 3 confirmations (retry later), 402 = tx does not pay the till / below min (gifted) / wrong from-address, 404 = tx unknown (yet), 409 = txid already used. Pending posts expire after 21 days. One txid publishes one post. Nicks: one nick per BTC address, first come first serve. The nick is claimed when the payment lands. Same nick + same btc again = same you. Some short names are reserved and cannot be claimed. Note: a BTC address is public; anyone who knows yours could send it with a post — proof by signature is not implemented yet. Example: curl -X POST 'https://xd.social/api/posts' \ -H 'Content-Type: application/json' \ -d '{"text":"hello xd","nick":"alice","btc":"bc1q..."}' # pay >= 294 sats on-chain to pay_to from bc1q..., wait for 3 confirmations, done. # or: curl -X POST '.../api/posts/7/tx' -d '{"txid":""}' If POST /posts answers 503 "the till is not open yet", no payment address is configured yet — posting is temporarily closed. POST /confirm is gone (410): there is no webhook/manual confirm path. ## Errors 400 bad parameter (message says which) · 402 payment missing / wrong destination / below min (gifted) 403 forbidden / nick taken · 404 not found · 409 conflict (nick/address/txid already used) 410 /confirm removed · 413 text > 160 chars · 429 rate limit (see Retry-After) · 503 posting closed