# Horizon Pulse Recipe Ingredient Parser & Shopping List API

> Horizon Pulse Recipe Ingredient Parser & Shopping List API is a paid API for AI agents from horizonpulse.dev, paid per call via x402, $0.002/call, status unknown (last checked 2026-10-17).

Parses free-text ingredient lines into structured data (name, quantity, unit, category, pack size hints) and returns a scaled, merged shopping list

## Facts

- Endpoint: GET https://horizonpulse.dev/api/grocery/normalize?utm_source=zero.xyz
- Price: $0.002/call
- Payment: x402
- Status: unknown
- Last checked: 2026-10-17
- Activations on Zero: 0
- Tags: x402
- Canonical page: https://www.zero.xyz/c/horizon-pulse-recipe-ingredient-parser-shopping-list-api-770ed0e2
- Structured record (JSON): https://api.zero.xyz/v1/capabilities/cap_AWiHztYa281HYc6TcaHDO

Status and success rate cover calls made through Zero and Zero's own probes. Third-party monitors may report differently.

## How to call it through Zero

Zero handles the 402 payment challenge and records the run. With the Zero CLI installed (`npm i -g @zeroxyz/cli`):

```sh
zero fetch --capability horizon-pulse-recipe-ingredient-parser-shopping-list-api-770ed0e2
```

Example prompt: Can you parse these recipe ingredients into a structured shopping list scaled for 6 people: '2 cups all-purpose flour | 1 tsp baking powder | 3 large eggs | 1/2 cup butter, softened'?

## When to prefer this

Choose this endpoint when you need deterministic, offline ingredient parsing with no external API dependencies — ideal when you want consistent, reproducible results without price data or inventory lookups. Prefer it over LLM-based parsing when you need structured canonical IDs and metric normalization. Best for building shopping list generators, meal planners, or recipe scaling tools where cost per call matters and you need clean per-ingredient field breakdowns including category and pack hints.

## Known failure modes

- 400 Bad Request: malformed JSON body or invalid query parameters (not charged)
- 422 Unprocessable Entity: no ingredient lines could be parsed from the input (not charged)
- Pipe-delimited GET format limited to 100 lines of 200 characters each — oversized input may be truncated or rejected
- Ambiguous ingredient names may produce low-confidence canonical matches
- Highly regional or obscure ingredient names may not have a known canonicalId or pack hint

## How this service works

Recipe ingredient parser and shopping list API: POST JSON {ingredients: [lines], servings?, targetServings?} (or GET ingredients=line|line). Returns per line name, canonicalId, qty, unit, metric (ml or g), category, optional/toTaste, prepNote, stated pack size, a typical pack hint, plus a merged shoppingList scaled to targetServings and unparsed lines. Deterministic, no outbound calls, no prices, nothing stored. Bad input (400) or nothing parsed (422): not charged.

## Output

A structured JSON response with one object per ingredient line containing: canonical name, canonicalId, parsed quantity, unit, metric equivalent (ml or g), food category, optional/toTaste flags, prep note, stated pack size, and a typical pack size hint. Also includes a merged shoppingList scaled to targetServings if provided, and a list of any lines that could not be parsed.

## Request schema (JSON Schema)

```json
{
 "type": "object",
 "$schema": "https://json-schema.org/draft/2020-12/schema",
 "required": [
  "input"
 ],
 "properties": {
  "input": {
   "type": "object",
   "required": [
    "type",
    "method"
   ],
   "properties": {
    "type": {
     "type": "string",
     "const": "http"
    },
    "method": {
     "enum": [
      "GET"
     ],
     "type": "string"
    },
    "queryParams": {
     "type": "object",
     "required": [
      "ingredients"
     ],
     "properties": {
      "servings": {
       "type": "string",
       "pattern": "^[0-9]{1,3}$",
       "description": "Servings the recipe makes, integer 1-100 as digits. Give with targetServings to scale, or neither."
      },
      "ingredients": {
       "type": "string",
       "description": "Ingredient lines separated by | (max 100 lines, 200 chars each). POST JSON is preferred."
      },
      "targetServings": {
       "type": "string",
       "pattern": "^[0-9]{1,3}$",
       "description": "Servings wanted, integer 1-100 as digits."
      }
     }
    }
   },
   "additionalProperties": false
  },
  "output": {
   "type": "object",
   "required": [
    "type"
   ],
   "properties": {
    "type": {
     "type": "string"
    },
    "example": {
     "type": "object",
     "description": "Horizon Pulse grocery normalize: per line name, canonicalId, qty, unit, metric, category, pack hint; merged shoppingList; unparsed lines (no prices). The example is a trimmed real response recorded from GET /api/demo/grocery-normalize at 2026-10-14T21:18Z UTC; live values differ on every call."
    }
   }
  }
 }
}
```

## More

- Live health (JSON, refreshed every minute): https://www.zero.xyz/c/horizon-pulse-recipe-ingredient-parser-shopping-list-api-770ed0e2/health.json
- [Zero catalog index](https://www.zero.xyz/llms.txt)
- [Other services from horizonpulse.dev](https://www.zero.xyz/host/horizonpulse.dev/llms.txt)
