Skip to main content

Getting Started with the PlanOps API

This guide will walk you through making your first API call to PlanOps in under 5 minutes.

Quick Start

1. Get Your Access Token

Follow Authentication Guide to obtain a token. For quick testing:

  1. Sign in to PlanOps in your browser
  2. Open DevTools (F12) → Console
  3. Run: const token = await window.Clerk.getToken(); console.log(token);
  4. Copy the token

2. Make Your First Request

Try fetching your projects:

curl https://test-api.projectjump.app/api/v1/projects \
-H "Authorization: Bearer YOUR_TOKEN"

Response:

{
"items": [
{
"id": "proj_abc123",
"name": "Office Building Construction",
"description": "New office development project",
"status": "active",
"created_at": "2025-01-15T10:30:00Z"
}
],
"total": 1,
"page": 1,
"page_size": 50
}

🎉 Congratulations! You just made your first API call.

Common Use Cases

List Projects

Get all projects you have access to:

import requests

headers = {'Authorization': f'Bearer {token}'}
response = requests.get(
'https://test-api.projectjump.app/api/v1/projects',
headers=headers
)

projects = response.json()
for project in projects['items']:
print(f"{project['name']} ({project['id']})")

Create a Task

Add a new task to a project:

task_data = {
"title": "Review architectural drawings",
"description": "Complete review by end of week",
"project_id": "proj_abc123",
"status": "pending",
"priority": "high",
"due_date": "2025-01-20T17:00:00Z"
}

response = requests.post(
'https://test-api.projectjump.app/api/v1/tasks',
headers=headers,
json=task_data
)

task = response.json()
print(f"Created task: {task['id']}")

Search Documents

Find documents by keyword:

params = {
"query": "foundation drawings",
"limit": 10,
"project_id": "proj_abc123"
}

response = requests.get(
'https://test-api.projectjump.app/api/v1/search',
headers=headers,
params=params
)

results = response.json()
for doc in results['items']:
print(f"{doc['title']} - {doc['document_type']}")

Upload a Document

Upload a file to a project:

# Read the file
with open('drawing.pdf', 'rb') as f:
files = {'file': ('drawing.pdf', f, 'application/pdf')}
data = {
'project_id': 'proj_abc123',
'document_type': 'drawing',
'title': 'Site Plan - Rev A',
}

response = requests.post(
'https://test-api.projectjump.app/api/v1/documents',
headers={'Authorization': f'Bearer {token}'},
files=files,
data=data
)

document = response.json()
print(f"Uploaded: {document['id']}")

Error Handling

Always handle errors appropriately:

import requests

def api_call(endpoint, method='GET', **kwargs):
"""Make an API call with error handling."""
url = f'https://test-api.projectjump.app{endpoint}'
headers = kwargs.pop('headers', {})
headers['Authorization'] = f'Bearer {token}'

response = requests.request(method, url, headers=headers, **kwargs)

# Handle errors
if response.status_code == 401:
raise Exception("Token expired or invalid - get a new token")
elif response.status_code == 403:
raise Exception("Permission denied - check user permissions")
elif response.status_code == 404:
raise Exception("Resource not found")
elif response.status_code >= 400:
error = response.json().get('detail', 'Unknown error')
raise Exception(f"API error: {error}")

return response.json()

# Usage
try:
projects = api_call('/api/v1/projects')
print(f"Found {len(projects['items'])} projects")
except Exception as e:
print(f"Error: {e}")

Pagination

Most list endpoints support pagination:

def fetch_all_projects():
"""Fetch all projects across multiple pages."""
all_projects = []
page = 1
page_size = 50

while True:
response = requests.get(
'https://test-api.projectjump.app/api/v1/projects',
headers=headers,
params={'page': page, 'page_size': page_size}
)

data = response.json()
all_projects.extend(data['items'])

# Check if there are more pages
if len(data['items']) < page_size:
break

page += 1

return all_projects

projects = fetch_all_projects()
print(f"Total projects: {len(projects)}")

Rate Limiting

The API implements rate limiting to ensure fair usage:

  • Rate limit: 100 requests per minute per user
  • Headers:
    • X-RateLimit-Limit: Maximum requests allowed
    • X-RateLimit-Remaining: Requests remaining
    • X-RateLimit-Reset: Time when limit resets (Unix timestamp)

Handle rate limits:

import time

response = requests.get(url, headers=headers)

if response.status_code == 429: # Too Many Requests
retry_after = int(response.headers.get('Retry-After', 60))
print(f"Rate limited. Waiting {retry_after} seconds...")
time.sleep(retry_after)
response = requests.get(url, headers=headers) # Retry

Best Practices

1. Reuse Tokens

Don't fetch a new token for every request. Tokens are valid for 60 minutes:

class PlanOpsClient:
def __init__(self, token):
self.token = token
self.base_url = 'https://test-api.projectjump.app'
self.headers = {'Authorization': f'Bearer {token}'}

def get_projects(self):
return requests.get(
f'{self.base_url}/api/v1/projects',
headers=self.headers
).json()

def get_tasks(self, project_id):
return requests.get(
f'{self.base_url}/api/v1/tasks',
headers=self.headers,
params={'project_id': project_id}
).json()

# Initialize once
client = PlanOpsClient(token)

# Reuse for multiple calls
projects = client.get_projects()
tasks = client.get_tasks('proj_abc123')

2. Use Meaningful Error Messages

Log request details for debugging:

import logging

logger = logging.getLogger(__name__)

try:
response = requests.post(url, headers=headers, json=data)
response.raise_for_status()
except requests.HTTPError as e:
logger.error(
f"API request failed: {e.response.status_code} "
f"{e.response.text} (URL: {url})"
)
raise

3. Validate Data Before Sending

Check required fields before making requests:

def create_task(title, project_id, **kwargs):
"""Create a task with validation."""
if not title or not project_id:
raise ValueError("title and project_id are required")

task_data = {
'title': title,
'project_id': project_id,
**kwargs
}

return requests.post(
'https://test-api.projectjump.app/api/v1/tasks',
headers=headers,
json=task_data
).json()

Next Steps

Now that you've made your first API calls, explore:

Example Projects

Check out these example integrations:

Python Script

#!/usr/bin/env python3
"""Export all tasks from a project to CSV."""

import csv
import requests
import sys

TOKEN = "your_token_here"
PROJECT_ID = "proj_abc123"

headers = {'Authorization': f'Bearer {TOKEN}'}

# Fetch tasks
response = requests.get(
'https://test-api.projectjump.app/api/v1/tasks',
headers=headers,
params={'project_id': PROJECT_ID}
)

tasks = response.json()['items']

# Write to CSV
with open('tasks.csv', 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=['id', 'title', 'status', 'priority', 'due_date'])
writer.writeheader()
writer.writerows(tasks)

print(f"Exported {len(tasks)} tasks to tasks.csv")

Node.js Integration

const fetch = require('node-fetch');

const API_BASE = 'https://test-api.projectjump.app';
const TOKEN = 'your_token_here';

async function getProjects() {
const response = await fetch(`${API_BASE}/api/v1/projects`, {
headers: { 'Authorization': `Bearer ${TOKEN}` }
});

if (!response.ok) {
throw new Error(`API error: ${response.statusText}`);
}

return response.json();
}

async function main() {
const projects = await getProjects();
console.log(`Found ${projects.items.length} projects`);

for (const project of projects.items) {
console.log(`- ${project.name} (${project.status})`);
}
}

main().catch(console.error);

Need Help?


Last updated: 2025-12-12