Programmatic access to your StaffPhotoBoard data
The StaffPhotoBoard API uses API keys for authentication. You can create and manage API keys from your Organisation Settings page.
Include your API key in requests using one of these methods:
X-API-Key: spb_live_abc123...
?api_key=spb_live_abc123...
Security Note: Keep your API keys secure and never share them publicly. Revoke any keys that may have been exposed.
/api/v1/boards/:boardId/replace
Replace all members on a board with new data. Useful for bulk imports from HRIS systems.
{
"members": [
{
"name": "John Doe",
"title": "CEO",
"email": "[email protected]",
"bio": "Leading the company since 2020",
"department": "Executive",
"order": 0,
"photo": "https://example.com/photo.jpg" // Optional: URL or base64
}
],
"metadata": {
"source": "HRIS Integration",
"syncedAt": "2026-01-06T00:00:00Z"
}
}
The photo field is optional and supports two formats:
Provide a URL to the photo. The API will fetch and upload it automatically.
"photo": "https://hris.example.com/api/employees/12345/photo.jpg"
Best for: HRIS integrations, larger images, photos already hosted elsewhere
Encode the image as a base64 data URI and include it directly in the request.
"photo": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD..."
Best for: Small images (<1MB), direct uploads, when you have the image data
Simply omit the photo field if you don't want to upload a photo.
{
"name": "John Doe",
"title": "CEO",
"email": "[email protected]",
"order": 0
}
Supported formats: JPEG, PNG, GIF and other standard image formats. The format is automatically detected from the data URI mime type or the URL response content type.
📐 Recommended Image Specifications
Note: Images are automatically processed and optimised for display on photo boards. For best results, use portrait-oriented images close to the recommended 280×336 size.
{
"boardId": "board_123",
"membersReplaced": 10,
"photosUploaded": 8,
"processedAt": "2026-01-06T00:00:00Z",
"warnings": [
{
"memberId": "member_456",
"code": "PHOTO_DOWNLOAD_FAILED",
"message": "Photo URL returned 404"
}
]
}
API requests are rate-limited to ensure service stability:
429 Too Many RequestsRateLimit-Limit: 100
RateLimit-Remaining: 95
RateLimit-Reset: 1704585600
Errors follow RFC 7807 Problem Details format:
{
"type": "https://api.staffphotoboard.paneone.net/errors/rate-limit-exceeded",
"title": "Rate Limit Exceeded",
"status": 429,
"detail": "You have exceeded the rate limit of 100 requests per 60 seconds.",
"instance": "/api/v1/boards/board_123/replace",
"retryAfter": 60
}
| Code | Description |
|---|---|
| 400 | Bad Request - Invalid input |
| 401 | Unauthorised - Invalid API key |
| 403 | Forbidden - Insufficient permissions |
| 404 | Not Found - Resource doesn't exist |
| 429 | Too Many Requests - Rate limit exceeded |
| 500 | Internal Server Error - Service error |
curl -X PUT https://api.staffphotoboard.paneone.net/api/v1/boards/board_123/replace \
-H "X-API-Key: spb_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"members": [
{
"name": "Jane Smith",
"title": "Engineering Manager",
"email": "[email protected]",
"order": 0,
"photo": "https://hris.example.com/photos/jane-smith.jpg"
}
]
}'
# Convert image to base64
BASE64_IMAGE=$(base64 -i photo.jpg | tr -d '\n')
# Make the request
curl -X PUT https://api.staffphotoboard.paneone.net/api/v1/boards/board_123/replace \
-H "X-API-Key: spb_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"members": [
{
"name": "Jane Smith",
"title": "Engineering Manager",
"email": "[email protected]",
"order": 0,
"photo": "data:image/jpeg;base64,'$BASE64_IMAGE'"
}
]
}'
const response = await fetch(
'https://api.staffphotoboard.paneone.net/api/v1/boards/board_123/replace',
{
method: 'PUT',
headers: {
'X-API-Key': 'spb_live_abc123...',
'Content-Type': 'application/json'
},
body: JSON.stringify({
members: [
{
name: 'Jane Smith',
title: 'Engineering Manager',
email: '[email protected]',
order: 0,
photo: 'https://hris.example.com/photos/jane-smith.jpg'
}
]
})
}
);
const data = await response.json();
console.log(data);
const fs = require('fs');
// Read and encode image
const imageBuffer = fs.readFileSync('photo.jpg');
const base64Image = `data:image/jpeg;base64,${imageBuffer.toString('base64')}`;
const response = await fetch(
'https://api.staffphotoboard.paneone.net/api/v1/boards/board_123/replace',
{
method: 'PUT',
headers: {
'X-API-Key': 'spb_live_abc123...',
'Content-Type': 'application/json'
},
body: JSON.stringify({
members: [
{
name: 'Jane Smith',
title: 'Engineering Manager',
email: '[email protected]',
order: 0,
photo: base64Image
}
]
})
}
);
const data = await response.json();
console.log(data);
import requests
url = "https://api.staffphotoboard.paneone.net/api/v1/boards/board_123/replace"
headers = {
"X-API-Key": "spb_live_abc123...",
"Content-Type": "application/json"
}
data = {
"members": [
{
"name": "Jane Smith",
"title": "Engineering Manager",
"email": "[email protected]",
"order": 0,
"photo": "https://hris.example.com/photos/jane-smith.jpg"
}
]
}
response = requests.put(url, headers=headers, json=data)
print(response.json())
import requests
import base64
# Read and encode image
with open('photo.jpg', 'rb') as image_file:
base64_image = base64.b64encode(image_file.read()).decode('utf-8')
photo_data_uri = f"data:image/jpeg;base64,{base64_image}"
url = "https://api.staffphotoboard.paneone.net/api/v1/boards/board_123/replace"
headers = {
"X-API-Key": "spb_live_abc123...",
"Content-Type": "application/json"
}
data = {
"members": [
{
"name": "Jane Smith",
"title": "Engineering Manager",
"email": "[email protected]",
"order": 0,
"photo": photo_data_uri
}
]
}
response = requests.put(url, headers=headers, json=data)
print(response.json())