> ## 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

**Nodes used:** [Parse](/guides/nodes/parse), [Extract](/guides/nodes/extract)

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.

## 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 theme={null}
{
  "status": "processed",
  "results": {
    "parse": { "markdown": "...", "parse_confidence": 96.0, "blocks": [] },
    "extractions": [
      {
        "split_name": null,
        "partition": null,
        "fields": {
          "store_name": {
            "value": "Corner Grocery",
            "confidence": 97.0,
            "evidence": [{ "text": "CORNER GROCERY", "page_number": 1 }],
            "verification_status": "not_verified",
            "value_override": null
          },
          "total_amount": {
            "value": "23.45",
            "confidence": 98.0,
            "evidence": [{ "text": "TOTAL 23.45", "page_number": 1 }],
            "verification_status": "not_verified",
            "value_override": null
          },
          "tax_amount": {
            "value": null,
            "confidence": null,
            "evidence": [],
            "verification_status": "not_verified",
            "value_override": null
          },
          "payment_method": {
            "value": "credit_card",
            "confidence": 95.0,
            "evidence": [{ "text": "VISA ****1234", "page_number": 1 }],
            "verification_status": "not_verified",
            "value_override": null
          },
          "contains_alcohol": {
            "value": "False",
            "confidence": 92.0,
            "evidence": [],
            "verification_status": "not_verified",
            "value_override": null
          }
        }
      }
    ]
  }
}
```

## Tips

* Good lighting and a flat surface make a large difference to a receipt photo. A crumpled or shadowed receipt lowers `parse_confidence`.
* Prefer PNG over a heavily compressed JPG when you control the capture.
* An `enum` with explicit options stops free-text variations such as "Visa", "credit card" and "CC". The value is always one of your option names.
* A `boolean` arrives as the string `"True"` or `"False"`. Compare against the string, or cast it, before you branch on it.
* Treat `value: null` as "not on the receipt", not as zero. Faded thermal paper often loses the tax line first.
* Set a lower confidence threshold on `contains_alcohol` than on `total_amount`. The flag matters less than the amount.

## 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>
