Skip to content

API Examples

This page provides practical examples for common API operations using different programming languages and tools.

First, set up authentication for all examples:

Terminal window
export PENTESTPAD_API_KEY="pp_3kqz6Pj58v86KmPMkTmCUmpt2ZJWCqZR0LbGOHyD"
export PENTESTPAD_BASE_URL="https://your-instance.pentestpad.com/api/v1"
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'
};
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'
}
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;
}
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']
#!/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"
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];
}
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']]
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);
}
}
});
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
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;
}
}
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 {}
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 };
}
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']
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;
}
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
Terminal window
curl -H "Authorization: Bearer your_api_key" \
https://your-instance.pentestpad.com/api/v1/projects
Terminal window
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
Terminal window
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
Terminal window
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
Terminal window
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.