Highly ambitious ATProtocol AppView service and sdks
138
fork

Configure Feed

Select the types of activity you want to include in your feed.

API Reference#

Complete reference for Slices API endpoints.

Base URL#

https://api.slices.network/xrpc/

Authentication#

Most write operations require OAuth 2.0 authentication. Include the access token in the Authorization header:

Authorization: Bearer YOUR_ACCESS_TOKEN

Read operations typically work without authentication.

Dynamic Collection Endpoints#

For each collection in your slice, the following endpoints are automatically generated:

[collection].getRecords#

Get records in a collection.

Method: GET

Parameters:

  • slice (string, required): Slice URI
  • limit (number, optional): Maximum records (default: 50)
  • cursor (string, optional): Pagination cursor
  • where (object, optional): Filter conditions using field-specific queries
  • sortBy (array, optional): Sort specification with field and direction objects

[collection].getRecord#

Get a single record.

Method: GET

Parameters:

  • slice (string, required): Slice URI
  • uri (string, required): Record URI

[collection].countRecords#

Count records in a collection.

Method: GET

Parameters:

  • slice (string, required): Slice URI
  • where (object, optional): Filter conditions using field-specific queries
  • Other filter parameters (no limit/cursor)

Response:

{
  "count": 150
}

[collection].createRecord#

Create a new record.

Method: POST

Authentication: Required

Body:

{
  "slice": "at://your-slice-uri",
  "record": {
    "$type": "com.recordcollector.album",
    "title": "Superunknown",
    "artist": "Soundgarden",
    "releaseDate": "1994-03-08",
    "condition": "Near Mint",
    "genre": ["grunge", "alternative metal"]
  },
  "rkey": "3jklmno456"
}

[collection].updateRecord#

Update an existing record.

Method: POST

Authentication: Required

Body:

{
  "slice": "at://your-slice-uri",
  "rkey": "3xyz789abc",
  "record": {
    "$type": "com.recordcollector.album",
    "title": "Dirt",
    "artist": "Alice in Chains",
    "releaseDate": "1992-09-29",
    "condition": "Very Good Plus",
    "notes": "Minor sleeve wear, vinyl plays perfectly"
  }
}

[collection].deleteRecord#

Delete a record.

Method: POST

Authentication: Required

Body:

{
  "rkey": "3abc123xyz"
}

Core Endpoints#

Slice Management#

network.slices.slice.getRecords#

Get all slices.

Method: GET

Parameters:

  • limit (number, optional): Maximum records to return (default: 50)
  • cursor (string, optional): Pagination cursor
  • where (object, optional): Filter conditions using field-specific queries
  • sortBy (array, optional): Sort specification with field and direction objects

Response:

{
  "records": [
    {
      "uri": "at://did:plc:abc/network.slices.slice/xyz",
      "cid": "bafyrei...",
      "did": "did:plc:abc",
      "collection": "network.slices.slice",
      "value": {
        "name": "My Slice",
        "domain": "com.example",
        "createdAt": "2024-01-01T00:00:00Z"
      },
      "indexedAt": "2024-01-01T00:00:00Z"
    }
  ],
  "cursor": "next-page-cursor"
}

network.slices.slice.getRecord#

Get a specific slice by URI.

Method: GET

Parameters:

  • uri (string, required): AT Protocol URI of the slice

Response: Single record object (same structure as getRecords item)

network.slices.slice.createRecord#

Create a new slice.

Method: POST

Authentication: Required

Body:

{
  "slice": "at://your-slice-uri",
  "record": {
    "$type": "network.slices.slice",
    "name": "My New Slice",
    "domain": "com.example",
    "createdAt": "2024-01-01T00:00:00Z"
  },
  "rkey": "optional-record-key"
}

Response:

{
  "uri": "at://did:plc:abc/network.slices.slice/xyz",
  "cid": "bafyrei..."
}

Slice Operations#

network.slices.slice.stats#

Get statistics for a slice.

Method: POST

Body:

{
  "slice": "at://your-slice-uri"
}

Response:

{
  "success": true,
  "collections": ["com.recordcollector.album", "com.recordcollector.review"],
  "collectionStats": [
    {
      "collection": "com.recordcollector.album",
      "recordCount": 427,
      "uniqueActors": 23
    }
  ],
  "totalLexicons": 5,
  "totalRecords": 500,
  "totalActors": 25,
  "message": "Statistics retrieved successfully"
}

network.slices.slice.listSliceRecords#

List records across multiple collections in a slice.

Method: POST

Body:

{
  "slice": "at://your-slice-uri",
  "collections": ["com.recordcollector.album", "com.recordcollector.review"],
  "authors": ["did:plc:optional-filter"],
  "limit": 20,
  "cursor": "pagination-cursor"
}

Response:

{
  "success": true,
  "records": [
    {
      "uri": "at://did:plc:abc/com.recordcollector.album/xyz",
      "cid": "bafyrei...",
      "did": "did:plc:abc",
      "collection": "com.recordcollector.album",
      "value": {/* record data */},
      "indexedAt": "2024-01-01T00:00:00Z"
    }
  ],
  "cursor": "next-page-cursor"
}

network.slices.slice.searchSliceRecords#

Search records across multiple collections in a slice by content.

Method: POST

Body:

{
  "slice": "at://your-slice-uri",
  "collections": ["com.recordcollector.album", "com.recordcollector.review"],
  "search": "search term",
  "authors": ["did:plc:optional-filter"],
  "limit": 20,
  "cursor": "pagination-cursor"
}

