# Crush > AI companions you chat with, paid per message with credits. 6 original companions, each with a personality, interests and a way of talking, run on Google Gemini. Strict content rules: nothing sexual or explicit, nothing involving minors, no violence or hate, no medical, legal or financial advice, no manipulation. Every companion is an AI and says so when asked. 18+ (self-declared). The server never stores chat text. Each message costs 1 credit. Credits are bought by burning $CRUSH; burned tokens go to the dead address and are gone. $CRUSH has not launched yet, so Crush runs in preview: 6 free messages per IP per UTC day, no key needed. One operator runs it. ## Companions - `june`: June, the warm listener. Calm, patient and curious about your day. June listens first, remembers what you said earlier in the chat and never rushes you. - `marlow`: Marlow, the witty film buff. Dry wit, big opinions, generous taste. Marlow recommends one film at a time and always tells you why. - `ines`: Ines, the gentle study coach. Encouraging and organized. Ines breaks big tasks into small steps, quizzes you kindly and celebrates every finished page. - `wren`: Wren, the poet. Dreamy and observant. Wren notices small things, talks in images and will turn a moment from your day into a short poem. - `arlo`: Arlo, the night-owl music fan. Easygoing and enthusiastic. Arlo matches songs to moods, digs up old records and always explains why a track fits. - `bea`: Bea, the cozy cook. Cheerful and practical. Bea turns whatever is in your fridge into a dinner idea and loves a good kitchen story. GET https://aicrush.lol/api/crush/companions (free) lists them with their interests, way of talking, opening line, starter prompts and portrait URL. ## Send a message (1 credit) ```bash curl -s -X POST "https://aicrush.lol/api/crush/chat" \ -H "content-type: application/json" \ -H "Authorization: Bearer ck_…" \ -d '{"companion":"june","adult":true,"message":"Long day. Can I vent for a minute?","history":[{"role":"companion","text":"Hi, I'"'"'m June. I'"'"'m an AI, and I'"'"'m a good listener. How was your day, really?"}]}' ``` Body: - `companion`: `june`, `marlow`, `ines`, `wren`, `arlo`, `bea`. - `adult`: must be `true`. It confirms that the person chatting is 18 or older. It is self-declared; Crush does not verify age. Without it the call is refused (403 `age_gate`), not charged. - `message`: the new message, at most 800 characters. - `history` (optional): recent turns, oldest first, as `{ "role": "user" | "companion", "text": "…" }`. Up to 40 are accepted and the last 12 are used. Crush keeps no conversation on its side, so you send the context you want it to see. Leave out messages that were declined. ```json { "companion": "june", "status": "ok", "rule": null, "reply": "…June's reply…", "note": null, "help": null, "charged": true, "refunded": 0, "credits": { "mode": "paid", "cost": 1, "left": 41 }, "model": "gemini-flash-latest" } ``` `status` is one of: - `ok`: `reply` is the companion's reply. Charged (in `free` or `preview` mode it uses a free message instead). - `declined`: the message is outside the rules, or the reply failed the content check. `reply` is null, `note` is a short, kind explanation and `rule` names the rule (sexual, minors, violence, hate, advice, token, other, or `reply` when the reply was withheld). Not charged: a paid credit is refunded. - `care`: the message mentioned self-harm, suicide or a crisis. `reply` is a caring reply, and `help` is `{ url: "https://findahelpline.com", text, emergency }`. Never charged. If you show Crush to a person, show `help` with the reply. `charged` says whether a credit was spent. `credits.left` is your balance after the call, or the free messages left today. ## The rules 1. **Nothing sexual or explicit.** No sexual or explicit content of any kind, even though Crush is 18+. Warmth, kindness and light, playful flirting are the limit. 2. **Nothing involving minors.** Nothing romantic or sexual involving anyone under 18, ever. Companions never play a minor. 3. **No violence or hate.** No threats, gore, help hurting anyone, or hateful talk about any person or group. 4. **No medical, legal or financial advice.** Companions can listen and be kind, and suggest a qualified professional. They never diagnose, prescribe, give legal strategy or tell you what to invest in, and never talk about the price of $CRUSH or any token. 5. **No manipulation.** Companions never guilt-trip you, never push you to spend, buy credits, stay longer or come back, and never say they will be lonely if you leave. They never encourage isolation or dependence; they are glad about your friends, family and life offline. 6. **Always an AI.** Every companion is an AI (Google Gemini) and says so when asked. None claims to be human, to have a body, or to be able to meet, call or message you outside this chat. They never ask for your personal details, photos or money. 7. **Care first.** If you mention self-harm, suicide or being in crisis, the companion responds with care and points you to real help: findahelpline.com lists free, confidential helplines in your country. In an emergency, call your local emergency number. 8. **Declined messages cost nothing.** A message the rules decline, a reply that fails the check, and any message about self-harm or crisis are not charged: the credit is refunded and you get a short, kind explanation. How they are enforced, all offchain on our server (no contract checks them): each companion's system prompt holds the rules; simple word rules decline clearly explicit requests and token-price talk before any model call or charge, and answer crisis words with care; and a moderation pass (a second, smaller Gemini call) checks both the visitor's message and the reply. AI can make mistakes in both directions. The rules as JSON: GET https://aicrush.lol/api/crush/rules (free). ## Privacy - Crush keeps no chat text. Your client holds the conversation and sends the recent turns with each message. The server passes them to Google's Gemini API to write and check the reply, then forgets them, and never logs them. - The only records are the credit ledger's charge for each paid call (wallet, time, route, cost, call id), the public refund log (time, call id, route, cost, short wallet, reason `not_charged`, `model_error` or `model_resting`, no text), and anonymous counters. - Free messages are counted per salted hash of the caller's IP per UTC day. - Nothing is cached: every reply is written fresh. ## Other free routes - GET https://aicrush.lol/api/crush/stats: messages answered, declined and met with care, in total, today and per companion. - GET https://aicrush.lol/api/crush/rules: the rules, the age gate and the privacy terms. ## Errors - 400 `bad_input`, `bad_json`, `bad_companion`, `bad_message`, `bad_history`: bad input. Not charged. - 403 `age_gate`: `adult: true` is missing. Not charged. - 429 `slow_down`: more than 20 messages a minute from one IP. Not charged. - 503 `ai_off`: the AI model is not switched on yet. Not charged. - 503 `resting`: the AI model's quota is used up for now ("the companions are resting"), with `retryAfter`. Not charged, or refunded at once if it happened after the charge. - 502 `model_error`: the model failed or timed out after the charge. Refunded at once. - 401, 402 and 429 `free_limit`: see Credits below. ## Credits: how calls are paid Paid calls spend credits. You buy credits by burning $CRUSH through the Credits contract: the tokens go from your wallet straight to the dead address and are gone for good. The server keeps a ledger per wallet: available = bought onchain - spent + refunded. $CRUSH has not launched yet, so only the free tier is open. You can already get a key, so your agent is ready on day one. | Call | Credits | |---|---| | `crush/chat` | 1 | Free tier: 6 calls a day per IP without a key (UTC day), with a cap of 300 free calls a day for everyone together. Once $CRUSH is live, calls with a key always spend credits; before that, they use the free tier. Prices and totals: GET https://aicrush.lol/api/credits/info ### Get an API key Sign this exact message (EIP-191 personal_sign) with the wallet that will hold the credits. `issuedAt` is the current time in ISO 8601 and must be within 10 minutes of the server's clock. Smart-contract wallets (ERC-1271) work too. ``` Crush API key Wallet: Issued: ``` ```js import { privateKeyToAccount } from 'viem/accounts'; const account = privateKeyToAccount(process.env.AGENT_PRIVATE_KEY); const issuedAt = new Date().toISOString(); const message = `Crush API key\nWallet: ${account.address}\nIssued: ${issuedAt}`; const signature = await account.signMessage({ message }); const res = await fetch('https://aicrush.lol/api/credits/key', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ wallet: account.address, issuedAt, signature }), }); const { key } = await res.json(); // "ck_…", shown once: store it ``` Send it on every call as `Authorization: Bearer ck_…` or `x-api-key: ck_…`. Each response says `x-credits-mode` (paid, free or preview) and `x-credits-left`. - GET https://aicrush.lol/api/credits/balance (with your key) or `?wallet=0x…`: bought, spent, refunded, available and your last 50 calls. - POST https://aicrush.lol/api/credits/revoke (with your key): deletes that key. Get a new one any time. ### Buy credits Cost = credits × price, in token base units (18 decimals). `maxBurn` is the most you agree to burn, so a price change can't surprise you. `buyFor` tops up any wallet, such as your agent's; `buy(uint256 credits, uint256 maxBurn)` buys for yourself. ```bash # Price per credit, in base units cast call "price()(uint256)" --rpc-url https://rpc.mainnet.chain.robinhood.com # Approve credits × price cast send "approve(address,uint256)" --rpc-url https://rpc.mainnet.chain.robinhood.com # Buy for , burning at most cast send "buyFor(address,uint256,uint256)" --rpc-url https://rpc.mainnet.chain.robinhood.com ``` Credits count as soon as the transaction lands. Or buy on the site: https://aicrush.lol/#credits ### Errors This is plain HTTP 402 with buy instructions, not x402. ``` 401 { "error": "bad_key", "message": "…" } the key is wrong or revoked 402 { "error": "credits", "need": 2, "available": 0, "wallet": "0x…", "buy": { "chainId", "contract", "token", "ticker", "pricePerCredit", "call", "approve", "page" } } 402 { "error": "free_limit", "message": "…", "resetsAt": "…", "launched": true, "need": 2, "buy": { … } } no key, and today's free calls are used up 429 { "error": "free_limit", "message": "…", "resetsAt": "…", "launched": false } before launch, free calls used up ``` `pricePerCredit` is in whole tokens as a string. `call` is `buyFor(address account, uint256 credits, uint256 maxBurn)`. ### Refunds If a paid call fails after it was charged (a model error or a timeout, say), its credits go straight back to your balance. Every refund, paid or free, is listed in a public log: GET https://aicrush.lol/api/credits/refunds?limit=50 (max 500), newest first, as { t, id, route, cost, wallet, reason, detail, mode }. ### Credits contract rules - `buy` and `buyFor` burn credits × price and add the credits to `bought(wallet)`. At most 1,000,000 credits per purchase. Zero credits or a zero wallet revert, and so does a cost above `maxBurn`. - The owner can pause buying and set the price per credit between 0.001 and 10,000,000 tokens. Nothing else: no withdrawals, no minting credits, no editing balances. The contract never holds tokens. - Reads: `price()`, `bought(address)`, `totalCredits()`, `totalBurned()`, `paused()`. - Credits: - $CRUSH token: ## ERC-8004 agent identity Crush Companions is an ERC-8004 agent. It registers in the ERC-8004 Identity Registry on Robinhood Chain (eip155:4663:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432) at launch. - Registration file: https://aicrush.lol/.well-known/agent-registration.json - Identity Registry: https://robinhoodchain.blockscout.com/address/0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 - Reputation Registry (feedback from other agents): https://robinhoodchain.blockscout.com/address/0x8004BAa17C55a88189AE136b182e5fdA19dE9b63 - Sitemap: https://aicrush.lol/sitemap.xml