PostoBox API
Welcome to the PostoBox API documentation. Use this API to integrate PostoBox with your applications and services.
The PostoBox API is a RESTful API that allows you to programmatically manage events, questions, and organization data. All requests and responses use JSON format.
Base URL
https://api.postobox.app/v1Content Type
application/jsonAPI Version
/v1 on the API subdomain.Authentication
All API requests require authentication using an API key.
Getting an API Key
To get an API key, you need to be an owner or admin of an organization. Navigate to Settings → API Keys in your dashboard.
- Go to your organization settings
- Click on "API Keys" in the Integrations section
- Click "Create Key" and select the required scopes
- Copy your API key - it will only be shown once
Using Your API Key
Include your API key in the Authorization header using the Bearer scheme:
curl -X GET "https://api.postobox.app/v1/events" \
-H "Authorization: Bearer pk_live_xxxx_your_api_key_here"Keep Your Key Secret
Permission Scopes
API keys have granular permission scopes. Only request the scopes you need:
| Scope | Description |
|---|---|
events:read | List and view events |
events:write | Create, update, and delete events |
questions:read | List and view questions |
questions:write | Submit new questions and vote on questions |
questions:moderate | Approve, reject, and delete questions |
organization:read | View organization information |
Rate Limiting
API requests are rate limited based on your organization's plan.
| Plan | Requests per Minute |
|---|---|
| Free | 60 |
| Starter | 300 |
| Professional | 1,000 |
| Enterprise | 5,000 |
Rate limit information is included in the response headers:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests per minute |
X-RateLimit-Remaining | Requests remaining in current window |
X-RateLimit-Reset | Unix timestamp when the limit resets |
Retry-After | Seconds until you can retry (only on 429 responses) |
Error Handling
The API uses standard HTTP status codes and returns errors in a consistent format.
All error responses follow this format:
{
"error": {
"message": "Description of what went wrong",
"status": 400,
"code": "ERROR_CODE",
"details": { ... }
}
}HTTP Status Codes
| Code | Description |
|---|---|
| 200 | Success |
| 201 | Created |
| 204 | No Content (successful delete) |
| 400 | Bad Request - Invalid parameters |
| 401 | Unauthorized - Invalid or missing API key |
| 403 | Forbidden - Insufficient permissions |
| 404 | Not Found |
| 409 | Conflict - Resource already exists |
| 429 | Rate limit exceeded |
| 500 | Internal server error |
Events
Manage Q&A events for your organization.
/eventsList all events for your organization.
Required Scope
events:readQuery Parameters
| Parameter | Type | Description |
|---|---|---|
page | integer | Page number for paginationDefault: 1 |
limit | integer | Items per page (max 100)Default: 20 |
active | boolean | Filter by active status |
Example Request
curl -X GET "https://api.postobox.app/v1/events?page=1&limit=10" \
-H "Authorization: Bearer pk_live_xxxx_your_key"Example Response
{
"data": [
{
"id": "clx123...",
"title": "Tech Conference 2024",
"slug": "tech-conference-2024",
"description": "Annual tech conference",
"startDate": "2024-06-01T09:00:00.000Z",
"endDate": "2024-06-01T18:00:00.000Z",
"active": true,
"needModeration": true,
"allowAnonymous": true,
"questionCount": 42,
"createdAt": "2024-05-01T10:00:00.000Z"
}
],
"pagination": {
"page": 1,
"limit": 10,
"total": 5,
"totalPages": 1
}
}/eventsCreate a new event.
Required Scope
events:writeRequest Body
| Parameter | Type | Description |
|---|---|---|
title* | string | Event title (2-200 chars) |
subtitle | string | Event subtitle (max 500 chars) |
slug* | string | URL-friendly identifier (lowercase, hyphens only) |
description | string | Event description (max 5000 chars) |
startDate* | ISO 8601 | Event start date/time |
endDate* | ISO 8601 | Event end date/time |
needModeration | boolean | Require question moderationDefault: true |
allowAnonymous | boolean | Allow anonymous questionsDefault: true |
maxQuestionLength | integer | Max question lengthDefault: 1200 |
active | boolean | Event is accepting questionsDefault: false |
Example Request
curl -X POST "https://api.postobox.app/v1/events" \
-H "Authorization: Bearer pk_live_xxxx_your_key" \
-H "Content-Type: application/json" \
-d '{
"title": "Product Launch Q&A",
"slug": "product-launch-qa",
"description": "Ask questions about our new product",
"startDate": "2024-07-15T14:00:00.000Z",
"endDate": "2024-07-15T16:00:00.000Z",
"needModeration": true,
"active": false
}'/events/{eventId}Get a specific event by ID.
Required Scope
events:readPath Parameters
| Parameter | Type | Description |
|---|---|---|
eventId* | string | The event ID |
/events/{eventId}Update an existing event. Only include fields you want to change.
Required Scope
events:writeExample Request
curl -X PATCH "https://api.postobox.app/v1/events/clx123..." \
-H "Authorization: Bearer pk_live_xxxx_your_key" \
-H "Content-Type: application/json" \
-d '{
"active": true,
"title": "Updated Event Title"
}'/events/{eventId}Delete an event. This is a soft delete - the event can be recovered.
Required Scope
events:writeQuestions
Manage questions within events.
/events/{eventId}/questionsList all questions for an event.
Required Scope
questions:readQuery Parameters
| Parameter | Type | Description |
|---|---|---|
page | integer | Page numberDefault: 1 |
limit | integer | Items per page (max 100)Default: 20 |
status | string | Filter by status: DEFAULT, SELECTED, ANSWERED, REJECTED |
sortBy | string | Sort field: createdAt, voteCountDefault: createdAt |
sortOrder | string | Sort order: asc, descDefault: desc |
Example Response
{
"data": [
{
"id": "clq123...",
"text": "What's the roadmap for 2024?",
"voteCount": 15,
"status": "SELECTED",
"isAnonymous": true,
"authorUsername": null,
"createdAt": "2024-06-01T10:30:00.000Z"
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 42,
"totalPages": 3
}
}/events/{eventId}/questionsSubmit a new question to an event.
Required Scope
questions:writeRequest Body
| Parameter | Type | Description |
|---|---|---|
text* | string | Question text |
identifier | string | Custom identifier for the submitter |
Example Request
curl -X POST "https://api.postobox.app/v1/events/clx123.../questions" \
-H "Authorization: Bearer pk_live_xxxx_your_key" \
-H "Content-Type: application/json" \
-d '{
"text": "What are the key features of the new release?",
"identifier": "user-12345"
}'/events/{eventId}/questions/{questionId}Get a specific question by ID.
Required Scope
questions:read/events/{eventId}/questions/{questionId}Update a question's status (moderation).
Required Scope
questions:moderateRequest Body
| Parameter | Type | Description |
|---|---|---|
status* | string | New status: DEFAULT, SELECTED, ANSWERED, or REJECTED |
Question Statuses
| Status | Description |
|---|---|
DEFAULT | Pending moderation |
SELECTED | Approved, visible to audience |
ANSWERED | Question has been answered |
REJECTED | Rejected, hidden from audience |
Example Request
curl -X PATCH "https://api.postobox.app/v1/events/clx.../questions/clq..." \
-H "Authorization: Bearer pk_live_xxxx_your_key" \
-H "Content-Type: application/json" \
-d '{ "status": "SELECTED" }'/events/{eventId}/questions/{questionId}Delete a question.
Required Scope
questions:moderate/events/{eventId}/questions/{questionId}/voteVote or unvote on a question. This is a toggle action - calling it again will remove the vote.
Required Scope
questions:writeRequest Body
| Parameter | Type | Description |
|---|---|---|
identifier* | string | Unique identifier for the voter (e.g., user ID in your system). Used to prevent duplicate votes. |
Vote Identity
Example Request
curl -X POST "https://api.postobox.app/v1/events/clx.../questions/clq.../vote" \
-H "Authorization: Bearer pk_live_xxxx_your_key" \
-H "Content-Type: application/json" \
-d '{ "identifier": "user-12345" }'Example Response
{
"data": {
"questionId": "clq123...",
"voted": true,
"voteCount": 16
}
}Toggle Behavior
| Current State | Action | Result |
|---|---|---|
| Not voted | POST /vote | voted: true, count +1 |
| Already voted | POST /vote | voted: false, count -1 |
/events/{eventId}/questions/streamReal-time stream of questions using Server-Sent Events (SSE). Receive updates when questions are added or votes change.
Required Scope
questions:readEnterprise Only
PLAN_UPGRADE_REQUIRED.Example Request
curl -N "https://api.postobox.app/v1/events/clx.../questions/stream" \
-H "Authorization: Bearer pk_live_xxxx_your_key"Stream Format
The stream sends data in SSE format. Updates are sent every 3 seconds when data changes, with heartbeats every 15 seconds to keep the connection alive.
data: [{"id":"clq123...","text":"What's the roadmap?",
"voteCount":15,"status":"SELECTED","isAnonymous":true,
"authorUsername":null,"createdAt":"2024-06-01T10:30:00.000Z"}]
:heartbeat 0
data: [{"id":"clq123...","voteCount":16,"status":"SELECTED",...}]
:heartbeat 1JavaScript Example
const eventSource = new EventSource(
'https://api.postobox.app/v1/events/clx.../questions/stream',
{
headers: {
'Authorization': 'Bearer pk_live_xxxx_your_key'
}
}
);
eventSource.onmessage = (event) => {
const questions = JSON.parse(event.data);
console.log('Questions updated:', questions);
};
eventSource.onerror = (error) => {
console.error('SSE error:', error);
eventSource.close();
};Stream Data
| Field | Type | Description |
|---|---|---|
id | string | Question ID |
text | string | Question text |
voteCount | integer | Current vote count |
status | string | SELECTED (only selected questions are streamed) |
isAnonymous | boolean | Whether question is anonymous |
authorUsername | string | null | Author username if not anonymous |
createdAt | ISO 8601 | Creation timestamp |
updatedAt | ISO 8601 | Last update timestamp |
Organization
Get information about your organization.
/organizationGet your organization's information including usage and limits.
Required Scope
organization:readExample Response
{
"data": {
"id": "clo123...",
"name": "Acme Corp",
"subdomain": "acme",
"slug": "acme-corp",
"logo": "https://...",
"primaryColor": "#BE123C",
"plan": "PROFESSIONAL",
"limits": {
"maxEvents": 50,
"maxQuestions": 5000
},
"usage": {
"eventCount": 12,
"questionCount": 847,
"memberCount": 5
},
"isActive": true,
"createdAt": "2024-01-15T10:00:00.000Z"
}
}