API Reference
POST /match
Determine whether pairs of menu item names refer to the same dish. Uses a two-stage pipeline: fast bi-encoder cosine similarity, then a specialized cross-encoder reranker for high-accuracy match decisions.
Handles misspellings, transliterations, noise, and language differences. "Kadhai Chicken" and "Karahi Chiken" are the same dish. "Butter Chicken" and "Dal Makhani" are not.
Request
| Parameter | Type | Required | Description |
|---|---|---|---|
pairs | object[] | Yes | Array of pairs to compare. 1-100 pairs. Each has text_a and text_b (max 500 chars each). |
cosine_threshold | float | No | Similarity threshold for match decision. Default: 0.85. |
{
"pairs": [
{"text_a": "Kadhai Chicken", "text_b": "Karahi Chiken"},
{"text_a": "Butter Chicken", "text_b": "Dal Makhani"}
],
"cosine_threshold": 0.85
}
Response
| Field | Type | Description |
|---|---|---|
results | object[] | One result per input pair, in submission order |
Each result:
| Field | Type | Description |
|---|---|---|
text_a | string | First item (as submitted) |
text_b | string | Second item (as submitted) |
cosine | float | Cosine similarity between embeddings (0-1) |
reranker_score | float or null | Reranker confidence (0-1), null if pair didn't pass cosine gate |
match | bool | True if the items refer to the same dish |
dietary_conflict | bool | True if one item is veg and the other non-veg |
protein_conflict | bool | True if items have conflicting proteins (e.g. chicken vs paneer) |
{
"results": [
{
"text_a": "Kadhai Chicken",
"text_b": "Karahi Chiken",
"cosine": 0.94,
"reranker_score": 0.97,
"match": true,
"dietary_conflict": false,
"protein_conflict": false
},
{
"text_a": "Butter Chicken",
"text_b": "Dal Makhani",
"cosine": 0.72,
"reranker_score": 0.12,
"match": false,
"dietary_conflict": false,
"protein_conflict": false
}
]
}
Example
import requests
response = requests.post("https://embed.statode.com/match",
headers={"X-API-Key": "YOUR_KEY", "Content-Type": "application/json"},
json={
"pairs": [
{"text_a": "Kadhai Chicken", "text_b": "Karahi Chiken"},
{"text_a": "Butter Chicken", "text_b": "Dal Makhani"},
{"text_a": "Cafe Latte", "text_b": "Caffe Latte (Regular)"}
]
}
)
for result in response.json()["results"]:
status = "MATCH" if result["match"] else "NO MATCH"
print(f"{result['text_a']} vs {result['text_b']}: {status} (cosine={result['cosine']:.2f})")
Cost
1.0 credits per pair.
Notes
- The reranker only fires for pairs that clear the cosine gate. If cosine similarity is very low, the pair is rejected without invoking the reranker, and
reranker_scorewill be null. dietary_conflictcatches cases like "Classic Burger" vs "Veggie Burger" that look similar but shouldn't be merged.protein_conflictcatches cases like "Chicken Momos" vs "Paneer Momos".- For bulk deduplication of an entire menu, use /dedup instead of calling /match for every possible pair.