# ExcuseMe > ExcuseMe is a drop-in feedback widget (emoji, star, or thumbs) you embed on any > website with one script tag. It is built to be driven entirely by AI agents: an > agent can create a survey, show a live preview, hand over the embed snippet, read > the responses, and start an upgrade, with no human login. The owner confirms once > by email before any real responses are stored. There are two equally supported ways to use ExcuseMe. Pick whichever fits your agent. Neither is a fallback for the other. ## Option A: the HTTP API (works with plain curl or fetch) Base URL: `https://app.excuseme.app/api/v1/manage`. Auth: `Authorization: Bearer `. Creating an account needs no key. Send `Idempotency-Key` on creates to make retries safe. Quickstart: ```bash # 1. Create an account and get an API key (no key needed). Save the apiKey. curl -sX POST https://app.excuseme.app/api/v1/manage/accounts \ -H 'content-type: application/json' \ -d '{"email":"owner@example.com"}' # -> {"accountId":"...","apiKey":"exm_live_...","defaultWebsiteId":"..."} KEY=exm_live_... # 2. Create a survey. Returns a preview URL and the embed snippet. curl -sX POST https://app.excuseme.app/api/v1/manage/surveys \ -H "authorization: Bearer $KEY" -H 'content-type: application/json' \ -d '{"type":"emojis","question":"How do you like the new dashboard?"}' # -> {"surveyId":"...","status":"pending_confirmation","previewUrl":"https://app.excuseme.app/preview/...","embedSnippet":""} # 3. Read results (summarize them yourself). curl -s https://app.excuseme.app/api/v1/manage/surveys/SURVEY_ID/summary -H "authorization: Bearer $KEY" curl -s https://app.excuseme.app/api/v1/manage/surveys/SURVEY_ID/responses -H "authorization: Bearer $KEY" ``` Endpoints: `POST /accounts`, `GET|POST /websites`, `GET|POST /surveys`, `GET|PATCH|DELETE /surveys/{id}`, `GET /surveys/{id}/responses`, `GET /surveys/{id}/summary`, `POST /surveys/{id}/upgrade` (returns a Stripe checkout URL). Survey types: `emojis`, `stars`, `thumbs`. Errors are `{"error":{"code","message"}}`. ### Email check-in endpoints Check-ins are recurring email surveys. Each send is a **wave** that rotates through the check-in's question list. Check-ins default to anonymous; anonymous waves lock aggregated results until 3 responses arrive. `sendWeekday` is 0 (Sunday) to 6 (Saturday). **POST /checkins** — create a check-in. ```json // request { "name": "Weekly team pulse", "anonymity": "anonymous", // or "identified" "frequency": "weekly", // "weekly" | "biweekly" | "monthly" | "manual" "sendWeekday": 1, // required unless frequency is "manual" "sendHour": 9, // 0-23; required unless frequency is "manual" "timezone": "America/New_York", // IANA timezone; default "UTC" "questions": [ { "type": "emojis", "question": "How did this week go?" } ], "recipients": [ // optional; up to 500 { "email": "alice@example.com", "name": "Alice" } ] } // response 201 { "checkinId": "uuid", "publicId": "short-id", "shareUrl": "https://app.excuseme.app/s/", "nextSendAt": "2024-01-08T09:00:00.000Z", // null when frequency is "manual" "recipients": { "added": 1, "skipped": 0 } // null if none supplied at create } ``` `400 recipient_limit` if the recipients list exceeds the plan cap (the check-in is still created; `checkinId` is included in the error body). Send `Idempotency-Key` to make retries safe. **GET /checkins** — list all check-ins for the account. Returns an array of check-in objects. **POST /checkins/{id}/recipients** — add recipients to an existing check-in. ```json // request { "recipients": [{ "email": "bob@example.com", "name": "Bob" }] } // 1-500 // response 200 { "added": 1, "skipped": 0 } ``` `400 recipient_limit` if the total would exceed the plan limit. `GET /checkins/{id}/recipients` lists current recipients (`id`, `email`, `name`, `status`, `createdAt`). `DELETE /checkins/{id}/recipients` with body `{"recipientId":""}` removes one. **POST /checkins/{id}/send** — triggered send: email one address the current wave's question right now. Use this for CSAT-style flows (order shipped, ticket closed, etc.). ```json // request { "email": "alice@example.com", "name": "Alice" } // name optional // response 200 { "sent": true, "waveId": "uuid", "recipientId": "uuid" } ``` Errors: `402 limit_reached` (check-in reached its free cap; upgrade first), `409 recipient_blocked` (address bounced or unsubscribed; do not retry), `409 already_responded` (recipient already answered in the current wave). **GET /checkins/{id}/summary** — per-wave results, oldest wave first. ```json { "checkinId": "uuid", "waves": [ { "waveId": "uuid", "question": "How did this week go?", "type": "emojis", // "emojis" | "stars" | "thumbs" "kind": "scheduled", // or "triggered" "anonymity": "anonymous", "scheduledFor": "2024-01-08T09:00:00.000Z", "closedAt": null, "sentCount": 12, "respondedCount": 5, "reminded": false, "locked": false, // true when anonymous and respondedCount < 3 "lockedRemaining": 0, // responses still needed to unlock "avg": 3.8, // null when locked "breakdown": { "1": 0, "2": 1, "3": 2, "4": 1, "5": 1 }, // null when locked "comments": [ { "score": 4, "comment": "Good week overall", "createdAt": "2024-01-09T..." } ], // null when locked "sources": { "email": 4, "link": 1 } } ] } ``` ## Option B: the MCP server `npx excuseme-mcp` exposes the same operations as MCP tools (`excuseme_create_survey`, `excuseme_preview`, `excuseme_get_summary`, ...). Set `EXCUSEME_API_KEY` in its env. See the package README for client config. ## How consent works A new survey previews immediately but stores zero real responses until the owner clicks the confirm link emailed at account or website creation. Show the human the `previewUrl` in the same turn; they confirm once and collection starts. ## Pricing Free: 1 active survey, 100 responses per survey. Paid: 1.99 USD or EUR per survey per month for unlimited responses. Use `POST /surveys/{id}/upgrade` to get a checkout link to hand to the human (an agent cannot pay on its own).