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

# Real-time merchant matching guide

> Merchant matching is not enabled by default. To request access, please contact us at .

***

## Overview

Real time merchant matching allows you to effectively match a small volume of merchants to locations and counterparties in Spade's database. In this guide, we'll use the `/merchants/ match` `POST` endpoint to submit a real-time merchant match.

## Request Schema

<CodeGroup>
  ```bash bash theme={null}
  {
    // REQUIRED
    "merchantName": "SHELL",
    "address": "11458 S Cicero Ave",
    "city": "Alsip",
    "region": "IL",
    "postalCode": "60803",
    "country": "USA",
    "requestId": "your‑internal‑id‑123",

    // OPTIONAL – improves accuracy
    "latitude": 41.6839,
    "longitude": -87.7398,
    "website": "shell.com",

    // OPTIONAL – controls corporation vs. location matching (defaults to "location")
    "level": "location",

    // OPTIONAL – echoed back in the response
    "customAttributes": {
      "importBatch": "oct‑15‑2025",
      "source": "legacy_sql_dump"
    }
  }
  ```
</CodeGroup>

> **Tip:** Latitude & longitude are the strongest disambiguators after name + address. Use them when you have them.

> **`level` field:** Use `"corporation"` when you want brand-level information (e.g. Costco in general) or `"location"` when you want information about a specific physical location (e.g. one specific Costco location). Defaults to `"location"` if not specified.

***

## Performing Your First Match

### 1. Prepare the payload

Pick a merchant from your database -- ideally one with a full postal address.

### 2. Send the request

<CodeGroup>
  ```bash bash theme={null}
  import requests, json, pprint

  payload = {
    "merchantName": "SHELL",
    "address": "11458 S Cicero Ave",
    "city": "Alsip",
    "region": "IL",
    "postalCode": "60803",
    "country": "USA",
    "latitude": 41.6839,
    "longitude": -87.7398,
    "requestId": "your‑internal‑id‑123",
    "level": "location"
  }

  resp = requests.post(
      "https://east.sandbox.spade.com/merchants/match",
      headers={"X-Api-Key": "<YOUR_SANDBOX_API_KEY>"},
      json=payload,
      timeout=2,
  )
  pprint.pp(resp.json())
  ```
</CodeGroup>

A minimal cURL equivalent:

<CodeGroup>
  ```bash bash theme={null}
  curl https://east.sandbox.spade.com/merchants/match \
    -H "Content-Type: application/json" \
    -H "X-Api-Key: <YOUR_SANDBOX_API_KEY>" \
    -d @payload.json
  ```
</CodeGroup>

### 3. Inspect the response

<CodeGroup>
  ```bash bash theme={null}
  {
    "requestId": "your‑internal‑id‑123",
    "counterparty": {
      "id": "d90d6e09-1be3-4042-8283-7e2a7544b65d",
      "name": "Shell",
      "similarity": 100
    },
    "location": {
      "id": "e1f396bc-a0a8-4615-b317-066164e98677",
      "name": "Shell",
      "address": "11458 S Cicero Ave",
      "city": "Alsip",
      "similarity": 100
    },
    "customAttributes": {
      "importBatch": "oct‑15‑2025",
      "source": "legacy_sql_dump"
    }
  }
  ```
</CodeGroup>

***

## Response Breakdown

### counterparty

| Field        | Description              |
| ------------ | ------------------------ |
| `id`         | *Spade Counterparty ID*  |
| `name`       | Canonical business name. |
| `similarity` | 0–100 match confidence.  |

### location

| Field        | Description                                                     |
| ------------ | --------------------------------------------------------------- |
| `id`         | *Spade Location ID*                                             |
| `name`       | Location‑level business name (if distinct from brand).          |
| `address`    | Cleansed, correctly cased postal address.                       |
| `city`       | Cleaned city corresponding to the Location                      |
| `similarity` | Confidence that this physical location is the one you provided. |

> **Similarity vs. Match Score?** For merchant matching we use *similarity* (string & geo distance based). Card enrichment uses *matchScore* (ML model across many signals). Treat them the same way: higher = better.

***

## Handling Non‑Matches

A *null* `counterparty` or `location` means we couldn’t find an acceptable match. Typical reasons:

* Typos or missing street numbers
* Recently opened stores not yet in our DB
* PO boxes or corporate HQ addresses

**What to do**

1. **Retry with more info** – add latitude/longitude if you have it.
2. **Store as unknown** – save the original name; you can re‑run matching later.

***

## Batch Matching (Optional)

If you have > 1000 merchants, use **`POST /batches/merchants/match`**. Learn more in our [batch merchant matching guide](/reference/batch-merchant-matching-guide).

## Implementation Notes

* **Content‑Type** must be `application/json`. Some HTTP tools fallback to `multipart/form-data`; override it explicitly.
* **400 errors** → invalid or missing required fields (address, city, region, postalCode, country, merchantName). Parse the response JSON for details.
* **403 errors** → invalid or missing API key.
* **500 errors** → Spade’s infrastructure. These are rare; exponential back‑off is recommended.

***

<Info />

If your request **includes** a suite, apartment, or unit designator (e.g., “123 Main St **Ste 204**”) and you *don’t* get a satisfactory match, resend the request **without** the suite information. Likewise, if your original request *omits* the suite but still fails to match, try **adding** the suite/apt/unit string. Suite tags are recorded inconsistently across data providers, so toggling them on or off often nudges a borderline similarity score over the threshold.

***

## Best Practices Checklist ✅

| Done? | Recommendation                                                                    |
| ----- | --------------------------------------------------------------------------------- |
|       | Send *full* street address **and** city/region/postalCode.                        |
|       | Provide latitude/longitude when available (mobile checkouts, GPS capture).        |
|       | Store `counterparty.id` and `location.id` **once** → attach to every transaction. |
|       | Decide on a similarity threshold (e.g., drop matches `<70`).                      |
|       | Use batch matching for historical backfills and weekly sync jobs.                 |
