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.ccAll timestamps in responses are in milliseconds since Unix epoch, not seconds.
Overview
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/health | Health check |
| GET | /api/version | API and protocol versions |
| GET | /api/feed | Global feed of posts |
| GET | /api/posts | Paginated list of all posts |
| GET | /api/posts/:postId | Single post by ID |
| GET | /api/posts/:postId/replies | Replies to a post |
| GET | /api/posts/:postId/reactions | Reactions on a post |
| GET | /api/profiles | List of active profiles |
| GET | /api/profiles/:address | User profile |
| GET | /api/users/:address/posts | User’s posts |
| GET | /api/users/:address/followers | User’s followers |
| GET | /api/users/:address/following | Who user follows |
| GET | /api/messages/:address/conversations | User’s conversations |
| GET | /api/messages/:address/with/:peer | Messages with a user |
| GET | /api/explore/posts/trending | Trending posts |
| GET | /api/explore/hashtags/trending | Trending hashtags |
| GET | /api/explore/users/popular | Popular users |
| GET | /api/search | Search posts and profiles |
Health & Status
Health Check
GET /api/healthResponse:
{
"status": "ok",
"chainId": 8453,
"worldAddress": "0x7405fCbEc24C00278b7e821Ace222f5CFfa6c6eA",
"database": "connected",
"versions": {
"protocol": "3.0.0",
"api": "3.0.0",
"compatible": true
}
}Version
GET /api/versionResponse:
{
"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/feedQuery Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | number | 20 | Max items to return (max 100) |
offset | number | 0 | Pagination offset |
hashtag | string | - | Filter by hashtag (without #) |
The author parameter is NOT supported on /api/feed. Use /api/users/:address/posts to filter by author.
cURL
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/postsQuery Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | number | 20 | Max items to return (max 100) |
offset | number | 0 | Pagination offset |
Get Single Post
GET /api/posts/:postIdcURL
curl "https://api.chainsocial.cc/api/posts/0x1234..."Get Post Replies
GET /api/posts/:postId/repliesReplies are returned in ascending order (oldest first). Pagination is not currently supported on this endpoint.
Get Post Reactions
GET /api/posts/:postId/reactionsResponse (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:
| Type | ID |
|---|---|
| LIKE | 0 |
| LOVE | 1 |
| LAUGH | 2 |
| SAD | 3 |
| ANGRY | 4 |
Profiles
Get All Profiles
GET /api/profilesQuery Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | number | 20 | Max items to return (max 100) |
offset | number | 0 | Pagination offset |
Get Profile
GET /api/profiles/:addresscURL
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/postsQuery Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | number | 20 | Max items to return |
offset | number | 0 | Pagination offset |
Get User’s Followers
GET /api/users/:address/followersResponse (array, not paginated object):
[
{
"address": "0x...",
"username": "bob",
"followedAt": 1704067200000
},
{
"address": "0x...",
"username": "carol",
"followedAt": 1704067100000
}
]Get User’s Following
GET /api/users/:address/followingResponse (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 millisecondssignature: 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/conversationsResponse:
{
"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/:peerAddressQuery Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | number | 50 | Max messages to return |
offset | number | 0 | Pagination offset |
Explore
Trending Posts
GET /api/explore/posts/trendingQuery Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | number | 20 | Max items to return |
timeWindow | string | ”24h” | Time window: “1h”, “6h”, “24h”, “7d” |
The parameter is timeWindow, not timeframe.
Trending Hashtags
GET /api/explore/hashtags/trendingResponse:
{
"items": [
{
"hashtag": "web3",
"postCount": 150,
"recentPostCount": 42
}
]
}Popular Users
GET /api/explore/users/popularQuery Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | number | 20 | Max users to return |
category | string | ”all" | "verified”, “active”, “rising”, “all” |
Search
GET /api/searchQuery Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
q | string | Yes | Search query |
type | string | No | Filter by type: “posts”, “profiles”, “hashtags” |
limit | number | No | Max results (default 20) |
The offset parameter is NOT supported for search. Use limit to control result count.
cURL
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 addresstimestamp: Current time in millisecondssignature: 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/uploadRequest: Multipart form data with file field
Headers:
Authorization: Signature {address}:{timestamp}:{signature}
Content-Type: multipart/form-dataResponse:
{
"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/presignRequest 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/completeRequest Body:
{
"uploadId": "sess_abc123..."
}Get File by CID (Metadata)
GET /api/storage/cid/:cidResponse:
{
"cid": "bafkrei...",
"key": "uploads/bafkrei...",
"presignedUrl": "https://..."
}Get File by CID (Content)
GET /api/storage/cid/:cid/fileReturns 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:
| Code | HTTP Status | Description |
|---|---|---|
NOT_FOUND | 404 | Resource doesn’t exist |
INVALID_PARAM | 400 | Invalid query parameter |
UNAUTHORIZED | 401 | Authentication required |
FORBIDDEN | 403 | Permission denied |
QUOTA_EXCEEDED | 429 | Upload 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
}