API Reference
API Examples
Practical examples and code snippets for using the PentestPad API
Overview
This page provides practical examples for common API operations using different programming languages and tools.
Authentication Setup
First, set up authentication for all examples:
Environment Variables
export PENTESTPAD_API_KEY="pp_3kqz6Pj58v86KmPMkTmCUmpt2ZJWCqZR0LbGOHyD"
export PENTESTPAD_BASE_URL="https://your-instance.pentestpad.com/api/v1"
JavaScript/Node.js
const API_KEY = process.env.PENTESTPAD_API_KEY;
const BASE_URL = process.env.PENTESTPAD_BASE_URL;
const headers = {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
};
Python
import os
import requests
API_KEY = os.getenv('PENTESTPAD_API_KEY')
BASE_URL = os.getenv('PENTESTPAD_BASE_URL')
headers = {
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'
}
Project Management
Create a Complete Project Workflow
JavaScript Example
async function createProjectWorkflow() {
// 1. List available teams
const teams = await fetch(`${BASE_URL}/teams`, { headers })
.then(r => r.json());
console.log('Available teams:', teams.data.map(t => t.name));
// 2. Create new project
const projectData = {
name: 'E-commerce Security Assessment',
description: 'Comprehensive security testing of online shopping platform',
client_id: 1,
team_id: teams.data[0].id, // Use first available team
type_id: 1,
status: 'not_started',
start_date: '2024-04-01',
end_date: '2024-04-30'
};
const project = await fetch(`${BASE_URL}/projects`, {
method: 'POST',
headers,
body: JSON.stringify(projectData)
}).then(r => r.json());
console.log('Created project:', project.data.name, project.data.uuid);
// 3. Update project status to in-progress
await fetch(`${BASE_URL}/projects/${project.data.uuid}/status`, {
method: 'POST',
headers,
body: JSON.stringify({ status: 'in_progress' })
});
console.log('Project status updated to: in_progress');
return project.data;
}
Python Example
def create_project_workflow():
# 1. List available teams
teams_response = requests.get(f'{BASE_URL}/teams', headers=headers)
teams = teams_response.json()
print('Available teams:', [t['name'] for t in teams['data']])
# 2. Create new project
project_data = {
'name': 'E-commerce Security Assessment',
'description': 'Comprehensive security testing of online shopping platform',
'client_id': 1,
'team_id': teams['data'][0]['id'], # Use first available team
'type_id': 1,
'status': 'not_started',
'start_date': '2024-04-01',
'end_date': '2024-04-30'
}
project_response = requests.post(
f'{BASE_URL}/projects',
headers=headers,
json=project_data
)
project = project_response.json()
print(f"Created project: {project['data']['name']} ({project['data']['uuid']})")
# 3. Update project status
status_response = requests.post(
f"{BASE_URL}/projects/{project['data']['uuid']}/status",
headers=headers,
json={'status': 'in_progress'}
)
print('Project status updated to: in_progress')
return project['data']
cURL Example
#!/bin/bash
# 1. Get teams
TEAMS=$(curl -s -H "Authorization: Bearer $PENTESTPAD_API_KEY" \
"$PENTESTPAD_BASE_URL/teams")
echo "Available teams: $TEAMS"
# Extract first team ID (requires jq)
TEAM_ID=$(echo $TEAMS | jq -r '.data[0].id')
# 2. Create project
PROJECT=$(curl -s -X POST \
-H "Authorization: Bearer $PENTESTPAD_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "E-commerce Security Assessment",
"description": "Comprehensive security testing",
"client_id": 1,
"team_id": '$TEAM_ID',
"type_id": 1,
"status": "not_started",
"start_date": "2024-04-01",
"end_date": "2024-04-30"
}' \
"$PENTESTPAD_BASE_URL/projects")
echo "Created project: $PROJECT"
# Extract project UUID
PROJECT_UUID=$(echo $PROJECT | jq -r '.data.uuid')
# 3. Update status
curl -s -X POST \
-H "Authorization: Bearer $PENTESTPAD_API_KEY" \
-H "Content-Type: application/json" \
-d '{"status": "in_progress"}' \
"$PENTESTPAD_BASE_URL/projects/$PROJECT_UUID/status"
echo "Project status updated"
Finding Management
Create Findings from Different Sources
JavaScript Example
async function createFindingsWorkflow(projectId) {
// 1. Create finding from scratch
const sqlInjection = await fetch(`${BASE_URL}/projects/${projectId}/findings`, {
method: 'POST',
headers,
body: JSON.stringify({
title: 'SQL Injection in User Profile',
description: 'User profile update functionality vulnerable to SQL injection',
impact: 'high',
probability: 'medium',
poc: '1. Login to application\n2. Navigate to profile\n3. Update bio with: "); DROP TABLE users; --',
risks: 'Complete database compromise possible',
remediation: 'Use parameterized queries for all database operations',
cvss: 'CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H',
cvss_score: 8.8,
affected_hosts: [
{
endpoint: 'https://app.example.com/profile',
port: 443,
protocol: 'HTTPS',
description: 'User profile management'
}
],
categories: [1, 5], // Injection + Authentication
extra_fields: {
cwe_id: 'CWE-89',
owasp_category: 'A03:2021',
tool_detected: 'Manual Testing'
}
})
}).then(r => r.json());
console.log('Created SQL Injection finding:', sqlInjection.data.uuid);
// 2. Create finding from template
const templateFinding = await fetch(`${BASE_URL}/projects/${projectId}/findings/template`, {
method: 'POST',
headers,
body: JSON.stringify({
template_id: 15, // XSS template
title: 'XSS in Search Functionality',
affected_hosts: [
{
endpoint: 'https://app.example.com/search',
port: 443,
description: 'Main search feature'
}
]
})
}).then(r => r.json());
console.log('Created template-based finding:', templateFinding.data.uuid);
// 3. Update finding status
await fetch(`${BASE_URL}/findings/${sqlInjection.data.uuid}/remediation`, {
method: 'PATCH',
headers,
body: JSON.stringify({
remediation_stage: 'requested',
status: 'in-progress',
remediation: 'Requested client to implement parameterized queries. Provided code examples.'
})
});
console.log('Updated finding remediation status');
return [sqlInjection.data, templateFinding.data];
}
Python Example
def create_findings_workflow(project_id):
# 1. Create finding from scratch
finding_data = {
'title': 'SQL Injection in User Profile',
'description': 'User profile update functionality vulnerable to SQL injection',
'impact': 'high',
'probability': 'medium',
'poc': '1. Login to application\n2. Navigate to profile\n3. Update bio with: "); DROP TABLE users; --',
'risks': 'Complete database compromise possible',
'remediation': 'Use parameterized queries for all database operations',
'cvss': 'CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H',
'cvss_score': 8.8,
'affected_hosts': [
{
'endpoint': 'https://app.example.com/profile',
'port': 443,
'protocol': 'HTTPS',
'description': 'User profile management'
}
],
'categories': [1, 5], # Injection + Authentication
'extra_fields': {
'cwe_id': 'CWE-89',
'owasp_category': 'A03:2021',
'tool_detected': 'Manual Testing'
}
}
sql_injection = requests.post(
f'{BASE_URL}/projects/{project_id}/findings',
headers=headers,
json=finding_data
).json()
print(f"Created SQL Injection finding: {sql_injection['data']['uuid']}")
# 2. Create from template
template_data = {
'template_id': 15, # XSS template
'title': 'XSS in Search Functionality',
'affected_hosts': [
{
'endpoint': 'https://app.example.com/search',
'port': 443,
'description': 'Main search feature'
}
]
}
template_finding = requests.post(
f'{BASE_URL}/projects/{project_id}/findings/template',
headers=headers,
json=template_data
).json()
print(f"Created template-based finding: {template_finding['data']['uuid']}")
# 3. Update remediation status
requests.patch(
f"{BASE_URL}/findings/{sql_injection['data']['uuid']}/remediation",
headers=headers,
json={
'remediation_stage': 'requested',
'status': 'in-progress',
'remediation': 'Requested client to implement parameterized queries. Provided code examples.'
}
)
print('Updated finding remediation status')
return [sql_injection['data'], template_finding['data']]
CSV Import Workflow
Complete CSV Import Process
JavaScript Example
async function csvImportWorkflow(projectId, csvFile) {
// 1. Get field mapping information first
const fieldInfo = await fetch(`${BASE_URL}/csv/field-mapping`, { headers })
.then(r => r.json());
console.log('CSV Field Requirements:');
Object.entries(fieldInfo.data.field_mapping).forEach(([field, description]) => {
console.log(` ${field}: ${description}`);
});
// 2. Validate CSV file
if (csvFile.size > 10 * 1024 * 1024) {
throw new Error('File too large. Maximum size is 10MB.');
}
const fileName = csvFile.name.toLowerCase();
if (!fileName.endsWith('.csv') && !fileName.endsWith('.txt')) {
throw new Error('Invalid file format. Use .csv or .txt files.');
}
// 3. Import CSV
const formData = new FormData();
formData.append('file', csvFile);
const importResult = await fetch(`${BASE_URL}/projects/${projectId}/findings/import-csv`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}` // Note: Don't include Content-Type for FormData
},
body: formData
}).then(r => r.json());
// 4. Process results
console.log(`Import completed: ${importResult.data.success_count} successes, ${importResult.data.error_count} errors`);
if (importResult.data.error_count > 0) {
console.log('Errors encountered:');
importResult.data.errors.forEach(error => {
console.log(` Row ${error.row}: ${error.error}`);
});
}
console.log('Successfully imported findings:');
importResult.data.imported_findings.forEach(finding => {
console.log(` Row ${finding.row}: ${finding.title} (${finding.uuid})`);
});
return importResult;
}
// Usage example with file input
document.getElementById('csvFileInput').addEventListener('change', async (event) => {
const file = event.target.files[0];
if (file) {
try {
await csvImportWorkflow('project-uuid-here', file);
} catch (error) {
console.error('Import failed:', error.message);
}
}
});
Python Example
import csv
from io import StringIO
def csv_import_workflow(project_id, csv_file_path):
# 1. Get field mapping information
field_info = requests.get(f'{BASE_URL}/csv/field-mapping', headers=headers).json()
print('CSV Field Requirements:')
for field, description in field_info['data']['field_mapping'].items():
print(f' {field}: {description}')
# 2. Validate file
import os
file_size = os.path.getsize(csv_file_path)
if file_size > 10 * 1024 * 1024: # 10MB
raise ValueError('File too large. Maximum size is 10MB.')
if not csv_file_path.lower().endswith(('.csv', '.txt')):
raise ValueError('Invalid file format. Use .csv or .txt files.')
# 3. Import CSV
with open(csv_file_path, 'rb') as f:
files = {'file': (os.path.basename(csv_file_path), f, 'text/csv')}
response = requests.post(
f'{BASE_URL}/projects/{project_id}/findings/import-csv',
headers={'Authorization': f'Bearer {API_KEY}'}, # No Content-Type for multipart
files=files
)
import_result = response.json()
# 4. Process results
success_count = import_result['data']['success_count']
error_count = import_result['data']['error_count']
print(f'Import completed: {success_count} successes, {error_count} errors')
if error_count > 0:
print('Errors encountered:')
for error in import_result['data']['errors']:
print(f" Row {error['row']}: {error['error']}")
print('Successfully imported findings:')
for finding in import_result['data']['imported_findings']:
print(f" Row {finding['row']}: {finding['title']} ({finding['uuid']})")
return import_result
# Create sample CSV for testing
def create_sample_csv(filename='sample_findings.csv'):
sample_data = [
{
'title': 'SQL Injection in Login Form',
'impact': 'high',
'probability': 'medium',
'description': 'Login form vulnerable to SQL injection attacks',
'poc': "1. Navigate to /login\n2. Enter: admin' OR 1=1 --\n3. Observe bypass",
'risks': 'Unauthorized access, data breach',
'remediation': 'Use parameterized queries',
'affected_hosts': 'https://example.com/login,https://api.example.com/auth',
'categories': '1,2',
'extra_fields': '{"cwe_id": "CWE-89", "owasp": "A03:2021"}'
},
{
'title': 'Cross-Site Scripting (XSS)',
'impact': 'medium',
'probability': 'high',
'description': 'Reflected XSS in search parameter',
'poc': '1. Go to /search?q=<script>alert(1)</script>\n2. Observe execution',
'risks': 'Session hijacking, credential theft',
'remediation': 'Implement proper output encoding',
'affected_hosts': '{"endpoint": "https://example.com/search", "port": 443}',
'categories': '3',
'status': 'draft'
}
]
with open(filename, 'w', newline='', encoding='utf-8') as f:
if sample_data:
writer = csv.DictWriter(f, fieldnames=sample_data[0].keys())
writer.writeheader()
writer.writerows(sample_data)
print(f'Created sample CSV: {filename}')
return filename
Error Handling
Robust Error Handling Example
JavaScript Example
class PentestPadAPI {
constructor(apiKey, baseUrl) {
this.apiKey = apiKey;
this.baseUrl = baseUrl;
this.headers = {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
};
}
async request(endpoint, options = {}) {
const url = `${this.baseUrl}${endpoint}`;
const config = {
headers: this.headers,
...options
};
try {
const response = await fetch(url, config);
const data = await response.json();
if (!response.ok) {
throw new APIError(data.message || 'Request failed', response.status, data);
}
return data;
} catch (error) {
if (error instanceof APIError) {
throw error;
}
// Network or other errors
throw new APIError(`Network error: ${error.message}`, 0, error);
}
}
async getProjects(filters = {}) {
const params = new URLSearchParams(filters).toString();
const endpoint = `/projects${params ? `?${params}` : ''}`;
try {
return await this.request(endpoint);
} catch (error) {
console.error('Failed to get projects:', error.message);
throw error;
}
}
async createFinding(projectId, findingData) {
try {
return await this.request(`/projects/${projectId}/findings`, {
method: 'POST',
body: JSON.stringify(findingData)
});
} catch (error) {
if (error.status === 422) {
console.error('Validation errors:', error.data.errors);
}
throw error;
}
}
}
class APIError extends Error {
constructor(message, status, data) {
super(message);
this.name = 'APIError';
this.status = status;
this.data = data;
}
}
Python Example
import requests
from requests.exceptions import RequestException, ConnectionError, Timeout
import json
class PentestPadAPI:
def __init__(self, api_key, base_url):
self.api_key = api_key
self.base_url = base_url
self.headers = {
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
}
def request(self, endpoint, method='GET', data=None, files=None):
url = f'{self.base_url}{endpoint}'
headers = self.headers.copy()
# Remove Content-Type for file uploads
if files:
headers.pop('Content-Type', None)
try:
response = requests.request(
method=method,
url=url,
headers=headers,
json=data if data and not files else None,
files=files,
timeout=30
)
# Try to parse JSON response
try:
response_data = response.json()
except json.JSONDecodeError:
response_data = {'message': response.text}
if not response.ok:
raise APIError(
response_data.get('message', 'Request failed'),
response.status_code,
response_data
)
return response_data
except ConnectionError:
raise APIError('Connection failed. Check your network or API endpoint.', 0)
except Timeout:
raise APIError('Request timed out. Try again later.', 0)
except RequestException as e:
raise APIError(f'Request failed: {str(e)}', 0)
class APIError(Exception):
def __init__(self, message, status, data=None):
super().__init__(message)
self.message = message
self.status = status
self.data = data or {}
Templates Management
Create and Use Vulnerability Templates
JavaScript Example
async function manageVulnerabilityTemplates() {
// 1. Create a new vulnerability template
const templateData = {
title: 'Buffer Overflow Template',
description: 'Template for buffer overflow vulnerabilities',
impact: 'Critical',
probability: 'Medium',
cvss: 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H',
cvss_score: 9.8,
poc: '1. Identify vulnerable function\n2. Create overflow payload\n3. Execute shellcode',
risks: 'Remote code execution, system compromise',
remediation: '1. Use safe string functions\n2. Implement stack canaries\n3. Enable DEP/ASLR',
categories: [1, 4],
project_types: [1, 3]
};
const template = await fetch(`${BASE_URL}/templates/vulnerabilities`, {
method: 'POST',
headers,
body: JSON.stringify(templateData)
}).then(r => r.json());
console.log('Created template:', template.data.id);
// 2. Use template to create finding in project
const finding = await fetch(`${BASE_URL}/projects/${projectId}/findings/template`, {
method: 'POST',
headers,
body: JSON.stringify({
template_id: template.data.id,
title: 'Buffer Overflow in Authentication Module',
affected_hosts: [
{
endpoint: 'https://app.example.com/auth',
port: 443,
description: 'Authentication service'
}
]
})
}).then(r => r.json());
console.log('Created finding from template:', finding.data.uuid);
return { template: template.data, finding: finding.data };
}
Python Example
def manage_vulnerability_templates():
# 1. Create vulnerability template
template_data = {
'title': 'CSRF Template',
'description': 'Cross-Site Request Forgery template',
'impact': 'Medium',
'probability': 'High',
'cvss': 'CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N',
'cvss_score': 6.5,
'poc': '1. Craft malicious form\n2. Host on attacker site\n3. Trick user into submission',
'risks': 'Unauthorized actions on behalf of user',
'remediation': '1. Implement CSRF tokens\n2. Verify Referer header\n3. Use SameSite cookies',
'categories': [2, 5],
'project_types': [1]
}
template_response = requests.post(
f'{BASE_URL}/templates/vulnerabilities',
headers=headers,
json=template_data
)
template = template_response.json()
print(f"Created template: {template['data']['id']}")
# 2. List all templates
templates_response = requests.get(
f'{BASE_URL}/templates/vulnerabilities',
headers=headers
)
templates = templates_response.json()
print(f"Total templates: {templates['total']}")
return template['data']
Import Templates from CSV
JavaScript Example
async function importTemplatesFromCsv(csvFile) {
// 1. Get field mapping first
const fieldMapping = await fetch(`${BASE_URL}/templates/vulnerabilities/csv/field-mapping`, {
headers
}).then(r => r.json());
console.log('Required fields:', Object.keys(fieldMapping.data.field_mapping));
// 2. Import vulnerability templates
const formData = new FormData();
formData.append('file', csvFile);
const importResult = await fetch(`${BASE_URL}/templates/vulnerabilities/import-csv`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}` // Only auth header for multipart
},
body: formData
}).then(r => r.json());
console.log(`Imported ${importResult.data.success_count} vulnerability templates`);
if (importResult.data.error_count > 0) {
console.log('Errors:', importResult.data.errors);
}
return importResult;
}
Python Example with Sample CSV Creation
def import_vulnerability_templates():
# 1. Create sample CSV
import csv
sample_templates = [
{
'title': 'SQL Injection Template',
'impact': 'High',
'probability': 'Medium',
'description': 'SQL injection vulnerability template',
'poc': '1. Find injection point\n2. Test with quotes\n3. Extract data',
'risks': 'Data breach, authentication bypass',
'remediation': 'Use parameterized queries',
'cvss': 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N',
'cvss_score': '8.1',
'categories': '1,2',
'project_types': '1',
'extra_fields': '{"cwe_id": "CWE-89", "owasp": "A03:2021"}'
},
{
'title': 'XSS Template',
'impact': 'Medium',
'probability': 'High',
'description': 'Cross-site scripting template',
'poc': '1. Find reflection point\n2. Test XSS payload\n3. Execute JavaScript',
'risks': 'Session hijacking, credential theft',
'remediation': 'Implement output encoding and CSP',
'cvss': 'CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N',
'cvss_score': '6.1',
'categories': '2,3',
'project_types': '1',
'extra_fields': '{"cwe_id": "CWE-79", "owasp": "A03:2021"}'
}
]
# Write to CSV
filename = 'vulnerability_templates.csv'
with open(filename, 'w', newline='', encoding='utf-8') as f:
if sample_templates:
writer = csv.DictWriter(f, fieldnames=sample_templates[0].keys())
writer.writeheader()
writer.writerows(sample_templates)
# 2. Import the CSV
with open(filename, 'rb') as f:
files = {'file': (filename, f, 'text/csv')}
response = requests.post(
f'{BASE_URL}/templates/vulnerabilities/import-csv',
headers={'Authorization': f'Bearer {API_KEY}'},
files=files
)
result = response.json()
print(f"Import completed: {result['data']['success_count']} templates imported")
return result
Quick Examples
Get All Projects
curl -H "Authorization: Bearer your_api_key" \
https://your-instance.pentestpad.com/api/v1/projects
Create a Finding
curl -X POST \
-H "Authorization: Bearer your_api_key" \
-H "Content-Type: application/json" \
-d '{
"title": "SQL Injection",
"impact": "High",
"probability": "Medium",
"description": "SQL injection vulnerability found"
}' \
https://your-instance.pentestpad.com/api/v1/projects/project-uuid/findings
Create Vulnerability Template
curl -X POST \
-H "Authorization: Bearer your_api_key" \
-H "Content-Type: application/json" \
-d '{
"title": "CSRF Template",
"impact": "Medium",
"probability": "High",
"description": "Cross-Site Request Forgery template"
}' \
https://your-instance.pentestpad.com/api/v1/templates/vulnerabilities
Import Findings CSV
curl -X POST \
-H "Authorization: Bearer your_api_key" \
-F "file=@findings.csv" \
https://your-instance.pentestpad.com/api/v1/projects/project-uuid/findings/import-csv
Import Templates CSV
curl -X POST \
-H "Authorization: Bearer your_api_key" \
-F "file=@vulnerability_templates.csv" \
https://your-instance.pentestpad.com/api/v1/templates/vulnerabilities/import-csv
This comprehensive guide provides practical, real-world examples for integrating with the PentestPad API across different programming languages and use cases.