Skip to Content
Building AppsAPI Reference

API Reference

The ChainSocial API provides indexed data from the blockchain. Use it for fast reads without needing a wallet connection.

Base URL

https://api.chainsocial.cc

All timestamps in responses are in milliseconds since Unix epoch, not seconds.

Overview

MethodEndpointDescription
GET/api/healthHealth check
GET/api/versionAPI and protocol versions
GET/api/feedGlobal feed of posts
GET/api/postsPaginated list of all posts
GET/api/posts/:postIdSingle post by ID
GET/api/posts/:postId/repliesReplies to a post
GET/api/posts/:postId/reactionsReactions on a post
GET/api/profilesList of active profiles
GET/api/profiles/:addressUser profile
GET/api/users/:address/postsUser’s posts
GET/api/users/:address/followersUser’s followers
GET/api/users/:address/followingWho user follows
GET/api/messages/:address/conversationsUser’s conversations
GET/api/messages/:address/with/:peerMessages with a user
GET/api/explore/posts/trendingTrending posts
GET/api/explore/hashtags/trendingTrending hashtags
GET/api/explore/users/popularPopular users
GET/api/searchSearch posts and profiles

Health & Status

Health Check

GET /api/health

Response:

{ "status": "ok", "chainId": 8453, "worldAddress": "0x7405fCbEc24C00278b7e821Ace222f5CFfa6c6eA", "database": "connected", "versions": { "protocol": "3.0.0", "api": "3.0.0", "compatible": true } }

Version

GET /api/version

Response:

{ "protocol": { "onchain": "3.0.0", "indexed": "3.0.0" }, "api": { "version": "3.0.0", "supportedProtocols": ["3.0.0", "2.0.0"] }, "indexer": { "syncing": false, "latestBlock": 12345678 }, "compatibility": { "compatible": true } }

Feed

Get Global Feed

GET /api/feed

Query Parameters:

