> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anyformat.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Receipt scanning

> Extract merchant, totals and payment method from receipt photos and scans

This example reads a receipt photo or scan and returns the merchant, the totals, the item count and how the purchase was paid. An `enum` field pins the payment method to a fixed set of names, and a `boolean` flags alcohol for expense policies.

<div className="af-payoff">
  <div className="af-payoff-pane">
    <div className="af-payoff-cap">The photo</div>

    <div className="af-payoff-line">
      <span className="af-mark">
        {'CORNER GROCERY'}
      </span>
    </div>

    <div className="af-payoff-line">
      {'2 x Sourdough loaf     7.00'}
    </div>

    <div className="af-payoff-line">
      {'1 x Olive oil         16.45'}
    </div>

    <div className="af-payoff-line">
      <span className="af-mark">
        {'TOTAL 23.45'}
      </span>
    </div>

    <div className="af-payoff-line">
      <span className="af-mark">
        {'VISA ****1234'}
      </span>
    </div>
  </div>

  <div className="af-payoff-arrow">→</div>

  <div className="af-payoff-pane">
    <div className="af-payoff-cap">What comes back</div>
    <div className="af-payoff-line"><span className="af-payoff-key">store\_name</span><b>{'Corner Grocery'}</b>{'  '}<span className="af-cite">97%</span></div>
    <div className="af-payoff-line"><span className="af-payoff-key">total\_amount</span><b>{'23.45'}</b>{'  '}<span className="af-cite">98%</span></div>
    <div className="af-payoff-line"><span className="af-payoff-key">payment\_method</span><b>{'credit_card'}</b>{'  '}<span className="af-cite">95%</span></div>
    <div className="af-payoff-line"><span className="af-payoff-key">contains\_alcohol</span>{'  '}<b>{'False'}</b>{'  '}<span className="af-cite">92%</span></div>
    <div className="af-payoff-line"><span className="af-payoff-key">tax\_amount</span><b>{'null'}</b></div>

    <div className="af-payoff-line">
      <span className="af-cite">
        {'↳ null means the line is not on the receipt'}
      </span>
    </div>
  </div>
</div>

<div className="af-cost">
  <span><b>Nodes</b><strong>Parse → Extract</strong></span>
  <span><b>Credits</b><strong>60 per page</strong>{' (Parse 25 + Extract 35, default tiers)'}</span>
  <span><b>You get</b>{' 8 fields, each with a confidence and its evidence'}</span>
</div>

## The workflow

<CodeGroup>
  ```json API theme={null}
  {
    "name": "Receipt scanning",
    "description": "Extract receipt details from photos and scans",
    "nodes": [
      { "id": "parse_1", "type": "parse" },
      {
        "id": "extract_1",
        "type": "extract",
        "extraction_schema": {
          "fields": [
            { "name": "store_name",      "description": "Name of the store or merchant", "data_type": "string" },
            { "name": "store_address",   "description": "Full address of the store location", "data_type": "string" },
            { "name": "receipt_date",    "description": "Date of the purchase transaction", "data_type": "date" },
            { "name": "total_amount",    "description": "Total amount charged including tax", "data_type": "float" },
            { "name": "tax_amount",      "description": "Total tax amount", "data_type": "float" },
            { "name": "number_of_items", "description": "Total number of items purchased", "data_type": "integer" },
            {
              "name": "payment_method",
              "description": "Payment method used for the transaction",
              "data_type": "enum",
              "enum_options": [
                { "name": "cash",           "description": "Cash payment" },
                { "name": "credit_card",    "description": "Credit card payment" },
                { "name": "debit_card",     "description": "Debit card payment" },
                { "name": "mobile_payment", "description": "Mobile or digital wallet payment" }
              ]
            },
            { "name": "contains_alcohol", "description": "Whether any alcoholic beverage was included in the purchase", "data_type": "boolean" }
          ]
        }
      }
    ],
    "edges": [{ "source": "parse_1", "target": "extract_1" }]
  }
  ```

  ```python Python theme={null}
  import os
  from anyformat.sdk import Client
  from anyformat.workflow import Schema

  client = Client(api_key=os.environ["ANYFORMAT_API_KEY"])

  workflow = (
      client.workflow("Receipt scanning", "Extract receipt details from photos and scans")
      .parse()
      .extract([
          Schema.string("store_name",       "Name of the store or merchant"),
          Schema.string("store_address",    "Full address of the store location"),
          Schema.date("receipt_date",       "Date of the purchase transaction"),
          Schema.float("total_amount",      "Total amount charged including tax"),
          Schema.float("tax_amount",        "Total tax amount"),
          Schema.integer("number_of_items", "Total number of items purchased"),
          Schema.enum("payment_method", "Payment method used for the transaction", options=[
              Schema.option("cash",           "Cash payment"),
              Schema.option("credit_card",    "Credit card payment"),
              Schema.option("debit_card",     "Debit card payment"),
              Schema.option("mobile_payment", "Mobile or digital wallet payment"),
          ]),
          Schema.boolean("contains_alcohol", "Whether any alcoholic beverage was included in the purchase"),
      ])
      .create()
  )
  ```

  ```typescript TypeScript theme={null}
  import { Anyformat, Schema } from "@anyformat/sdk";

  const af = new Anyformat({ apiKey: process.env.ANYFORMAT_API_KEY! });

  const workflow = await af
    .workflow("Receipt scanning", "Extract receipt details from photos and scans")
    .parse()
    .extract([
      Schema.string("store_name",       "Name of the store or merchant"),
      Schema.string("store_address",    "Full address of the store location"),
      Schema.date("receipt_date",       "Date of the purchase transaction"),
      Schema.float("total_amount",      "Total amount charged including tax"),
      Schema.float("tax_amount",        "Total tax amount"),
      Schema.integer("number_of_items", "Total number of items purchased"),
      Schema.enum("payment_method", "Payment method used for the transaction", [
        Schema.option("cash",           "Cash payment"),
        Schema.option("credit_card",    "Credit card payment"),
        Schema.option("debit_card",     "Debit card payment"),
        Schema.option("mobile_payment", "Mobile or digital wallet payment"),
      ]),
      Schema.boolean("contains_alcohol", "Whether any alcoholic beverage was included in the purchase"),
    ])
    .create();
  ```
