# SalSmart MCP and API for AI agents — מחירי סופר בישראל

SalSmart provides Israeli grocery product search and per-branch prices derived from public supermarket price-transparency files. Search with Hebrew product names, manufacturer names, or barcodes. Prices are in Israeli new shekels (ILS).

- Human documentation: https://salsmart.com/agents
- Connect ChatGPT, Claude or a compatible MCP agent: https://salsmart.com/connect
- Public MCP endpoint: https://salsmart.com/mcp
- Privacy: https://salsmart.com/privacy
- Support: https://salsmart.com/support
- Production prepaid plan and checkout: https://salsmart.com/api-plan
- OpenAPI 3.1: https://salsmart.com/openapi.json
- Live source and refresh status: https://salsmart.com/api/data-status
- Crawlable product catalog: https://salsmart.com/products
- Dairy and eggs: https://salsmart.com/categories/dairy-eggs
- Bread and bakery: https://salsmart.com/categories/bread-bakery
- Rice, pasta, and legumes: https://salsmart.com/categories/rice-pasta-legumes
- Beverages: https://salsmart.com/categories/beverages
- Snacks and sweets: https://salsmart.com/categories/snacks-sweets
- Chains and branches: https://salsmart.com/stores
- Sitemap of exported pages: https://salsmart.com/sitemap.xml

## Public MCP: free, read-only tools

Connect a remote MCP client to **`https://salsmart.com/mcp`** using **Streamable HTTP**, with **no authentication / No sign in**. Salsmart does not require an account or API key for this connector. Follow https://salsmart.com/connect for host-specific instructions; availability depends on the host account and workspace policy.

The direct custom connector is ready. **Public ChatGPT and Claude directory listings have not been approved.** Adding the URL as a custom connector does not imply either platform has reviewed or listed Salsmart.

### Tools

- **`search_products`**: `{"q":"חלב תנובה","limit":5}`. `q` is a 2–100-character product name, manufacturer, or barcode **string**, with Hebrew support. Preserve leading zeros. `limit` is optional, an integer from 1 to 20, and defaults to 20. Verify the returned barcode for an exact match; this is text search, not a separate exact-lookup operation.
- **`get_data_status`**: `{}`. Returns the actual branch coverage, source publication and successful-fetch times, and counts of fresh/stale sources. Freshness requires a successful fetch within 12 hours and source publication within 72 hours.

Both tools read data only. They do not buy groceries, modify accounts, purchase API access or process payments. Never pass an API key, card data or claim token as a tool argument.

Search uses the existing free REST implementation and shares its allowance: **60 admitted requests per fixed UTC minute and 500 per UTC day per network address**. Users behind the same AI host or network can share the allowance. Validation failures do not consume search quota. An admitted query can consume a unit even if the result is empty or a later search failure occurs.

### Results and interface

`search_products` returns `query`, `count`, `products`, `currency: "ILS"`, `checked_at`, `citation_url` and `coverage_note` in `structuredContent`, plus a text result for clients without UI support. Products preserve the REST offer and source fields described below and add a `citation_url`. Product-page citations are only supplied for pages in the exported catalog; other results cite a public search request. Do not infer stock availability or the lowest price in Israel.

The optional interface is a self-contained **MCP App** resource at `ui://salsmart/search-v1.html`, MIME type `text/html;profile=mcp-app`. Compatible ChatGPT/Claude hosts can render comparison cards within the conversation. It calls the same read-only search tool through the host; a client without interface support still receives useful prices, timestamps, sources and coverage limitations.

Quota and service failures return an MCP tool result with `isError: true`. Their text content contains JSON `{"error":{"code":"...","message":"...","http_status":429,"retry_after_seconds":30}}`; values shown here are schematic. Honor the supplied retry delay. Other protocol/input-validation errors can use standard MCP error text. A failed tool call is not evidence that no matching product exists. Do not treat an error as a successful zero-result search.

The endpoint supports initialization, tool discovery/calls and resource listing/reading through the standard MCP SDK. It uses stateless HTTP POST requests, without persistent sessions or standalone SSE; GET and DELETE return 405. Use an MCP client rather than opening the endpoint as a web page. OpenAPI describes the separate REST routes, not the MCP protocol.