ParameterTypeDefaultDescription
limitnumber20Max items to return (max 100)
offsetnumber0Pagination offset
hashtagstring-Filter by hashtag (without #)

The author parameter is NOT supported on /api/feed. Use /api/users/:address/posts to filter by author.

curl "https://api.chainsocial.cc/api/feed?limit=10"

Response:

{ "items": [ { "post": { "postId": "0x...", "author": "0x...", "contentId": "0x...", "content": "Hello world!", "visibility": "PUBLIC", "createdAt": 1704067200000, "editedAt": null, "replyTo": null, "quoteOf": null, "isDeleted": false, "isEdited": false }, "author": { "address": "0x...", "username": "alice", "joinedAt": 1704000000000, "lastActiveAt": 1704067200000, "isVerified": false, "isActive": true, "metadata": { "displayName": "Alice", "bio": "Web3 developer", "avatar": { "uri": "ipfs://bafkrei...", "mimeType": "image/png" } } } } ], "page": { "limit": 10, "offset": 0 } }

Posts

Get All Posts

GET /api/posts

Query Parameters:

ParameterTypeDefaultDescription
limitnumber20Max items to return (max 100)
offsetnumber0Pagination offset

Get Single Post

GET /api/posts/:postId
curl "https://api.chainsocial.cc/api/posts/0x1234..."

Get Post Replies

GET /api/posts/:postId/replies

Replies are returned in ascending order (oldest first). Pagination is not currently supported on this endpoint.

Get Post Reactions

GET /api/posts/:postId/reactions

Response (array of reactions):

[ { "postId": "0x...", "user": "0x...", "reactionType": "LIKE", "reactionTypeId": 0, "createdAt": 1704067200000 }, { "postId": "0x...", "user": "0x...", "reactionType": "LOVE", "reactionTypeId": 1, "createdAt": 1704067300000 } ]

Reaction Types:

TypeID
LIKE0
LOVE1
LAUGH2
SAD3
ANGRY4

Profiles

Get All Profiles

GET /api/profiles

Query Parameters:

ParameterTypeDefaultDescription
limitnumber20Max items to return (max 100)
offsetnumber0Pagination offset

Get Profile

GET /api/profiles/:address
curl "https://api.chainsocial.cc/api/profiles/0x1234..."

Response:

{ "profile": { "address": "0x...", "username": "alice", "joinedAt": 1704000000000, "lastActiveAt": 1704067200000, "isVerified": false, "isActive": true, "metadata": { "displayName": "Alice", "bio": "Web3 developer", "avatar": { "uri": "ipfs://bafkrei...", "mimeType": "image/png" }, "coverImage": { "uri": "ipfs://bafkrei...", "mimeType": "image/jpeg" }, "website": "https://alice.xyz", "links": [ { "type": "twitter", "url": "https://twitter.com/alice", "handle": "@alice" } ] } }, "followerCount": 150, "followingCount": 42 }

Users

Get User’s Posts

GET /api/users/:address/posts

Query Parameters:

ParameterTypeDefaultDescription
limitnumber20Max items to return
offsetnumber0Pagination offset

Get User’s Followers

GET /api/users/:address/followers

Response (array, not paginated object):

[ { "address": "0x...", "username": "bob", "followedAt": 1704067200000 }, { "address": "0x...", "username": "carol", "followedAt": 1704067100000 } ]

Get User’s Following

GET /api/users/:address/following

Response (array, not paginated object):

[ { "address": "0x...", "username": "dave", "followedAt": 1704067200000 } ]

Messages

Message endpoints require authentication. You can only access your own messages.

Authentication

Message endpoints require signature-based authentication. Include an Authorization header:

Authorization: Bearer <base64(JSON.stringify({ address, timestamp, signature }))>

Where:

  • address: Your wallet address (lowercase)
  • timestamp: Current time in milliseconds
  • signature: EIP-191 signature of: ChainSocial API Authentication\nAddress: {address}\nTimestamp: {timestamp}

The timestamp must be within 2 minutes of the server time.

Alternative: API tokens can be used for service-to-service authentication:

Authorization: API-Key <token>

Get Conversations

GET /api/messages/:address/conversations

Response:

{ "items": [ { "participant1": "0x...", "participant2": "0x...", "peerAddress": "0x...", "peer": { "address": "0x...", "username": "bob" }, "lastMessageAt": 1704067200000, "messageCount": 42, "unreadCount": 3, "lastMessage": { "messageId": "0x...", "sender": "0x...", "content": "Hey!", "sentAt": 1704067200000 } } ] }

Get Messages with User

GET /api/messages/:address/with/:peerAddress

Query Parameters:

ParameterTypeDefaultDescription
limitnumber50Max messages to return
offsetnumber0Pagination offset

Explore

GET /api/explore/posts/trending

Query Parameters:

ParameterTypeDefaultDescription
limitnumber20Max items to return
timeWindowstring”24h”Time window: “1h”, “6h”, “24h”, “7d”

The parameter is timeWindow, not timeframe.

GET /api/explore/hashtags/trending

Response:

{ "items": [ { "hashtag": "web3", "postCount": 150, "recentPostCount": 42 } ] }
GET /api/explore/users/popular

Query Parameters:

ParameterTypeDefaultDescription
limitnumber20Max users to return
categorystring”all""verified”, “active”, “rising”, “all”

GET /api/search

Query Parameters:

ParameterTypeRequiredDescription
qstringYesSearch query
typestringNoFilter by type: “posts”, “profiles”, “hashtags”
limitnumberNoMax results (default 20)

The offset parameter is NOT supported for search. Use limit to control result count.

curl "https://api.chainsocial.cc/api/search?q=ethereum&limit=10"

Storage

The Storage API handles file uploads and retrieval. Files are stored in S3 and referenced by content-addressed CIDs.

Authentication (Storage)

Storage upload endpoints require a different authentication format:

Authorization: Signature {address}:{timestamp}:{signature}

Where:

  • address: Your wallet address
  • timestamp: Current time in milliseconds
  • signature: EIP-191 signature of: ChainSocial Storage Auth\nTimestamp: {timestamp}\nAction: {action}

The action is typically “upload” for upload endpoints. The timestamp must be within 2 minutes.

Upload File

POST /api/storage/upload

Request: Multipart form data with file field

Headers:

Authorization: Signature {address}:{timestamp}:{signature} Content-Type: multipart/form-data

Response:

{ "cid": "bafkrei...", "content": { "contentType": "image/png", "size": 12345 }, "locations": [ { "type": "s3", "key": "uploads/bafkrei..." } ], "presignedUrl": "https://...", "quotaRemaining": { "uploads": 95, "bytes": 99000000 } }

Allowed Content Types:

  • Images: image/png, image/jpeg, image/gif, image/webp, image/svg+xml
  • Video: video/mp4, video/webm, video/quicktime
  • Audio: audio/mpeg, audio/wav, audio/ogg, audio/webm
  • Documents: application/pdf

Create Presigned Upload URL

POST /api/storage/presign

Request Body:

{ "contentType": "image/png", "fileName": "avatar.png", "maxSize": 5000000 }

Response:

{ "uploadId": "sess_abc123...", "uploadUrl": "https://s3.../presigned-url", "expiresAt": 1704070800000 }

Complete Presigned Upload

POST /api/storage/complete

Request Body:

{ "uploadId": "sess_abc123..." }

Get File by CID (Metadata)

GET /api/storage/cid/:cid

Response:

{ "cid": "bafkrei...", "key": "uploads/bafkrei...", "presignedUrl": "https://..." }

Get File by CID (Content)

GET /api/storage/cid/:cid/file

Returns the actual file content. This endpoint:

  • Is publicly accessible (no authentication required)
  • Returns the file with appropriate Content-Type header
  • Sets long cache headers (Cache-Control: public, max-age=31536000, immutable)
  • Returns 304 Not Modified for matching ETags

Use /api/storage/cid/{cid}/file for displaying images in your app. This provides a stable, non-expiring URL unlike presigned S3 URLs.

Quotas

Storage has daily upload limits:

  • Max uploads per day: 100 (configurable via STORAGE_MAX_UPLOADS_PER_DAY)
  • Max bytes per day: 100MB (configurable via STORAGE_MAX_BYTES_PER_DAY)

Quotas reset every 24 hours.


Error Handling

All errors return JSON with this structure:

{ "error": "Error message", "code": "ERROR_CODE" }

Common Error Codes:

CodeHTTP StatusDescription
NOT_FOUND404Resource doesn’t exist
INVALID_PARAM400Invalid query parameter
UNAUTHORIZED401Authentication required
FORBIDDEN403Permission denied
QUOTA_EXCEEDED429Upload quota exceeded

Visibility Rules

Posts have three visibility levels:

  • PUBLIC (0): Visible to everyone
  • FOLLOWERS (1): Visible only to users who follow the author
  • PRIVATE (2): Visible only to the author

When authenticated, you can see:

  • All PUBLIC posts
  • FOLLOWERS posts from users you follow
  • PRIVATE posts you authored

When unauthenticated, you can only see PUBLIC posts.


Indexer Syncing

Some endpoints may return indexerSyncing: true in the response when the indexer is still catching up with the blockchain. During this time, data may be incomplete or stale.

{ "items": [], "indexerSyncing": true }