
Potatoes and grain
298 kcal estimated
345 kcal reference
The model called the quinoa couscous. Review food identity as well as the total.
Inspect saved JSON →Send one image. Get foods, estimated portions, calories, protein, carbs and fat in structured JSON. Pay by card for scan credits, or buy a single analysis with x402. No subscription.
Inspect the foods, portions and JSON before funding an agent. These are saved benchmark estimates from our current model, not fresh scans. The measured-reference calories show where an estimate can miss.

298 kcal estimated
345 kcal reference
The model called the quinoa couscous. Review food identity as well as the total.
Inspect saved JSON →
354 kcal estimated
292 kcal reference
The reference includes sweet potato and oil. A photo can miss preparation details.
Inspect saved JSON →
212 kcal estimated
153 kcal reference
The portion estimate is too high in this example. Review estimated grams before logging.
Inspect saved JSON →Nutrition5k, Thames et al., CC BY 4.0. Images unchanged. JSON includes source links, original model evidence and measured-reference details. Machine-readable example catalog · Full benchmark and limits.
Card credits: create and save a key, generate a checkout URL, and let the cardholder complete payment. Then call REST or MCP with the funded key. x402: use an authorized Base USDC wallet for autonomous per-call payment.
Run the complete card-credit quickstart · Read the machine guide
Buy 500 scan credits for $5 through Stripe. The price includes applicable tax. No subscription, and unused credits do not expire. Save the API key before checkout, then configure it in your agent’s private environment. One credit pays for one successful analysis through REST or MCP. Failed analyses return the reserved credit.
// Load an ID saved for this intended scan before making the request.
// Reuse it with the same image and API key after a lost response.
const requestId = savedRequestId;
const response = await fetch("https://kcalsnap.com/api/v1/analyze", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KCALSNAP_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": requestId
},
body: JSON.stringify({ image_base64, mime_type: "image/jpeg" })
});Download the runnable Node quickstart. It reads an image file, saves the request ID before sending, and reuses completed results without another credit. No dependencies or wallet required.
Check remaining credits with GET /api/v1/credits/balance using the same Bearer key. For MCP, configure the Authorization header on the HTTP connection. The tool then uses credits without a crypto payment adapter.
Agents can create a checkout link with POST /api/v1/credits/checkout, a Bearer key and {"order_id":"UUID_V4"}. Generate the key as kcs_live_ followed by 32 cryptographically random bytes encoded as 64 lowercase hex characters. Persist both values before the request. The response contains checkout_url for the cardholder to complete. Reuse the same order ID on checkout retries. After payment, Stripe's webhook adds credits automatically; POST /api/v1/credits/confirm with {"session_id":"cs_live_..."} can also verify it. Only verified paid sessions grant credits.
Card funding uses Stripe Checkout. It requires the cardholder to complete checkout. Direct agent card payment through shared payment tokens or MPP is not enabled. Agents that need autonomous pay-per-call purchasing can use the existing x402 flow below.
https://kcalsnap.com/mcp.No-food results and analysis failures are not charged. If payment confirmation is uncertain, retry the same request and signed authorization. The API saves the result and reconciles the original payment.
Use an x402-compatible client with a funded Base USDC wallet. This example uses the official TypeScript SDK. Supply a JPEG or PNG as base64, up to 2 MB and 2048 pixels per side.
import { readFileSync } from "node:fs";
import { x402Client } from "@x402/core/client";
import { ExactEvmScheme } from "@x402/evm/exact/client";
import { wrapFetchWithPayment } from "@x402/fetch";
import { privateKeyToAccount } from "viem/accounts";
const signer = privateKeyToAccount(process.env.AGENT_WALLET_KEY);
const client = new x402Client()
.setSpendControls({ maxAmountPerPayment: "$0.01" })
.register("eip155:8453", new ExactEvmScheme(signer));
const paidFetch = wrapFetchWithPayment(fetch, client);
const response = await paidFetch("https://kcalsnap.com/api/v1/analyze", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID()
},
body: JSON.stringify({
image_base64: readFileSync("lunch.jpg").toString("base64"),
mime_type: "image/jpeg",
language: "en"
})
});
console.log(response.status, await response.json());
Already know the meal weight? Add known_total_grams to the JSON or MCP request: 1 to 5000 grams, with at most two decimals, excluding the plate and inedible parts. KcalSnap uses that total and estimates each food's share from the photo. The response labels this in portion_basis; ingredient weights and nutrition remain estimates. Weigh everything shown, including sides, sauces and drinks. Omit the field when unknown or if only part of the meal was weighed. Use a new idempotency key if the weight changes.
Configure your client's spending policy before using automatic payment. For recovery after a lost response, persist the original request key and signed PAYMENT-SIGNATURE. Do not start a fresh payment for a pending request.
{
"request_id": "...",
"dish_name": "Cooked rice",
"items": [{
"name": "Cooked rice",
"estimated_grams": 100,
"nutrition_source": "usda",
"nutrition": {
"kcal": 130, "protein_g": 2.7,
"carbs_g": 28.2, "fat_g": 0.3
}
}],
"totals": {
"kcal": 130, "protein_g": 2.7,
"carbs_g": 28.2, "fat_g": 0.3
},
"estimated_total_grams": 100,
"estimate": true
}Illustrative response excerpt. The full output is described in the schema. A successful response includes a PAYMENT-RESPONSE header with the settlement transaction.
Connect a client supporting Streamable HTTP to:
https://kcalsnap.com/mcpThe analyze_food tool accepts the image, MIME type, language, optional known_total_grams and an idempotency_key. Tool discovery is free. Paid calls use the official @x402/mcp convention: payment in params._meta["x402/payment"], receipt in _meta["x402/payment-response"].
Your MCP client can send a prepaid Bearer API key, or use x402 with a payment adapter. An ordinary chat client will not automatically gain wallet or card access.
English and Lithuanian output are supported. Food database queries remain in English.
A photo does not reveal exact portion weight, oil, ingredients or preparation. Use this for food logging and meal summaries. It does not establish medical nutrition needs or allergen safety.
Our September 2026 baseline benchmark used matcher v4 on 48 source groups from Nutrition5k, with weighed ingredient masses and database-calculated nutrition references. Two passes used Gemini 3.1 Flash Lite:
| Measure | Observed result |
|---|---|
| Calories within 25% of reference | 50.0% of 96 outcomes |
| Median absolute calorie percentage error | 25.1% |
| Mean absolute calorie error | 103 kcal |
| Warm nutrition-pipeline median / p95 | 2.04 s / 3.36 s |
This is a limited research sample, not a guarantee for your photos. Those timings exclude payment settlement and public API network overhead. Production now uses matcher v8 with preparation and food-identity fixes. The table records the historical v4 pipeline. Read the separate DFood confirmation results for matcher v7. Read the October matcher audit and dataset follow-up. model_confidence is the model's own rating, not a calibrated probability of accuracy.
Keep the request_id from a successful result or analysis error when contacting hello@kcalsnap.com about a scan.
| Response | Agent action |
|---|---|
| 200 | Save the JSON result and payment receipt. |
| 400 / 413 / 415 | Fix the input. No payment is submitted. |
| 402 | Inspect the advertised terms before signing a payment. |
| 409 | If in progress, retry unchanged. If conflicting, recover the original request. |
| 410 | The 24-hour result recovery window has expired. |
| 422 | No food detected. No payment is submitted. |
| 429 | Capacity, repeated-failure or spending limit reached. Respect Retry-After; no payment or credit is consumed. |
| 503 payment_pending | Wait 60 seconds. Retry the exact image, key and signed authorization. Do not pay again. |
Initial capacity: 200 new analyses per rolling day across the beta, 30 per hour, 100 per wallet or API key per day, and 3 concurrent analyses. x402 has a shared allowance of 100 attempts per rolling day, 15 per hour and 2 concurrent jobs within those totals. After 25 unsuccessful analyses per wallet or API key in a rolling day, new requests may pause; provider rejection errors are excluded. Completed results can still be replayed. Limits may change as the beta grows. Mainnet Base, native USDC and externally owned wallets are supported. Other networks, tokens and smart-contract wallets are not yet supported.
KcalSnap does not persist submitted images. They are processed through OpenRouter and its Gemini provider. Food names go to USDA. Successful result text can be recovered for 24 hours; expired completed results are removed when the API next records a request. Results awaiting payment reconciliation stay until resolved. We retain request fingerprints, wallet addresses and payment records for retries, abuse prevention and accounting. On-chain payments are public. See our privacy policy.
Card payments are handled by Stripe. KcalSnap stores API key fingerprints, credit balances and purchase records, never full API keys or card details on the server. Refunds or disputes pause the affected key for support review. Crypto payment is facilitated by PayAI and received in a dedicated KcalSnap wallet. Never send funds directly to the wallet as a top-up; use the authorization returned by the API. For a paid request you cannot recover, email hello@kcalsnap.com with the request ID and transaction hash, never your private key.