# KcalSnap agent API > Estimate calories, protein, carbohydrates, fat and edible portion sizes from a food photo. REST and MCP. Public beta. - Documentation: https://kcalsnap.com/developers/ - Runnable card-credit guide: https://kcalsnap.com/developers/quickstart/ - Dependency-free Node 22+ client: https://kcalsnap.com/developers/quickstart.mjs - Saved example catalog (no key or payment): https://kcalsnap.com/developers/examples/catalog.json - OpenAPI: https://kcalsnap.com/openapi.json - REST: POST https://kcalsnap.com/api/v1/analyze - MCP: https://kcalsnap.com/mcp (stateless Streamable HTTP, analyze_food tool) - Price: 0.01 USDC for one successful analysis. x402 v2 exact payments on Base (eip155:8453). No signup, subscription or API key needed for x402. - Health: https://kcalsnap.com/api/health - Support: hello@kcalsnap.com ## Inputs JSON: image_base64 (raw base64 JPEG/PNG), mime_type (image/jpeg or image/png), language (en or lt, defaults to en). Optional known_total_grams: measured edible food weight, 1 to 5000 grams with at most two decimal places, excluding the plate and inedible parts. Omit when unknown; never invent a measurement. Maximum 2 MB decoded image, 16 through 2048 pixels on each side, 20 detected components. REST requires Idempotency-Key: 16 to 128 letters, digits, underscores or hyphens. MCP takes idempotency_key as a tool argument. ## x402 payment An unpaid REST request returns HTTP 402 with a PAYMENT-REQUIRED header and the same x402 PaymentRequired JSON in its body. Use a funded Base USDC wallet through an x402-compatible client. EOA wallets only in this beta. Check the exact price, asset, chain and recipient against your budget and policy before authorizing payment. Retry with PAYMENT-SIGNATURE containing the base64-encoded x402 PaymentPayload. MCP uses params._meta["x402/payment"] and returns _meta["x402/payment-response"]. MCP discovery and initialization are free. Payment-required JSON-RPC errors use code -32042 with PaymentRequired data, as supported by @x402/mcp. A successful REST response includes PAYMENT-RESPONSE containing the settlement receipt. No-food results and analysis failures do not submit payment. Settlement follows a validated, saved result. Card-funded credits are available as an alternative, described below. ## Safe retries Persist the input, Idempotency-Key and signed payment authorization until you have the result. Always retry those exact same values together. A fresh authorization is a different purchase. After 503 payment_pending, wait 60 seconds and retry unchanged. Do not generate a new payment. 409 in_progress means wait and retry unchanged. 409 idempotency_conflict means the input, key or authorization differs from the original. A paid response is recoverable for 24 hours. 410 means the recovery window expired. 429 rate_limited, failure_limit or spend_limited means new requests are temporarily limited. No payment or credit is consumed. Respect Retry-After (3600 seconds for failure/spending limits, otherwise 60); this is a retry hint, not guaranteed recovery. Completed requests can still be replayed. If unresolved, contact support with request ID and transaction hash. Never share wallet private keys. Keep request_id from results and analysis errors for support at hello@kcalsnap.com. ## Output and limits Returns request_id, dish_name, items, totals (kcal, protein_g, carbs_g, fat_g), estimated_total_grams, model, matcher_version, estimate=true and processing_ms. Each item includes name, query, estimated_grams, model_confidence, nutrition_source (usda or ai), fdc_id, matched_name, per_100g and nutrition. When known_total_grams is supplied, component weights are allocated proportionally from the photo estimates and sum to that total. portion_basis identifies supplied_total and photo_estimated_proportions. The supplied weight must cover every detected component, including sides, sauces and drinks. Omit it when only part of the pictured meal was weighed. Changing or removing the weight requires a new idempotency key. Individual component weights, food identity and nutrition remain estimates. All photo-only portions and nutrition are estimates. model_confidence is not calibrated accuracy. Do not infer allergen safety or medical suitability. Historical September 2026 Nutrition5k benchmark (matcher v4): 48 source groups, 2 passes, 96 Gemini 3.1 Flash Lite outcomes. 50.0% within 25% of calorie reference; median absolute calorie error 25.1%; mean absolute calorie error 103 kcal. References use weighed ingredients and database nutrition, not chemical assays. Production now uses matcher v8; these historical scores are not a v8 accuracy claim. Matcher audit: https://kcalsnap.com/journal/nutrition5k-calorie-benchmark/#matcher-update Historical v4 warm pipeline median 2.04 seconds, p95 3.36 seconds, excluding payment/network overhead. This is not an API latency guarantee. Historical v7 DFood measured-photo study and frozen confirmation: https://kcalsnap.com/journal/dfood-weighed-photo-benchmark/ Machine-readable benchmark results: https://kcalsnap.com/journal/dfood-weighed-photo-benchmark/results.json Beta limits: 200 new analyses per rolling 24 hours globally, 30 per hour globally, 100 per wallet or API key per day, 3 concurrent globally. Within those totals, x402 has 100 attempts per rolling day, 15 per hour and 2 concurrent jobs. After 25 unsuccessful analyses per wallet/key in a rolling day, new requests may pause; provider rejection errors are excluded. ## Privacy KcalSnap does not persist images. Images are processed through OpenRouter and its Gemini provider; food names go to USDA. Text results are available for 24 hours, then removed on subsequent API activity. Unresolved payment results remain until reconciled. Request fingerprints, wallet addresses and settlement records remain for accounting and retry protection. Blockchain transactions are public. See https://kcalsnap.com/privacy.html. ## Card-funded scan credits Buy 500 successful scans for $5 USD, including applicable tax. No subscription. Unused credits do not expire. Human purchase and key backup: https://kcalsnap.com/developers/credits/ REST and MCP accept `Authorization: Bearer kcs_live_<64 lowercase hex characters>`. One credit per successful scan. Failed scans return the reservation. Retries with the same key, input and Idempotency-Key recover the original result for 24 hours without another credit. GET https://kcalsnap.com/api/v1/credits/balance returns credits_remaining, blocked and test_mode. Bearer authentication required. POST https://kcalsnap.com/api/v1/credits/checkout accepts {"order_id":"UUID_V4"}. Use the same Bearer key and order ID on retries. It returns a Stripe checkout_url for the cardholder to complete. Generate an API key from 32 secure random bytes, hex encoded after kcs_live_. Save it before creating checkout. The server stores only its hash. Never put keys in URLs. Stripe webhooks grant credits after verified payment. POST /api/v1/credits/confirm with {"session_id":"cs_live_..."} and the original Bearer key provides recovery if needed. Card funding requires Stripe Checkout completion. Direct agent SPT/MPP card payments are not enabled. For autonomous per-call payment, use x402 with an authorized wallet. Shared beta capacity applies to both payment methods: 200 new scans per rolling day, 30 per hour, 100 per key/wallet per day, 3 concurrent. Credits do not reserve capacity. For unused-credit refunds contact hello@kcalsnap.com with a Stripe receipt. Never share the API key. Refunds/disputes pause the key for review. ## Runnable agent workflow Review/download quickstart.mjs, then run: node quickstart.mjs init; node quickstart.mjs checkout. init writes a private .kcalsnap/key and .gitignore; back up the key securely before funding. checkout returns a payment URL; give it to the cardholder with their approval. It never pays automatically. After payment, run node quickstart.mjs balance, then node quickstart.mjs scan lunch.jpg. Use --key-file=/private/path/key.txt on every command to reuse a website-downloaded key instead of generating one. The scan command persists a request ID before sending. Retry the same command and exact image after a connection failure. Respect retryAfter. Completed responses are cached in private local files. Identical repeated commands return the local result without another API call or charge. --new-scan explicitly starts another paid analysis only after a terminal previous result. Never replace an unresolved request with a new paid request. The client stops unresolved recovery after 24 hours. Contact support with the displayed Idempotency-Key and request ID if available. Keep local state, and investigate a stale .lock process before removing its lock file. For an explicitly authorized later top-up, checkout --new-order first inspects the original order through POST /api/v1/credits/checkout-status. It refuses to replace an open or unresolved checkout. Only paid, Stripe-confirmed expired or not_issued state allows a new link. not_issued requires an exhaustive bounded Stripe lookup with no matching session and an order older than 48 hours. Incomplete lookup stays unresolved. If a session could not be recovered, contact support with order_id. Optional checkout context: {"channel":"agent"}. Add discovery/use_case only when the owner stated them; never infer answers. All fields are optional. Enums are in OpenAPI. ## Request-linked feedback POST https://kcalsnap.com/api/v1/credits/feedback with the original Bearer key and {"request_id":"UUID_V4","category":"wrong_portion","note":"Optional actual feedback"}. Categories: helpful, wrong_food, wrong_portion, wrong_nutrition, integration_problem, other. Note maximum 500 characters. Never include API keys or personal information. Only completed credit-funded requests owned by the key and created within 90 days are eligible. MCP callers use this REST endpoint. x402 feedback goes to support with request ID. One submission per request; repeat identical payloads safely, changed payloads return 409. At most 10 per key and 1000 globally per rolling day; 429 means wait. Feedback does not change credits, trigger refunds or automatically change the model. Forward real user feedback; never fabricate approval or complaints. Feedback is removed after 90 days on the next eligible submission. See the privacy policy for server and local storage. Back up the complete .kcalsnap directory, not only the key. Checkout recovery state is local to this integration. Restoring only a key or using multiple independent clients can lose the original order ID; check existing payment links and balance before authorizing another purchase. The API supports multiple intentionally purchased packs per key.