Response:

{
  "success": true,
  "records": [
    {
      "uri": "at://did:plc:abc/com.recordcollector.album/xyz",
      "cid": "bafyrei...",
      "did": "did:plc:abc",
      "collection": "com.recordcollector.album",
      "value": {/* record data */},
      "indexedAt": "2024-01-01T00:00:00Z"
    }
  ],
  "cursor": "next-page-cursor"
}

network.slices.slice.syncUserCollections#

Synchronously sync collections for the authenticated user.

Method: POST

Authentication: Required

Body:

{
  "slice": "at://your-slice-uri",
  "timeoutSeconds": 30
}

Response:

{
  "success": true,
  "reposProcessed": 1,
  "recordsSynced": 45,
  "timedOut": false,
  "message": "Sync completed successfully"
}

network.slices.slice.startSync#

Start an asynchronous bulk sync job.

Method: POST

Authentication: Required

Body:

{
  "slice": "at://your-slice-uri",
  "collections": ["com.recordcollector.album"],
  "externalCollections": ["app.bsky.actor.profile"],
  "repos": ["did:plc:abc", "did:plc:xyz"],
  "limitPerRepo": 100
}

Response:

{
  "success": true,
  "jobId": "job-uuid",
  "message": "Sync job started"
}

network.slices.slice.codegen#

Generate TypeScript client code.

Method: POST

Body:

{
  "target": "typescript",
  "slice": "at://your-slice-uri"
}

Response:

{
  "success": true,
  "generatedCode": "// Generated TypeScript client code..."
}

Lexicon Management#

network.slices.lexicon.getRecords#

Get lexicons in a slice.

Method: GET

Parameters: Same as collection.getRecords

network.slices.lexicon.countRecords#

Count lexicons in a slice.

Method: GET

Parameters: Same as collection.getRecords (except limit and cursor)

Response:

{
  "count": 10
}

network.slices.lexicon.createRecord#

Add a lexicon to a slice.

Method: POST

Authentication: Required

Body:

{
  "slice": "at://your-slice-uri",
  "record": {
    "$type": "network.slices.lexicon",
    "nsid": "com.recordcollector.album",
    "definitions": "{\"lexicon\": 1, ...}",
    "createdAt": "2024-01-01T00:00:00Z",
    "slice": "at://your-slice-uri"
  }
}

Actor Management#

network.slices.slice.getActors#

Get actors (users) in a slice.

Method: GET

Parameters:

  • slice (string, required): Slice URI
  • search (string, optional): Search query
  • dids (string[], optional): Filter by DIDs
  • limit (number, optional): Maximum results
  • cursor (string, optional): Pagination cursor

Response:

{
  "actors": [
    {
      "did": "did:plc:abc",
      "handle": "user.bsky.social",
      "sliceUri": "at://slice-uri",
      "indexedAt": "2024-01-01T00:00:00Z"
    }
  ],
  "cursor": "next-page"
}

Blob Upload#

com.atproto.repo.uploadBlob#

Upload a blob (image, file).

Method: POST

Authentication: Required

Headers:

  • Content-Type: MIME type of the blob

Body: Raw binary data

Response:

{
  "blob": {
    "$type": "blob",
    "ref": { "$link": "bafkrei..." },
    "mimeType": "image/jpeg",
    "size": 127198
  }
}

Error Responses#

All endpoints may return error responses:

{
  "error": "InvalidRequest",
  "message": "Detailed error message"
}

Common HTTP status codes:

  • 200: Success
  • 400: Bad request
  • 401: Authentication required
  • 403: Forbidden
  • 404: Not found
  • 500: Internal server error

Pagination#

List endpoints support cursor-based pagination:

  1. Make initial request without cursor
  2. Use returned cursor for next page
  3. Continue until no cursor returned

Example:

let cursor = undefined;
do {
  const response = await fetch(`/xrpc/collection.getRecords?cursor=${cursor}`);
  const data = await response.json();
  // Process records
  cursor = data.cursor;
} while (cursor);

Filtering#

List endpoints support filtering using the where parameter with field-specific query operators:

Filter Operators#

  • eq: Exact match
  • contains: Partial text match (case-insensitive)
  • in: Match any value in array

Examples#

Exact match filtering:

{
  "where": {
    "artist": { "eq": "Nirvana" },
    "condition": { "eq": "Mint" }
  }
}

Text search filtering:

{
  "where": {
    "title": { "contains": "nevermind" },
    "genre": { "contains": "grunge" }
  }
}

Array filtering:

{
  "where": {
    "condition": { "in": ["Mint", "Near Mint", "Very Good Plus"] },
    "artist": { "in": ["Nirvana", "Pearl Jam", "Soundgarden"] }
  }
}

Global search across all fields:

{
  "where": {
    "json": { "contains": "grunge" }
  }
}

Sorting#

Sort parameter uses an array format with field and direction:

{
  "sortBy": [
    { "field": "releaseDate", "direction": "desc" },
    { "field": "title", "direction": "asc" }
  ]
}

Examples:

  • [{ "field": "releaseDate", "direction": "desc" }] - Newest releases first
  • [{ "field": "artist", "direction": "asc" }] - Alphabetical by artist
  • [{ "field": "releaseDate", "direction": "desc" }, { "field": "title", "direction": "asc" }] - Newest first, then alphabetical by title

Next Steps#