···11+# Constellation API Reference
22+33+Constellation is an ATProto-wide backlink indexer that tracks links between records. It's part of the [microcosm](https://microcosm.blue/) project.
44+55+## Base URL
66+77+```
88+https://constellation.microcosm.blue
99+```
1010+1111+## Required Headers
1212+1313+```typescript
1414+headers: {
1515+ "Accept": "application/json",
1616+ "User-Agent": "deckbelcher.com by @aviva.gay"
1717+}
1818+```
1919+2020+The `Accept` header is required for JSON responses. The `User-Agent` is a courtesy request from the maintainer.
2121+2222+## Endpoints
2323+2424+### Get Backlinks
2525+2626+Find records that link to a target.
2727+2828+```
2929+GET /xrpc/blue.microcosm.links.getBacklinks
3030+```
3131+3232+**Parameters:**
3333+- `subject` (required): Target URI being linked to (e.g., `scry:uuid`, `at://did/collection/rkey`)
3434+- `source` (required): Collection and path in format `collection:path` (e.g., `com.deckbelcher.collection.list:.items[com.deckbelcher.collection.list#cardItem].ref.scryfallUri`)
3535+- `did` (optional, repeatable): Filter to specific user(s)
3636+- `limit` (optional): Max results, default 16, max 100
3737+3838+**Response:**
3939+```typescript
4040+{
4141+ total: number;
4242+ records: Array<{
4343+ uri: string; // AT URI of linking record
4444+ cid: string; // CID of linking record
4545+ did: string; // DID of record owner
4646+ indexedAt: string;
4747+ }>;
4848+ cursor?: string;
4949+}
5050+```
5151+5252+### Count Links
5353+5454+Get total count of records linking to a target.
5555+5656+```
5757+GET /links/count
5858+```
5959+6060+**Parameters:**
6161+- `target` (required): Target URI (URL-encoded)
6262+- `collection` (required): Collection NSID
6363+- `path` (required): JSON path (URL-encoded)
6464+6565+**Response:**
6666+```typescript
6767+{ total: number }
6868+```
6969+7070+### Count Distinct DIDs
7171+7272+Get count of unique users linking to a target.
7373+7474+```
7575+GET /links/count/distinct-dids
7676+```
7777+7878+Same parameters as `/links/count`.
7979+8080+## Path Syntax
8181+8282+Constellation uses JSONPath-like notation.
8383+8484+**IMPORTANT**: The two endpoints expect different path formats:
8585+- `getBacklinks` source: `collection:path` where path has NO leading dot
8686+- `/links/count` path: path WITH leading dot
8787+8888+Example for the same query:
8989+- getBacklinks: `source=com.deckbelcher.collection.list:items[...].ref.oracleUri`
9090+- count: `path=.items[...].ref.oracleUri`
9191+9292+### Basic Paths
9393+9494+```
9595+.field # Direct field
9696+.nested.field # Nested object
9797+.array[] # Array elements (no $type)
9898+.array[].nested # Nested in array
9999+```
100100+101101+### Union Array Elements ($type)
102102+103103+**IMPORTANT**: When an array element is a union type (has `$type` field), constellation includes the type in the path:
104104+105105+```
106106+.items[com.deckbelcher.collection.list#cardItem].ref.scryfallUri
107107+```
108108+109109+NOT:
110110+```
111111+.items[].ref.scryfallUri # WRONG for union types
112112+```
113113+114114+This is because constellation's link extractor (`links/src/record.rs`) uses the `$type` value when present:
115115+116116+```rust
117117+if let Some(JsonValue::String(t)) = o.get("$type") {
118118+ format!("{path}[{t}]") // Uses $type in path
119119+} else {
120120+ format!("{path}[]") // Plain array notation
121121+}
122122+```
123123+124124+## DeckBelcher-Specific Paths
125125+126126+We use `oracleUri` for card aggregation so counts include all printings of a card.
127127+128128+### Cards in Collection Lists (saves/bookmarks)
129129+130130+```
131131+collection: com.deckbelcher.collection.list
132132+path: .items[com.deckbelcher.collection.list#cardItem].ref.oracleUri
133133+target: oracle:<uuid>
134134+```
135135+136136+### Decks in Collection Lists
137137+138138+```
139139+collection: com.deckbelcher.collection.list
140140+path: .items[com.deckbelcher.collection.list#deckItem].deckUri
141141+target: at://<did>/com.deckbelcher.deck.list/<rkey>
142142+```
143143+144144+### Cards in Deck Lists (future: "decks containing")
145145+146146+```
147147+collection: com.deckbelcher.deck.list
148148+path: .cards[].ref.oracleUri
149149+target: oracle:<uuid>
150150+```
151151+152152+Note: `deck.list` cards don't have `$type`, so use `[]`.
153153+154154+## Example Queries
155155+156156+Check if a user saved a card (by oracle ID):
157157+```bash
158158+curl -H "Accept: application/json" \
159159+ "https://constellation.microcosm.blue/xrpc/blue.microcosm.links.getBacklinks?\
160160+subject=oracle:1a62ba93-153c-4bed-9f6a-ff914df360c1&\
161161+source=com.deckbelcher.collection.list:.items[com.deckbelcher.collection.list%23cardItem].ref.oracleUri&\
162162+did=did:plc:xyz&\
163163+limit=1"
164164+```
165165+166166+Count total saves (by oracle ID):
167167+```bash
168168+curl -H "Accept: application/json" \
169169+ "https://constellation.microcosm.blue/links/count?\
170170+target=oracle:1a62ba93-153c-4bed-9f6a-ff914df360c1&\
171171+collection=com.deckbelcher.collection.list&\
172172+path=.items[com.deckbelcher.collection.list%23cardItem].ref.oracleUri"
173173+```
174174+175175+## Source Code
176176+177177+- Repository: [at-microcosm/microcosm-rs](https://github.com/at-microcosm/microcosm-rs/tree/main/constellation)
178178+- Link extraction logic: `links/src/record.rs`
179179+180180+## Latency Considerations
181181+182182+Constellation indexes records from the ATProto firehose. There may be a delay between when a record is written to a PDS and when constellation has indexed it. For optimistic UI updates, trust the PDS write succeeded rather than immediately re-querying constellation.