API Reference
API Reference
Access BuoyForms programmatically with our REST API.
Authentication
All API requests require an API key passed in the Authorization header:
Authorization: Bearer YOUR_API_KEYCreate API keys in Settings > API Keys.
Base URL
https://api.buoyforms.com/v1Rate Limits
Rate limits vary by plan and are enforced per API key:
| Plan | Requests/Minute |
|---|---|
| Free | 10 |
| Pro | 100 |
| Business | 500 |
| Enterprise | 2,000 |
Rate Limit Headers
Every API response includes rate limit headers:
| Header | Description |
|---|---|
X-RateLimit-Limit |
Maximum requests per window |
X-RateLimit-Remaining |
Requests remaining in current window |
X-RateLimit-Reset |
Unix timestamp when limit resets |
Handling Rate Limits
When rate limited, the API returns HTTP 429 with a Retry-After header indicating seconds to wait.
{
"error": "rate_limit_exceeded",
"message": "Too many requests",
"retryAfter": 45
}Best practices:
- Implement exponential backoff on 429 responses
- Cache responses where possible
- Batch operations when supported
- Monitor your
X-RateLimit-Remainingheader
Endpoints
Forms
List Forms
GET /formsQuery Parameters:
limit(integer, default 50): Results per pageoffset(integer, default 0): Pagination offsetstatus(string): Filter bydraftorpublished
Response:
{
"data": [
{
"id": "form_abc123",
"title": "Contact Form",
"slug": "contact",
"status": "published",
"createdAt": "2025-01-15T10:00:00Z",
"updatedAt": "2025-01-20T14:30:00Z"
}
],
"pagination": {
"total": 42,
"limit": 50,
"offset": 0
}
}Get Form
GET /forms/:formIdCreate Form
POST /formsBody:
{
"title": "Survey Form",
"description": "Customer feedback survey",
"slug": "survey"
}Update Form
PATCH /forms/:formIdDelete Form
DELETE /forms/:formIdSubmissions
List Submissions
GET /forms/:formId/submissionsQuery Parameters:
limit(integer, default 50): Results per pageoffset(integer, default 0): Pagination offsetstartDate(ISO date): Filter by submission dateendDate(ISO date): Filter by submission date
Get Submission
GET /submissions/:submissionIdCreate Submission
POST /forms/:formId/submissionsUsed for programmatic form submissions. Bypasses CAPTCHA.
Body:
{
"fields": {
"email": "user@example.com",
"message": "Hello!"
},
"metadata": {
"source": "api"
}
}Delete Submission
DELETE /submissions/:submissionIdFields
List Form Fields
GET /forms/:formId/fieldsCreate Field
POST /forms/:formId/fieldsUpdate Field
PATCH /fields/:fieldIdDelete Field
DELETE /fields/:fieldIdWebhooks
List Webhooks
GET /webhooksCreate Webhook
POST /webhooksBody:
{
"url": "https://your-app.com/webhook",
"events": ["submission.created"],
"formId": "form_abc123"
}Update Webhook
PATCH /webhooks/:webhookIdDelete Webhook
DELETE /webhooks/:webhookIdError Responses
Errors return appropriate HTTP status codes with JSON body:
{
"error": "validation_error",
"message": "Invalid request body",
"details": [
{
"field": "email",
"message": "Invalid email format"
}
]
}| Status | Description |
|---|---|
| 400 | Bad Request - Invalid parameters |
| 401 | Unauthorized - Invalid or missing API key |
| 403 | Forbidden - Insufficient permissions |
| 404 | Not Found - Resource doesn't exist |
| 429 | Too Many Requests - Rate limit exceeded |
| 500 | Internal Server Error |
Webhooks Signature Verification
Verify webhook authenticity using the X-Signature header:
const crypto = require('crypto');
function verifySignature(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}SDK Support
Official SDKs coming soon:
- JavaScript/TypeScript
- Python
- Ruby
- Go
Changelog
- 2025-11-27: Added rate limiting headers and documentation
- 2025-11-20: Initial API release