VibeCircle Bot API
Quick Start
1. Get an API Token
Go to Settings > API Tokens in the VibeCircle app, or call:
curl -X POST https://pg-me.know.tw/api/api-tokens \
-H "Cookie: session_token=YOUR_SESSION" \
-H "Content-Type: application/json" \
-d '{"label": "My Bot", "expiresInDays": 90}'
The response includes a token field (e.g. vbc_a1b2c3d4...). Save it immediately — it is only shown once.
2. Authenticate
Include the token in all requests:
Authorization: Bearer vbc_your_token_here
3. Send a Message
# Create or get a DM thread
curl -X POST https://pg-me.know.tw/api/dm/threads \
-H "Authorization: Bearer vbc_..." \
-H "Content-Type: application/json" \
-d '{"participantId": "USER_CUID"}'
# Send a text message
curl -X POST https://pg-me.know.tw/api/dm/threads/THREAD_ID/messages \
-H "Authorization: Bearer vbc_..." \
-H "Content-Type: application/json" \
-d '{"body": "Hello from bot!"}'
4. Send a Photo
# Step 1: Request upload URL
curl -X POST https://pg-me.know.tw/api/media/upload-url \
-H "Authorization: Bearer vbc_..." \
-H "Content-Type: application/json" \
-d '{"filename": "photo.jpg", "mimeType": "image/jpeg", "sizeBytes": 123456}'
# Response: {"url": "https://s3.../presigned-url", "objectKey": "uploads/user123/abc.jpg"}
# Step 2: Upload file to the presigned URL
curl -X PUT "PRESIGNED_URL" \
-H "Content-Type: image/jpeg" \
--data-binary @photo.jpg
# Step 3: Register the upload
curl -X POST https://pg-me.know.tw/api/media/complete \
-H "Authorization: Bearer vbc_..." \
-H "Content-Type: application/json" \
-d '{"objectKey": "uploads/user123/abc.jpg", "mimeType": "image/jpeg", "sizeBytes": 123456}'
# Response: {"id": "MEDIA_ID", ...}
# Step 4: Send message with the image
curl -X POST https://pg-me.know.tw/api/dm/threads/THREAD_ID/messages \
-H "Authorization: Bearer vbc_..." \
-H "Content-Type: application/json" \
-d '{"body": "Check this out!", "mediaObjectId": "MEDIA_ID"}'
Interactive Docs
Full API reference with "Try it out" is available at:
https://pg-me.know.tw/api/docs
Endpoint Reference
All endpoints are under /api. Protected endpoints require Authorization: Bearer vbc_... header.
Auth (Public)
| Method | Path | Description |
|--------|------|-------------|
| POST | /auth/magic-link | Send magic link email {email} |
| GET | /auth/verify?token=X&email=Y | Verify magic link, set session cookie |
| GET | /auth/session | Get current session (returns {user} or null) |
| POST | /auth/logout | Logout, clear session |
API Tokens (Protected)
| Method | Path | Description |
|--------|------|-------------|
| GET | /api-tokens | List active tokens |
| POST | /api-tokens | Create token {label, expiresInDays?} |
| DELETE | /api-tokens/:tokenId | Revoke token |
Users (Protected)
| Method | Path | Description |
|--------|------|-------------|
| GET | /users/me | Get own profile |
| PATCH | /users/me | Update profile {name?, image?} |
| GET | /users/search?email=X | Search users by email |
| GET | /users/:userId | Get user profile |
DM (Protected)
| Method | Path | Description |
|--------|------|-------------|
| GET | /dm/threads | List DM threads |
| POST | /dm/threads | Create thread {participantId, isE2ee?} |
| GET | /dm/threads/:threadId/messages | List messages ?cursor=&limit= |
| POST | /dm/threads/:threadId/messages | Send message {body?, mediaObjectId?} |
Media (Protected)
| Method | Path | Description |
|--------|------|-------------|
| POST | /media/upload-url | Get presigned upload URL {filename, mimeType, sizeBytes} |
| POST | /media/complete | Register completed upload {objectKey, mimeType, sizeBytes, ...} |
Friends (Protected)
| Method | Path | Description |
|--------|------|-------------|
| GET | /friends?status=ACCEPTED | List friends |
| POST | /friends/request | Send friend request {friendId} |
| POST | /friends/:id/accept | Accept request |
| POST | /friends/:id/reject | Reject request |
| PATCH | /friends/:id/tier | Update tier {tier: CLOSE_FRIEND\|FRIEND\|ACQUAINTANCE} |
| DELETE | /friends/:id | Remove friend |
Feed (Protected)
| Method | Path | Description |
|--------|------|-------------|
| GET | /feed | Get feed (presences + pins from friends) |
Spotify (Protected)
| Method | Path | Description |
|--------|------|-------------|
| GET | /spotify/connect | Redirect to Spotify OAuth |
| GET | /spotify/callback | OAuth callback |
| DELETE | /spotify | Unlink Spotify |
Pins (Protected)
| Method | Path | Description |
|--------|------|-------------|
| GET | /pins | List pins |
| POST | /pins | Create pin {spotifyTrackId, trackName, artistName, albumName, ...} |
| DELETE | /pins/:id | Delete pin |
Presence (Protected)
| Method | Path | Description |
|--------|------|-------------|
| GET | /presence/:userId | Get user's current presence |
| PATCH | /presence/settings | Update presence visibility {audienceTier} |
Realtime Events (Pusher/Soketi)
Bot can subscribe to private-user-{userId} channel for live events:
| Event | Payload | Description |
|-------|---------|-------------|
| new-message | {threadId, message} | New DM message received |
| friend-request | {friendshipId, from} | Incoming friend request |
| friend-accepted | {friendshipId} | Friend request accepted |
Pusher auth endpoint: POST /api/pusher/auth
Error Responses
All errors return JSON:
{"error": "Error message"}
Common status codes:
400— Bad request / validation error401— Unauthorized (missing or invalid token)403— Forbidden404— Not found