</CodeGroup>

## Run it and read the result

Send the photo as the `files` field. JPG, PNG and PDF all work. Poll the run until its `status` is `processed`.

<CodeGroup>
  ```bash curl theme={null}
  # 1. Create the workflow with the JSON above
  curl -X POST 'https://api.anyformat.ai/v3/workflows/' \
    -H "Authorization: Bearer $ANYFORMAT_API_KEY" \
    -H 'Content-Type: application/json' \
    -d @receipt-workflow.json
  # → 201 { "id": "<workflow_id>", ... }

  # 2. Upload the receipt photo and start a run
  curl -X POST "https://api.anyformat.ai/v3/workflows/$WORKFLOW_ID/upload/run/" \
    -H "Authorization: Bearer $ANYFORMAT_API_KEY" \
    -F 'files=@receipt.jpg'
  # → 202 { "run_id": "<run_id>", "document_packet_id": "...", "status": "queued" }

  # 3. Poll until "status" is "processed"
  curl "https://api.anyformat.ai/v3/runs/$RUN_ID/" \
    -H "Authorization: Bearer $ANYFORMAT_API_KEY"
  ```

  ```python Python theme={null}
  result = workflow.run("receipt.jpg").wait()

  print(result.fields["store_name"].value)
  print(result.fields["total_amount"].value)
  print(result.fields["payment_method"].value)
  print(result.fields["contains_alcohol"].value)
  ```

  ```typescript TypeScript theme={null}

  import type { ExtractedField } from "@anyformat/sdk";

  const file = new File([readFileSync("receipt.jpg")], "receipt.jpg", { type: "image/jpeg" });
  const result = await (await workflow.run(file)).wait();

  console.log((result.field("store_name") as ExtractedField<string> | undefined)?.value);
  console.log((result.field("total_amount") as ExtractedField<string> | undefined)?.value);
  console.log((result.field("payment_method") as ExtractedField<string> | undefined)?.value);
  console.log((result.field("contains_alcohol") as ExtractedField<string> | undefined)?.value);  // "True" or "False"
  ```
</CodeGroup>

## Response

The `results` envelope of a processed run, trimmed. Every value is a string on the wire, including booleans (`"True"` / `"False"`) and numbers. A field the model could not find comes back with `value: null` and `confidence: null`, as `tax_amount` does on this receipt.

```json Response highlight={6,8} theme={null}
{
  "results": {
    "extractions": [{ "fields": {
      "store_name":       { "value": "Corner Grocery", "confidence": 97.0, "evidence": [{ "text": "CORNER GROCERY", "page_number": 1 }] },
      "total_amount":     { "value": "23.45", "confidence": 98.0, "evidence": [{ "text": "TOTAL 23.45", "page_number": 1 }] },
      "tax_amount":       { "value": null, "confidence": null, "evidence": [] },
      "payment_method":   { "value": "credit_card", "confidence": 95.0, "evidence": [{ "text": "VISA ****1234", "page_number": 1 }] },
      "contains_alcohol": { "value": "False", "confidence": 92.0, "evidence": [] }
    } }]
  }
}
```

Every field also carries `verification_status` and `value_override`. [Runs and results](/concepts/runs-and-results) has the full envelope, section by section.

## When it goes wrong

**The tax line comes back `null`.** Faded thermal paper loses the tax line before it loses the total. A field the model cannot find returns `value: null` and `confidence: null`, which means "not on the receipt", not zero. Treat it as missing, and do not default it to `0` before someone has looked.

**A boolean branch never fires.** `contains_alcohol` arrives as the string `"True"` or `"False"`, like every other value on the wire. `if (row.contains_alcohol)` is true for both. Compare against the string, or cast it, before you branch.

**The payment method comes back empty.** An `enum` constrains the output to the option names you declared, so a receipt paid a way you did not list has nothing to match. That is what stops "Visa", "credit card" and "CC" arriving as three different values. Add the missing option to `enum_options`, or use a `string` field when the set is open.

**A crumpled photo drags every field down.** Extract reads the parse, so a shadowed or creased receipt costs you twice. Capture flat and lit, and prefer PNG over a heavily compressed JPG where you control the capture. For a batch that stays bad, move the Parse node to the [agentic tier](/guides/nodes/parse) (100 credits per page), which is the tier for low-quality inputs.

**One threshold flags the wrong fields.** This receipt returned `total_amount` at 98% and `contains_alcohol` at 92%, and the two do not deserve the same gate. Set the threshold per field: the amount is worth a human look, the flag usually is not.

## Next steps

<CardGroup cols={2}>
  <Card title="Runs and results" icon="list" href="/concepts/runs-and-results">
    The results envelope and the run status model
  </Card>

  <Card title="Errors" icon="triangle-exclamation" href="/api-reference-v3/introduction">
    Rate limits, idempotency and retries
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.