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

# Everyone spells your supplier differently

> Read the supplier name off the invoice, then resolve it to the code your ERP actually uses, with a reference CSV you upload once

The invoice says "Wayne Enterprises". Your supplier master says "Wayne Enterprises, Inc." and your ERP only speaks `SUP-1042`. Next month the same supplier writes "WAYNE ENTERPRISES SA" and the whole thing starts again. [Smart lookup](/guides/nodes/smart-lookup) resolves the name on the page against a CSV you upload once, and returns the row your systems need.

<div className="af-payoff">
  <div className="af-payoff-pane">
    <div className="af-payoff-cap">On the invoice</div>
    <div className="af-payoff-line"><b>INVOICE</b></div>

    <div className="af-payoff-line">
      <span className="af-mark">
        {'From: Wayne Enterprises'}
      </span>
    </div>

    <div className="af-payoff-line">
      {'148 Eric Track, New Stephanie, NC'}
    </div>

    <div className="af-payoff-cap" style={{ marginTop: '12px' }}>In suppliers.csv</div>

    <div className="af-payoff-line">
      {'SUP-1042  Wayne Enterprises, Inc.'}
    </div>

    <div className="af-payoff-line">
      {'SUP-2013  Wayne Medical Supplies LLC'}
    </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">vendor\_name</span><b>{'Wayne Enterprises'}</b>{'  '}<span className="af-cite">97%</span></div>
    <div className="af-payoff-line"><span className="af-payoff-key">invoice\_number</span><b>{'INV-2026-9001'}</b>{'  '}<span className="af-cite">96%</span></div>
    <div className="af-payoff-line"><span className="af-payoff-key">supplier\_id</span><b>{'SUP-1042'}</b></div>
    <div className="af-payoff-line"><span className="af-payoff-key">payment\_terms</span><b>NET30</b></div>

    <div className="af-payoff-line">
      <span className="af-cite">
        {'↳ the read fields cite the page'}
      </span>
    </div>

    <div className="af-payoff-line">
      <span className="af-cite">
        {'↳ the looked-up fields cite the CSV'}
      </span>
    </div>
  </div>
</div>

<div className="af-cost">
  <span><b>Nodes</b><strong>{'Parse → Extract'}</strong></span>
  <span><b>Credits</b><strong>135 per page</strong>{' (Parse 25 + Extract 35 + lookup 75)'}</span>
  <span><b>You get</b>{' the name as printed and the code you file it under'}</span>
</div>

## The workflow

Smart lookup is not a node of its own. It is a `source` on a field of the [Extract](/guides/nodes/extract) node, plus the reference CSV attached to that node. Here `vendor_name` is read off the page; `supplier_id` and `payment_terms` are resolved from the file.

<CodeGroup>
  ```json API theme={null}
  {
    "name": "Invoices with supplier codes",
    "description": "Read the supplier name off the invoice, then resolve it to the code your ERP uses",
    "nodes": [
      { "id": "parse_1", "type": "parse" },
      {
        "id": "extract_1",
        "type": "extract",
        "extraction_schema": {
          "fields": [
            { "name": "vendor_name",    "description": "Supplier name exactly as printed on the invoice", "data_type": "string" },
            { "name": "invoice_number", "description": "The unique invoice identifier", "data_type": "string" },
            {
              "name": "supplier_id",
              "description": "Canonical supplier code from the supplier master, joined on the supplier name",
              "data_type": "string",
              "source": "smart_lookup"
            },
            {
              "name": "payment_terms",
              "description": "Agreed payment terms for this supplier, from the supplier master",
              "data_type": "string",
              "source": "smart_lookup"
            }
          ]
        },
        "lookup_file_uploads": [
          { "filename": "suppliers.csv", "content": "<base64 of the CSV bytes>" }
        ],
        "lookup_suggestion": "Match the supplier name against the supplier_name column, ignoring legal suffixes such as Inc., Ltd, LLC and S.A. Return the row's supplier_id and payment_terms."
      }
    ],
    "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("Invoices with supplier codes", "Resolve the supplier to the code your ERP uses")
      .parse()
      .extract(
          [
              Schema.string("vendor_name", "Supplier name exactly as printed on the invoice"),
              Schema.string("invoice_number", "The unique invoice identifier"),
              Schema.string(
                  "supplier_id",
                  "Canonical supplier code from the supplier master, joined on the supplier name",
                  source="smart_lookup",
              ),
              Schema.string(
                  "payment_terms",
                  "Agreed payment terms for this supplier, from the supplier master",
                  source="smart_lookup",
              ),
          ],
          lookup_files=["suppliers.csv"],
          lookup_suggestion=(
              "Match the supplier name against the supplier_name column, ignoring legal suffixes "
              "such as Inc., Ltd, LLC and S.A. Return the row's supplier_id and payment_terms."
          ),
      )
      .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("Invoices with supplier codes", "Resolve the supplier to the code your ERP uses")
    .parse()
    .extract(
      [
        Schema.string("vendor_name", "Supplier name exactly as printed on the invoice"),
        Schema.string("invoice_number", "The unique invoice identifier"),
        Schema.string("supplier_id", "Canonical supplier code from the supplier master, joined on the supplier name", {
          source: "smart_lookup",
        }),
        Schema.string("payment_terms", "Agreed payment terms for this supplier, from the supplier master", {
          source: "smart_lookup",
        }),
      ],
      {
        lookupFiles: ["suppliers.csv"],
        lookupSuggestion:
          "Match the supplier name against the supplier_name column, ignoring legal suffixes such as Inc., Ltd, LLC and S.A. Return the row's supplier_id and payment_terms.",
      },
    )
    .create();
  ```
