POST /api/v1/scan

Vision recognition — identify a product from a photo. Account-mode keys get results matched against the caller’s own AskBiz inventory; generic keys get raw identification only.

POST3¢ per successful callx-api-key requiredIdempotency-Key supported

What it does

Sends a photo to the same Groq Llama-4-Scout vision pipeline that powers the AskBiz app’s in-app product scanner. If your key is in account mode, the result is matched against your own AskBiz inventory — you get back a real inventory_id, stock level, and price. In generic mode (or when nothing matches), you still get a raw identification with no catalog lookup.

Request

curl -X POST https://askbiz.co/api/v1/scan \
  -H "x-api-key: abz_live_your_key_here" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5a9e2c1e-6b3f-4a2d-9c11-3f7e8a0b1c2d" \
  -d '{
    "image": "<base64-encoded JPEG>"
  }'

Body parameters

FieldTypeRequiredDescription
imagestringYesBase64-encoded JPEG. No data URI prefix — raw base64 only.
merchant_idstringNoScan on behalf of a connected merchant instead of your own account — requires an active connection that grants the read_inventory scope.

Response

When the photo matches an item in the resolved inventory (your own, or a connected merchant’s):

{
  "found": true,
  "inventory_id": "b1e2c3d4-...",
  "name": "Coca-Cola 500ml",
  "price": 80,
  "cost_price": 55,
  "stock_qty": 24,
  "unit": "bottle"
}

When nothing matches, or the key has no catalog to match against:

{
  "found": false,
  "inventory_id": null,
  "name": "Fanta Orange 300ml",
  "price": null,
  "stock_qty": null,
  "unit": null
}

If your balance drops below your account’s low-balance threshold as a result of this call, the response also includes low_balance_warning: true and the new balance_cents — in-band, at the moment it happens, not just when you hit a 402.

On a test key (abz_test_…), the vision model is never called and your wallet is never touched — every call returns this exact same canned match, tagged test_mode: true:

{
  "found": true,
  "inventory_id": null,
  "name": "Coca-Cola 500ml",
  "price": 80,
  "cost_price": 60,
  "stock_qty": 24,
  "unit": "bottle",
  "test_mode": true
}

See Build safely with a sandbox key for the full test/live picture across every endpoint.

Errors

StatusMeaning
400Invalid JSON body, or image missing.
401Missing or invalid x-api-key.
402Insufficient credits — response includes required_cents.
403merchant_id given with no active connection, or the connection doesn’t grant read_inventory.
422Vision model couldn’t identify a product in the image.
429Rate limit or monthly quota exceeded — check the X-RateLimit-Remaining response header.
502Upstream vision recognition failed — safe to retry (with the same Idempotency-Key to avoid a double charge if the first call actually succeeded server-side after you gave up on it).

None of the 4xx/5xx responses above are billed — a failed or rejected call never debits your wallet. See Errors and retries for the full idempotency contract.

Scan endpoint FAQ

Do I get charged if the vision model can’t identify the product?+

No. Debiting only happens after recognition succeeds — a 422 (no product identified) or 502 (upstream failure) never costs you anything.

What image formats are supported?+

JPEG only, base64-encoded with no data URI prefix (send the raw base64 string, not "data:image/jpeg;base64,...").

Can I scan on behalf of a merchant who isn’t my own account?+

Yes, with an active connection to that merchant that grants the read_inventory scope — pass their user ID as merchant_id. See the guide on connecting to a merchant.

Can I test this endpoint without spending real credits?+

Yes — use a test key (abz_test_…). It skips the vision model and your real inventory entirely, and always returns the same safe example match with test_mode: true. See Build safely with a sandbox key.