Manual · Query
Multi-Agent Join
A join query matches records from two agents on a shared field and returns the intersecting pairs. This is SapixDB's equivalent of a SQL inner join — evaluated across two separate strand agents at query time.
How it works
A join query is issued against any one of the participating agents. SapixDB scans both agents' records, groups them by the value of the on field, and returns only the keys that appear in both agents. The endpoint is the standard query route on either participating agent:
POST /v1/agents/:id/query
The :id segment can be either agent — the result is the same regardless of which side you POST to.
Request shape
{
"type": "join",
"agents": ["users", "orders"],
"on": "user_id"
}| Field | Type | Description |
|---|---|---|
type | "join" | Must be the literal string "join". |
agents | string[] | Exactly two agent IDs. Order does not affect the result. |
on | string | The field name that must match in records from both agents. |
Prerequisite — shared field in both agents
Each agent must contain records that include the join field in their payload. There is no schema enforcement — the field simply needs to exist at query time. Records that lack the field on either side are skipped.
Write a record to each agent before joining:
POST /v1/agents/users/records/json
Authorization: Bearer spx_root_YOUR_ROOT_KEY
Content-Type: application/json
{
"data": {
"user_id": "usr_001",
"name": "Alice",
"plan": "pro"
}
}POST /v1/agents/orders/records/json
Authorization: Bearer spx_root_YOUR_ROOT_KEY
Content-Type: application/json
{
"data": {
"user_id": "usr_001",
"amount": 299.99,
"status": "paid"
}
}Executing the join
POST /v1/agents/users/query
Authorization: Bearer spx_root_YOUR_ROOT_KEY
Content-Type: application/json
{
"type": "join",
"agents": ["users", "orders"],
"on": "user_id"
}Response format
The response contains a join_results array. Each element represents one matched key value and carries the full payload from both agents under their respective agent-ID keys.
{
"join_results": [
{
"key": "usr_001",
"users": {
"user_id": "usr_001",
"name": "Alice",
"plan": "pro"
},
"orders": {
"user_id": "usr_001",
"amount": 299.99,
"status": "paid"
}
}
]
}| Field | Description |
|---|---|
key | The shared field value that matched — i.e. the value of on that appears in both agents. |
<agent_id> | One key per participating agent, each containing that agent's matched record payload. |
Inner-join semantics
The join is strictly an inner join. A key must be present in both agents for a result row to be emitted. Unmatched records are silently excluded:
| Situation | Result |
|---|---|
user_id exists in both agents | Included in join_results |
| User record with no matching order | Excluded — no left-join or outer-join |
| Order record with no matching user | Excluded |
Record missing the on field entirely | Skipped and never matched |
Multiple key values
A single join query handles any number of distinct key values in one pass. If ten users and their orders all share different user_id values, all ten matched pairs are returned in a single join_results array.
{
"join_results": [
{ "key": "usr_001", "users": { ... }, "orders": { ... } },
{ "key": "usr_002", "users": { ... }, "orders": { ... } },
{ "key": "usr_003", "users": { ... }, "orders": { ... } }
]
}Joining more than two agents
agents array accepts exactly two entries. Passing three or more agents returns a validation error.To correlate data across three or more agents, use one of these patterns:
Option 1 — chained joins in application code
Run a first join (e.g. users + orders), extract the keys from the result, then run a second join (e.g. orders + shipments) and merge the two result sets in your application.
Option 2 — graph traversal
If you have defined graph edges between agents, use GET /v1/graph/traverse?from=users&depth=2 to walk the relationship graph and discover connected agents before fetching their records. This is more expressive for deep hierarchies. See the Graph Index page.
Error conditions
| Error | Cause |
|---|---|
invalid_query_type | type is not "join". |
agent_not_found | One of the agent IDs in agents does not exist. |
too_many_agents | agents contains more than two entries. |
missing_on_field | on is absent or empty. |