Quickstart
Welcome to the Pindown.ai API v1 - transform your automation data into beautiful, real-time dashboards and shareable reports.
Base URL
https://api.pindown.ai/v1Authentication
All API endpoints require authentication via API Keys. You can generate API keys in your dashboard settings.
Creating an API Key
- Navigate to Dashboard → API Keys
- Click “Generate New API Key”
- Give your key a descriptive name (e.g., “Production Automation”)
- Select the required scopes/permissions
- Copy your API key immediately - it will only be shown once!
Using Your API Key
Include your API key in the Authorization header:
Authorization: Bearer pk_live_your_api_key_hereSecurity Note: Keep your API keys secure and never commit them to version control. Use environment variables in production.
API Overview
The Pindown.ai API v1 provides RESTful endpoints for managing your automation dashboards:
| Resource | Description | Endpoint |
|---|---|---|
| Pins | Create and update visual pin-cards (stats, charts, tables) | /v1/pins |
| Pin Blocks | Add dynamic content blocks (markdown, conditionals, images) | /v1/pins/:pinId/blocks |
| Pinboards | Organize pins into shareable dashboards | /v1/pinboards |
| Datasets | Store and manage data sources | /v1/datasets |
API Features
âś… Real-time Updates - Push data and see instant changes
âś… 14+ Pin Card Types - Stats, charts, tables, alerts, and more
âś… Template Variables - Dynamic content with {{variable}} syntax
âś… RBAC & Sharing - Granular permissions (owner, editor, viewer)
âś… Batch Operations - Update multiple pins in one request
âś… Scoped API Keys - Fine-grained access control
Quick Start
1. Create a Stat Card Pin
Create a simple stat card showing your automation metrics:
curl -X POST https://api.pindown.ai/v1/pins \
-H "Authorization: Bearer pk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"data_type": "pin-card",
"pin_type": "stat-cards",
"pin_layout": "1x1",
"content": {
"cards": [{
"title": "Total Sales",
"value": "$12,450",
"change": "+23.5%",
"trend": "up"
}]
},
"metadata": {
"title": "Sales Dashboard",
"tags": ["sales", "analytics"],
"is_public": false
}
}'Response:
{
"success": true,
"data": {
"pin_id": "p-abc123def456",
"shareable_url": "https://pindown.ai/share/pin/p-abc123def456",
"created_at": "2024-11-01T15:30:00Z"
}
}2. Update Pin Data (Real-time)
Update your pin’s data to see instant changes on your dashboard:
curl -X PUT https://api.pindown.ai/v1/pins/p-abc123def456 \
-H "Authorization: Bearer pk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"content": {
"cards": [{
"title": "Total Sales",
"value": "$15,230",
"change": "+45.2%",
"trend": "up"
}]
}
}'3. Create a Pinboard Dashboard
Organize multiple pins into a visual dashboard:
curl -X POST https://api.pindown.ai/v1/pinboards \
-H "Authorization: Bearer pk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"title": "Marketing Dashboard",
"description": "Real-time marketing metrics",
"tags": ["marketing", "kpis"],
"is_public": false
}'4. Add Pin to Pinboard
curl -X POST https://api.pindown.ai/v1/pinboards/pb-xyz789/pins \
-H "Authorization: Bearer pk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"pin_id": "p-abc123def456",
"position": {
"x": 0,
"y": 0,
"w": 2,
"h": 1
}
}'Response Format
All API v1 responses include standard HTTP status codes and consistent JSON structures:
Success Response (2xx)
{
"success": true,
"data": {
"pin_id": "p-abc123",
"shareable_url": "https://pindown.ai/share/pin/p-abc123"
}
}Error Response (4xx, 5xx)
{
"error": {
"code": "VALIDATION_FAILED",
"message": "Pin card type is required",
"details": {
"field": "pin_type",
"expected": "stat-cards | line-chart | flexible-table | ..."
}
}
}Common Error Codes
| Code | Status | Description |
|---|---|---|
UNAUTHORIZED | 401 | Invalid or missing API key |
FORBIDDEN | 403 | Insufficient scopes/permissions |
NOT_FOUND | 404 | Resource doesn’t exist |
VALIDATION_FAILED | 400 | Invalid request body |
RATE_LIMIT_EXCEEDED | 429 | Too many requests |
Rate Limits
Rate limits are enforced per API key based on your subscription tier:
| Tier | Requests/Hour | Requests/Minute | Best For |
|---|---|---|---|
| Starter (Free) | 16/hour | 1/min | Testing API |
| Professional | 1,000/hour | 60/min | Production apps |
| Team | 5,000/hour | 300/min | Team automation |
Rate Limit Headers
Every API response includes rate limit information:
X-RateLimit-Limit-Hour: 3000
X-RateLimit-Remaining-Hour: 2847
X-RateLimit-Reset-Hour: 2024-11-01T16:00:00Z
X-RateLimit-Limit-Minute: 50
X-RateLimit-Remaining-Minute: 42
X-RateLimit-Reset-Minute: 2024-11-01T15:31:00Z
X-RateLimit-Token-Cost: 2Rate Limit Exceeded Response
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. You've used 51 tokens out of 50 per minute.",
"details": {
"limit": 50,
"used": 51,
"window": "minute",
"resetAt": "2024-11-01T15:31:00Z",
"tier": "hobby",
"upgrade_url": "https://pindown.ai/pricing"
}
}
}API Examples
Explore comprehensive examples organized from simplest to most complex:
- Pin with Blocks - Create a simple pin and add content blocks (markdown, code, images)
- Datasets & Template Variables - Store data separately and reference it with
{{variables}} - Pinboard with Pins - Create visual dashboards with pins
- Pinboards with Pin Cards - Create visual dashboards with stats, charts, and tables
- Sharing Pins - Share individual pins with collaborators
- Sharing Pinboards - Share entire dashboards with your team
- Custom Roles & Permissions - Advanced role-based access control
SDKs and Examples
JavaScript/Node.js
const PINDOWN_API_KEY = process.env.PINDOWN_API_KEY;
const API_BASE = 'https://api.pindown.ai/v1';
// Create a stat card pin
async function createStatCard(title, value, change) {
const response = await fetch(`${API_BASE}/pins`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${PINDOWN_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
data_type: 'pin-card',
pin_type: 'stat-cards',
pin_layout: '1x1',
content: {
cards: [{
title,
value,
change,
trend: change.startsWith('+') ? 'up' : 'down'
}]
},
metadata: {
title: `${title} Card`,
is_public: false
}
})
});
if (!response.ok) {
throw new Error(`API Error: ${response.statusText}`);
}
return response.json();
}
// Update pin data (real-time)
async function updatePin(pinId, newContent) {
const response = await fetch(`${API_BASE}/pins/${pinId}`, {
method: 'PUT',
headers: {
'Authorization': `Bearer ${PINDOWN_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ content: newContent })
});
return response.json();
}
// Example: Update sales every 5 seconds
const salesPinId = 'p-abc123';
setInterval(async () => {
const newSales = await fetchSalesData(); // Your data source
await updatePin(salesPinId, {
cards: [{
title: 'Total Sales',
value: `$${newSales.toLocaleString()}`,
change: `+${((newSales / lastSales - 1) * 100).toFixed(1)}%`,
trend: 'up'
}]
});
}, 5000);Python
import requests
import os
from typing import Dict, Any
PINDOWN_API_KEY = os.environ.get('PINDOWN_API_KEY')
API_BASE = 'https://api.pindown.ai/v1'
def create_stat_card(title: str, value: str, change: str) -> Dict[str, Any]:
"""Create a stat card pin"""
response = requests.post(
f'{API_BASE}/pins',
headers={
'Authorization': f'Bearer {PINDOWN_API_KEY}',
'Content-Type': 'application/json'
},
json={
'data_type': 'pin-card',
'pin_type': 'stat-cards',
'pin_layout': '1x1',
'content': {
'cards': [{
'title': title,
'value': value,
'change': change,
'trend': 'up' if change.startswith('+') else 'down'
}]
},
'metadata': {
'title': f'{title} Card',
'is_public': False
}
}
)
response.raise_for_status()
return response.json()
def update_pin(pin_id: str, new_content: Dict[str, Any]) -> Dict[str, Any]:
"""Update pin data in real-time"""
response = requests.put(
f'{API_BASE}/pins/{pin_id}',
headers={
'Authorization': f'Bearer {PINDOWN_API_KEY}',
'Content-Type': 'application/json'
},
json={'content': new_content}
)
response.raise_for_status()
return response.json()
# Example: Update metrics from your automation
if __name__ == '__main__':
# Create pin
result = create_stat_card('API Calls', '12,450', '+23.5%')
pin_id = result['data']['pin_id']
print(f"Created pin: {pin_id}")
# Update pin with new data
update_pin(pin_id, {
'cards': [{
'title': 'API Calls',
'value': '15,230',
'change': '+45.2%',
'trend': 'up'
}]
})
print("Pin updated successfully!")Next Steps
Explore the complete API documentation:
- Pins API - Create and manage pin-cards (stats, charts, tables, alerts)
- Pinboards API - Build visual dashboards and organize pins
- Datasets API - Store and manage data sources (JSON, markdown)
- Blocks API - Add dynamic content blocks to pins
API Scopes
When creating an API key, you can grant fine-grained permissions:
| Scope | Access | Description |
|---|---|---|
datasets:read | Read-only | List and view datasets |
datasets:write | Read + Write | Create, update, delete datasets |
pins:read | Read-only | List and view pins |
pins:write | Read + Write | Create, update, delete pins |
pins:share | Share | Update sharing settings |
pinboards:read | Read-only | List and view pinboards |
pinboards:write | Read + Write | Create, update, delete pinboards |
pinboards:invite | Invite | Manage collaborators |
* | Full Access | All permissions (use with caution) |
Best Practice: Use the minimum required scopes for each API key. For example, a read-only dashboard only needs pins:read and pinboards:read.
Support
- đź’¬ Discord: Join our communityÂ