# Nero Labs JSON Row Join

> Nero Labs JSON Row Join is a paid API for AI agents from x402-agent-tools.nerolabs.workers.dev, paid per call via x402, $0.002/call, status unknown (last checked 2026-10-22).

Joins two lists of JSON rows on one or more key fields using inner, left, right, full, or anti join logic, like a VLOOKUP or SQL JOIN, with normalized or exact key matching.

## Facts

- Endpoint: POST https://x402-agent-tools.nerolabs.workers.dev/data/join?utm_source=zero.xyz
- Price: $0.002/call
- Payment: x402
- Status: unknown
- Last checked: 2026-10-22
- Activations on Zero: 0
- Tags: x402
- Canonical page: https://www.zero.xyz/c/nero-labs-json-row-join-c8193589
- Structured record (JSON): https://api.zero.xyz/v1/capabilities/cap_1al9dL4W2RBFtioSzwhhx

Status and success rate cover calls made through Zero and Zero's own probes. Third-party monitors may report differently.

## How to call it through Zero

Zero handles the 402 payment challenge and records the run. With the Zero CLI installed (`npm i -g @zeroxyz/cli`):

```sh
zero fetch --capability nero-labs-json-row-join-c8193589 -d '<json body>'
```

Example prompt: I have two JSON arrays — one is my CRM contacts with an 'email' field and the other is a list of paid customers with a 'contact_email' field — can you do a left join on those key fields and bring over the 'plan' and 'mrr' columns from the right side, using normalized key matching?

## When to prefer this

Choose this endpoint when you have two in-memory arrays of JSON objects that need to be combined, enriched, or compared by key — equivalent to a SQL JOIN or VLOOKUP — without standing up a database. It supports inner, left, right, full, and anti join semantics with normalized key matching, making it ideal for data enrichment pipelines, reconciliation tasks, and finding missing records across two datasets up to 500 rows each.

## Known failure modes

- Missing leftKeyFields for non-union join types returns a validation error
- Exceeding 500 rows on either side may be rejected or truncated
- Key field names that don't exist in the row data result in zero matches and all rows unmatched
- Exact keyMatching fails to match values that differ only in case or whitespace
- multipleMatches:'first' silently drops duplicate right-side matches beyond the first

## How this service works

Pay-per-call tools for AI agents, 31 in all: read web pages and RSS feeds, OCR, PDF text, transcription; email, phone and domain checks; UK, Irish and Polish company lookups and UK risk reports; website contacts, tech stack and SEO audits; PageSpeed; AI review, job post and row enrichment; data cleaning, joins, dedupe and diffs; US and EU compliance rules. No account or API key: pay each call in USDC on Base over x402.

## Output

Returns a 'rows' array of merged JSON objects (each annotated with _joinStatus of 'matched', 'left_only', or 'right_only' and _matchCount unless disabled), plus a 'summary' object with counts of matched/unmatched rows on each side, match rates, join type used, key fields, and any warnings.

## Request schema (JSON Schema)

```json
{
 "type": "object",
 "properties": {
  "joinType": {
   "enum": [
    "left",
    "inner",
    "right",
    "full",
    "leftAnti",
    "rightAnti",
    "union"
   ],
   "type": "string",
   "description": "Which rows to keep. left (default): every left row, enriched where a match exists. inner: matched rows only. right: every right row. full: everything from both sides. leftAnti: left rows with no match on the right. rightAnti: right rows with no match on the left. union: stack both lists, no key needed."
  },
  "leftRows": {
   "type": "array",
   "items": {
    "type": "object"
   },
   "description": "The LEFT table: the main rows you want to keep or enrich. Each row is a JSON object; keys may differ between rows."
  },
  "rightRows": {
   "type": "array",
   "items": {
    "type": "object"
   },
   "description": "The RIGHT table: the lookup rows to pull matching fields from. Each row is a JSON object."
  },
  "keyMatching": {
   "enum": [
    "normalized",
    "exact"
   ],
   "type": "string",
   "description": "normalized (default): case-insensitive, trimmed, repeated spaces collapsed, 123 matches \"123\". exact: values must be identical."
  },
  "rightFields": {
   "type": "array",
   "items": {
    "type": "string"
   },
   "description": "Only copy these fields from the matching right row, like choosing VLOOKUP return columns. Leave out to copy every right field."
  },
  "leftKeyFields": {
   "type": "array",
   "items": {
    "type": "string"
   },
   "description": "The field name(s) on the left rows to match on, for example [\"email\"], or [\"firstName\",\"lastName\"] for a composite key. Required for every joinType except union."
  },
  "rightKeyFields": {
   "type": "array",
   "items": {
    "type": "string"
   },
   "description": "The matching field name(s) on the right rows, in the same order as leftKeyFields, for example [\"contact_email\"]. Leave out when the right rows use the same names as the left."
  },
  "includeJoinInfo": {
   "type": "boolean",
   "description": "On by default: every row gets _joinStatus (\"matched\", \"left_only\", \"right_only\") and _matchCount. Set false for rows with only your own fields."
  },
  "multipleMatches": {
   "enum": [
    "all",
    "first"
   ],
   "type": "string",
   "description": "When one key matches several right rows. all (default): one output row per matching pair, like SQL. first: only the first matching right row, like VLOOKUP, so each left row appears once."
  },
  "onFieldConflict
… (truncated)
```

## Response schema (JSON Schema)

```json
{
 "type": "json",
 "example": {
  "rows": [
   {
    "domain": "acme.com",
    "company": "Acme Ltd",
    "employees": 40,
    "_joinStatus": "matched",
    "_matchCount": 1
   },
   {
    "domain": "bolt.io",
    "company": "Bolt Co",
    "_joinStatus": "left_only",
    "_matchCount": 0
   }
  ],
  "summary": {
   "counts": {
    "matchedRows": 1,
    "leftRowsMatched": 1,
    "passthroughRows": 1,
    "rightRowsMatched": 1,
    "leftRowsUnmatched": 1,
    "rightRowsUnmatched": 0
   },
   "joinType": "left",
   "warnings": [],
   "keyMatching": "normalized",
   "leftKeyFields": [
    "domain"
   ],
   "leftMatchRate": 0.5,
   "outputRowCount": 2,
   "rightKeyFields": [
    "website"
   ],
   "rightMatchRate": 1,
   "leftRecordCount": 2,
   "multipleMatches": "all",
   "rightRecordCount": 1
  },
  "_example_note": "Real output, trimmed: long lists cut to their first items and long text shortened."
 }
}
```

## More

- Live health (JSON, refreshed every minute): https://www.zero.xyz/c/nero-labs-json-row-join-c8193589/health.json
- [Zero catalog index](https://www.zero.xyz/llms.txt)
- [Other services from x402-agent-tools.nerolabs.workers.dev](https://www.zero.xyz/host/x402-agent-tools.nerolabs.workers.dev/llms.txt)