Read [privacy](https://salsmart.com/privacy) and [support](https://salsmart.com/support) for data handling and connection help.

## Free REST product search

`GET https://salsmart.com/api/product-search?q={query}&limit={limit}`

No API key, registration, or payment is required for this endpoint. `q` is required, must contain 2–100 characters, and accepts a name, manufacturer, or barcode. Whitespace is normalized. Multiple whitespace-separated terms are ANDed across name, manufacturer, and barcode; the first five terms are used. The optional `search` parameter is a legacy alias when `q` is absent. Prefer `q`.

`limit` defaults to 20 products and must be an integer between 1 and 20. Larger or malformed values return 400. The prepaid API supports up to 100 products. `count` is the number of products actually returned, not the total number of matching products. The endpoint has no pagination parameter. Results with no positive-price offers from active chains are excluded; this can produce fewer than `limit` products.

```sh
curl --get 'https://salsmart.com/api/product-search' \
  --data-urlencode 'q=חלב תנובה' \
  --data-urlencode 'limit=5'
```

```http
GET https://salsmart.com/api/product-search?q=7290000111186&limit=1
```

The barcode query searches the identifier text. Verify the returned `barcode` before treating a result as an exact match.

### Free quota

Free access permits **60 valid requests per fixed UTC minute and 500 per UTC day per network address**. People and agents on the same network share this allowance. Invalid queries and invalid limits do not consume a unit. Syntactically valid admitted attempts count even if no product matches or a later database/search error occurs. A denied quota request increments neither counter.

The response supplies `RateLimit-Policy`, `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`. The latter is a delay in seconds for the currently controlling window. HTTP 429 includes `Retry-After`; wait at least that many seconds. A positive remaining value is not a guarantee that the next request will succeed. Responses use `Cache-Control: no-store`.

The quota table contains a daily, purpose-scoped HMAC identifier and counters, without raw IP addresses, queries or keys. The server requires a trusted Cloudflare edge address and configured HMAC secret; if these or the database are unavailable it returns 503 rather than silently disabling the quota.


### Response shape

The following is schematic. The price, identifiers, and store name are placeholders, not a real offer.

```json
{
  "query": "שם מוצר",
  "count": 1,
  "products": [
    {
      "barcode": "ברקוד המוצר",
      "name": "שם המוצר כפי שפורסם במקור",
      "manufacturer": null,
      "unit_of_measure": "100 גרם",
      "image_url": null,
      "offers": [
        {
          "price": 12.5,
          "update_date": null,
          "store_id": "מזהה סניף",
          "chain_id": "מזהה רשת",
          "store_name": "שם סניף",
          "store_city": null,
          "chain_name": "שם רשת",
          "source_file": null,
          "source_url": null,
          "source_published_at": null,
          "fetched_at": null,
          "refresh_status": null
        }
      ]
    }
  ]
}
```

- `barcode`: string identifier. Preserve leading zeros. Do not assume every identifier is a validated GTIN.
- `name`, `manufacturer`: source product metadata; names can be abbreviated. Unknown metadata can be null.
- `unit_of_measure`: source measurement basis. It is not necessarily the package size; do not derive a package quantity or unit price from this field alone.
- `image_url`: optional product image URL; null means no image is available.
- `offers[].price`: positive price in ILS, at the identified chain and branch. Offers are ordered by ascending price within each product.
- `offers[].update_date`: source price-change timestamp, often `YYYY-MM-DD HH:mm:ss`, or null. This is not a file-fetch timestamp and does not establish when SalSmart last checked that price. The source may omit a timezone; do not invent one.
- `offers[].source_file` / `source_url`: last successful source filename and public provenance URL, when recorded. The URL may identify a listing or resolver; signed download tokens and credentials are omitted. FTPS sources need a compatible client.
- `offers[].source_published_at`: source-file publication time from its filename, in ISO 8601 with a timezone. This is separate from a product price change.
- `offers[].fetched_at`: last successful fetch/import time for this exact branch source, in ISO 8601 with a timezone. Null or absent means unknown.
- `offers[].refresh_status`: latest branch refresh outcome. A failed attempt retains previous successful data; inspect the timestamps rather than treating the status as a freshness guarantee.
- `chain_id` and `store_id`: use the pair to identify a branch. A `store_id` alone is not globally unique.
- `store_name`, `store_city`: source branch metadata, possibly null. A missing city must stay unknown.
- `chain_name`: source chain name.

### Status codes

- `200`: search succeeded. No results means `count: 0` and `products: []`.
- `400`: missing/invalid `q` or `limit`; error codes include `invalid_query` and `invalid_limit`. No free quota unit is consumed.
- `429`: `free_search_quota_exceeded`; honor `Retry-After` or use the prepaid API.
- `503`: `free_search_unavailable`; quota configuration, edge identity or search/database service is unavailable. Internal SQL details are not exposed. A failed query is not evidence that a product is unavailable. Use bounded retries.

## Production prepaid API for agents

The standard paid plan is a **one-time ILS 19 purchase for 1,000 successful-search credits**, with **no automatic renewal**. The unit cost is ILS 0.019 per newly completed search. The pack is prepaid, so the service does not charge a card per individual API call and cannot silently charge for another pack. Start through https://salsmart.com/api-plan after the user authorizes the payment and budget.

`GET https://salsmart.com/api/billing/checkout` reports `{enabled,plan}`. The plan uses `amount: 1900` agorot, `currency: "ils"`, and `credits: 1000`. If `enabled` is false, new purchases are unavailable; do not promise an active checkout.

### Purchase and receive access

1. After user authorization, send `POST /api/billing/checkout` with `Content-Type: application/json` and `{"plan":"starter"}`. Include `Authorization: Bearer <EXISTING_API_KEY>` only when topping up an existing account. Without it, the server starts a new account. An invalid supplied top-up key fails instead of creating a different account.
2. Save the returned `purchase_id` and private `claim_token` securely, then follow `checkout_url` to the Stripe payment page. Starting checkout is not payment and does not grant credit. Never put claim tokens, API keys or payment secrets into URLs, logs or analytics.
3. After payment, send `POST /api/billing/claim` with JSON `{"purchase_id":"<PURCHASE_ID>","claim_token":"<CLAIM_TOKEN>"}`. HTTP 202 means confirmation is pending; honor `Retry-After: 3` and poll with bounded retries. Only a verified settled payment grants credits.
4. A new account returns HTTP 200 with `status: "claimed"`, `api_key`, `key_prefix` and `credits_remaining`. Save the API key securely: the claim endpoint returns it once. A repeated completed claim returns 409 `key_already_claimed`. The browser completion flow can recover an interrupted first response using its still-private pending receipt. An existing-account top-up returns `status: "credited"`, `credits_added`, and `credits_remaining` without issuing a replacement key.

Do not send card details to Salsmart; card entry and payment happen on Stripe's hosted page. Payment review, refunds or disputes can suspend the associated account. Do not retry a charge automatically when payment status is uncertain; inspect the receipt and claim state.

### Paid search

`GET https://salsmart.com/api/v1/search?q={query}&limit={limit}`

- `Authorization: Bearer <API_KEY>` is required. Keys belong in the header, never a query parameter.
- `Idempotency-Key` is required: 8–128 ASCII letters/digits/dots/colons/hyphens/underscores, starting with a letter or digit. Use a different identifier for each new paid search.
- `q` is required and must be 2–100 characters. The paid v1 route requires `q` and does not accept the legacy `search` alias.
- `limit` is an integer from 1 to 100, default 20. Each returned product can include multiple branch offers. Source fields and limitations are the same as the basic search.
- Every newly completed **HTTP 200 search, including zero matching products, costs one credit**. Authentication, validation and internal failures consume no credits. Exhausted balance returns HTTP 402; there is no automatic top-up or automatic card charge.

```sh
curl --get 'https://salsmart.com/api/v1/search' \
  -H 'Authorization: Bearer <API_KEY>' \
  -H 'Idempotency-Key: agent-search-000001' \
  --data-urlencode 'q=חלב תנובה' \
  --data-urlencode 'limit=100'
```

The paid response includes the basic `{query,count,products}` fields plus `request_id`, `limit`, `generated_at`, and `billing: {credits:1,unit:"successful_search"}`. That body records the original purchased search cost and remains unchanged on replay. Read `X-Credits-Charged` to determine whether this response charged a new credit.

### Safe retries and the 24-hour replay window

If a timeout or temporary error leaves completion uncertain, retry the **same Idempotency-Key and the same parameters**. Concurrent or later retries within 24 hours return the identical purchased response without another debit, even if grocery prices subsequently change. Successful headers include:

- `X-Request-Id`: stable completed request ID.
- `X-Credits-Charged`: `1` for a new completion, `0` for replay.
- `X-Credits-Remaining`: observed account balance.
- `Idempotent-Replayed`: `true` or `false`.
- `Idempotency-Expires-At`: ISO 8601 UTC end of the 24-hour replay window, distinct from API-key validity.

Changed parameters under an unexpired key return 409 `idempotency_conflict`. After the replay window, the retained key tombstone returns **409 `idempotency_expired` and never charges again under that key**. An expired response cannot be replayed; use a new key only when the user wants a new paid search. Cached bodies are removed by bounded opportunistic cleanup, while small idempotency and accounting records remain. The 24-hour replay cutoff applies even if physical cleanup has not run yet.

Paid status codes: 400 invalid input/idempotency header; 401 invalid, inactive, expired or revoked API key; 402 `credits_exhausted`; 409 idempotency conflict/expiry; 413 oversized response with no charge (use a smaller limit and a new key); 503 temporary failure (retry with the same key). Private v1/billing responses use `Cache-Control: no-store`.

### Free balance check

`GET https://salsmart.com/api/v1/usage` requires the Bearer key but consumes no credit and needs no Idempotency-Key. It returns `account_id`, `key_prefix`, `credits_remaining`, `purchased_credits`, `consumed_credits`, `credit_cost_per_search: 1`, and `checked_at`. The complete API key is never returned here.

## Grounding an answer in the data

1. Match the returned identifier, name, manufacturer, and package information to the user's request. Do not expand abbreviated source names without evidence.
2. Cite the price, chain, branch, and source price-change date when known. Link to `https://salsmart.com/product/{barcode}` only when that page exists in the catalog/sitemap; otherwise cite the API request URL used to obtain the answer.
3. Say “lowest among the returned branches in the database” (Hebrew: “הזול מבין הסניפים שבמאגר”). Coverage is partial; this is not proof of the lowest price in Israel or a particular city.
4. Preserve old dates and nulls. `update_date: null` means the source price-change date is unknown, not today. Cite `fetched_at` separately when known; an old price-change date can be legitimate in a freshly retrieved file. Check `source_published_at` and the live source status before describing a result as recently verified.
5. A price record does not confirm inventory, delivery availability, or promotion eligibility. Prices may differ or change; verify with the store.

The API queries SalSmart's database when requested. Product and category pages are prebuilt snapshots and can differ from API results. Use the live source-status endpoint for the latest recorded refresh outcome. Neither surface guarantees real-time prices.

## Live provenance and freshness

`GET https://salsmart.com/api/data-status` requires no key or payment and returns uncached JSON. It reports `checked_at`, `updated_at`, `fresh_stores`, `total_stores`, `stale_stores`, and `sources`. Each source is identified by `chain_id` plus `store_id`, with `source_file`, `source_url`, `source_published_at`, `last_attempt_at`, `last_success_at`, `price_count`, `status`, and `last_error`. `last_success_at` is the branch-level value exposed as `offers[].fetched_at`.

The refresh schedule checks the configured branches every six hours. A scheduled check can fail; read the actual timestamps and outcomes. The current freshness rule requires a successful fetch within 12 hours and a source file published within 72 hours. Missing timestamps and future timestamps are not fresh. A failed attempt retains the prior successful data. `checked_at` only timestamps the status response, and `updated_at` is the latest successful branch fetch; neither establishes that all branches were refreshed. HTTP 503 means status is unavailable, not fresh.

Coverage is a limited comparison set, not every branch in the covered chains or every Israeli store. Read the live counts and branch metadata for the actual current coverage. Retailer price-change dates may be much older than file publication or fetch dates, including when a price has not changed for months.

## Optional x402 testnet endpoint

`GET https://salsmart.com/api/paid/product-search?q={query}&limit={limit}`

This is an x402 version 2 integration experiment on **Base Sepolia**, network `eip155:84532`. Its requested price is **0.01 testnet USDC per request**. It does not charge real money and does not purchase standard API credits. The same underlying data is available through basic free search within its quota, or through the production prepaid API with its larger search limit.

An unpaid request with a query receives HTTP `402`. Read the Base64-encoded JSON in the `PAYMENT-REQUIRED` response header and follow its current payment requirements. A compatible x402 client prepares the testnet payment authorization and retries with a `PAYMENT-SIGNATURE` request header. A settled success can include an `x402` object and payment response headers. Do not hard-code payment assets or recipient details from examples; read the challenge.

Payments require user authorization and a budget. This legacy x402 route advertises no production-network support. For real-money prepaid API access use https://salsmart.com/api-plan and `/api/v1/search`. A missing receiving-address configuration can return `503`.

## Connection and discovery

The public MCP connector at https://salsmart.com/mcp and the separate HTTP/JSON REST API are available. Custom-connector setup for ChatGPT, Claude and Grok Bot is documented at https://salsmart.com/connect; their marketplace submissions are awaiting review, not public approval. Grok Bot search, status, exact-barcode and no-match tool cases passed; its optional native widget is not verified. Read https://salsmart.com/developers for an executable free-search example and REST onboarding, https://salsmart.com/mcp-server.json for remote-server metadata, and https://salsmart.com/llms.txt for a short discovery index. The marketplace MCP is free and does not consume prepaid REST credits. Follow normal HTML links in the catalog to discover category pages and their product pages. OpenAPI describes REST routes only. Privacy and support are available at https://salsmart.com/privacy and https://salsmart.com/support.
