Recipe catalog / entity-match
Match records to one entity
Do firstRecord and secondRecord describe the same real-world entity despite formatting, abbreviation, or partial fields?
You need to decide whether two customer, vendor, product, or place records should be merged or linked.
Explore this recipe interactively ยท Source and implementation guide
Use entity-match in TypeScript
Install with npm install jev-recipes. Requires Node.js 22.9 or newer and ES modules. Set TYPESAFE_API_KEY in your server environment for live calls, which send input to TypeSafe and use API quota. See the installation guide.
import { entityMatch } from 'jev-recipes/entity-match';
const result = await entityMatch({
"firstRecord": "{\"name\":\"Acme Corp.\",\"city\":\"Portland, OR\",\"phone\":\"(503) 555-0147\",\"website\":\"acme.example\"}",
"secondRecord": "ACME Corporation, 1200 SW Main St, Portland Oregon 97204. Tel 503-555-0147.",
"context": "Both records come from vendor onboarding forms filled in by hand.",
"minConfidence": 0.8
});
console.log(result);
Input contract
| Field | Type | Needed |
|---|---|---|
| firstRecord | string | Required |
| secondRecord | string | Required |
| context | string | Optional |
| minConfidence | number | Optional |
Full input and result schemas
{
"input": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"firstRecord": {
"type": "string"
},
"secondRecord": {
"type": "string"
},
"context": {
"type": "string"
},
"minConfidence": {
"type": "number",
"minimum": 0,
"maximum": 1
}
},
"required": [
"firstRecord",
"secondRecord"
]
},
"result": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"model": {
"type": "string"
},
"usage": {
"type": "object",
"properties": {
"input_tokens": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"output_tokens": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
}
},
"required": [
"input_tokens",
"output_tokens"
],
"additionalProperties": false
},
"status": {
"type": "string",
"enum": [
"ready",
"review"
]
},
"probability": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"confidence": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"verdict": {
"type": "string",
"enum": [
"same",
"different"
]
}
},
"required": [
"model",
"usage",
"status",
"probability",
"confidence",
"verdict"
],
"additionalProperties": false
}
}Saved example result
This hand-authored response demonstrates the contract. It is not a model accuracy measurement. Run it without an API key: npx jev-recipes demo entity-match.
{
"model": "demo-fixture",
"usage": {
"input_tokens": 0,
"output_tokens": 0
},
"status": "ready",
"probability": 0.94,
"confidence": 0.94,
"verdict": "same"
}
Evaluation evidence
jev-1.13.0 / 2026-09-27 / 40 held-out cases
Scoring revision 1.
30 ready decisions, with 100% accuracy among those decisions.
95% case-level interval: 74% to 95%. Related synthetic cases are correlated.
Measured on these synthetic cases
This measurement uses an earlier or unverified recipe or evaluator version. Rerun with the current recipe and evaluator before treating these numbers as current.
Use the evaluation guide to measure this decision on your own labeled cases.
Limitations
- Judges identity from the supplied fields only. It does not look records up or verify that either one is accurate.
- Merge, survivorship, and which fields win remain application rules.
Related recipes
- ticket-match: Use ticket-match to decide whether two support tickets report the same issue.
- task-duplicate: Use task-duplicate to catch a task that repeats one already on the list.