</CodeGroup>

The SDKs read each path in `lookup_files` from disk and send it as `lookup_file_uploads`. Over the API you send the bytes inline, base64-encoded.

## The reference file

Any CSV with a column to match on and the columns you want back. This one carries a near-miss on purpose: two suppliers whose names both start with "Wayne".

```csv suppliers.csv theme={null}
supplier_id,supplier_name,city,payment_terms
SUP-1042,"Wayne Enterprises, Inc.",Gotham,NET30
SUP-2013,"Wayne Medical Supplies LLC",Gotham,NET45
SUP-3390,"Acme Industries S.A.",Phoenix,NET15
SUP-4471,"Globex Corporation Ltd",Springfield,NET30
SUP-5528,"Initech LLC",Austin,NET60
```

## Response

`vendor_name` and `invoice_number` were read off the page, so they carry a confidence and the phrase they came from. `supplier_id` and `payment_terms` came out of the CSV, so their `confidence` is `null` and their `evidence` is empty: there is no page they were read from.

```json theme={null}
{
  "status": "processed",
  "results": {
    "extractions": [
      {
        "split_name": null,
        "partition": null,
        "fields": {
          "vendor_name": {
            "value": "Wayne Enterprises",
            "confidence": 97.0,
            "evidence": [{ "text": "From: Wayne Enterprises\n148 Eric Track, New Stephanie, NC 00575", "page_number": 1 }],
            "verification_status": "not_verified",
            "value_override": null
          },
          "invoice_number": {
            "value": "INV-2026-9001",
            "confidence": 96.0,
            "evidence": [{ "text": "Invoice #: INV-2026-9001\nIssue date: 2026-02-20", "page_number": 1 }],
            "verification_status": "not_verified",
            "value_override": null
          },
          "supplier_id": {
            "value": "SUP-1042",
            "confidence": null,
            "evidence": [],
            "verification_status": "not_verified",
            "value_override": null
          },
          "payment_terms": {
            "value": "NET30",
            "confidence": null,
            "evidence": [],
            "verification_status": "not_verified",
            "value_override": null
          }
        }
      }
    ]
  }
}
```

## When it goes wrong

**The looked-up field has no confidence.** That is correct, not a bug. A looked-up value did not come off the page, so there is nothing to be confident about and nothing to cite. Judge the match by the extracted field beside it: if `vendor_name` is right, the join had the right input.

**It matched the wrong row.** Two suppliers here start with "Wayne". The matcher works from the field name, the field description and `lookup_suggestion`, so add the signal that separates them: "match on supplier name **and** city". A description that names the column beats a clever hint.

**Nothing comes back.** The lookup returns empty when no row is a defensible match, which is the honest answer for a supplier that is not in your file yet. Use `"source": "lookup_if_missing"` when you would rather keep whatever was printed on the page than get nothing.

**You wanted to check a value against a fixed list.** Then you want an [enum field](/concepts/field-types), not a lookup. Smart lookup is for a list that lives in a file and returns a *different* value than the one it matched.

**The workflow is rejected when you save it.** An Extract node with a lookup field and no reference file is refused at save time. Send `lookup_file_uploads` on create, or add the file to the node in Studio.

## Next steps

<CardGroup cols={2}>
  <Card title="Smart lookup" icon="magnifying-glass" href="/guides/nodes/smart-lookup">
    Every option, including the matching effort
  </Card>

  <Card title="Field types" icon="diagram-project" href="/concepts/field-types">
    When to use an enum instead
  </Card>
</CardGroup>
