Clients API
The Clients API provides full CRUD operations for managing clients, along with user management endpoints for inviting and removing client users. You can create, read, update, and delete clients, manage custom fields, and control client portal access through these endpoints.
Endpoints
Section titled “Endpoints”List Clients
Section titled “List Clients”Get a paginated list of clients with optional search and sorting.
GET /api/v1/clientsQuery Parameters:
search(string) - Search clients by company namesortBy(string) - Sort by field:company_name,website,contact_person_name,contact_email,contact_phone(default:company_name)sortDirection(string) - Sort direction:ascordesc(default:asc)per_page(integer) - Results per page, max 100 (default: 15)
Response:
{ "success": true, "data": [ { "id": 1, "company_name": "Acme Corporation", "website": "https://acme.com", "address": "123 Main St", "city": "New York", "country": "US", "contact_person_name": "Jane Smith", "contact_person_position": "CTO", "contact_phone": "+1-555-0123", "contact_email": "jane@acme.com", "color": "#3B82F6", "industry_id": 2, "permissions": { "can_view": true, "can_create": true, "can_edit_and_delete": true }, "created_at": "2024-02-15T10:30:00.000000Z", "updated_at": "2024-03-10T14:20:00.000000Z" } ], "meta": { "current_page": 1, "per_page": 15, "total": 73, "last_page": 5 }}Get Client
Section titled “Get Client”Get detailed information about a specific client, including users, custom fields, and project count.
GET /api/v1/clients/{id}Response:
{ "success": true, "data": { "id": 1, "company_name": "Acme Corporation", "website": "https://acme.com", "address": "123 Main St", "city": "New York", "country": "US", "contact_person_name": "Jane Smith", "contact_person_position": "CTO", "contact_phone": "+1-555-0123", "contact_email": "jane@acme.com", "color": "#3B82F6", "industry_id": 2, "access_status": "active", "custom_fields": { "contract_type": "Annual", "sla_tier": "Premium" }, "projects_count": 5, "users": [ { "id": 10, "name": "Jane Smith", "email": "jane@acme.com", "type": "client", "created_at": "2024-02-15T10:30:00.000000Z" } ], "permissions": { "can_view": true, "can_create": true, "can_edit_and_delete": true }, "created_at": "2024-02-15T10:30:00.000000Z", "updated_at": "2024-03-10T14:20:00.000000Z" }}Create Client
Section titled “Create Client”Create a new client with optional custom fields.
POST /api/v1/clientsRequest Body:
{ "company_name": "Globex Corporation", "website": "https://globex.com", "address": "456 Corporate Blvd", "city": "San Francisco", "country": "US", "industry_id": 3, "contact_person_name": "Hank Scorpio", "contact_person_position": "CEO", "contact_phone": "+1-555-0456", "contact_email": "hank@globex.com", "color": "#10B981", "custom_fields": { "contract_type": "Monthly", "sla_tier": "Standard" }}Response:
{ "success": true, "message": "Client created successfully.", "data": { "id": 2, "company_name": "Globex Corporation" }}Update Client
Section titled “Update Client”Update an existing client.
PUT /api/v1/clients/{id}PATCH /api/v1/clients/{id}Request Body (partial update with PATCH):
{ "company_name": "Globex Corp", "contact_email": "security@globex.com", "custom_fields": { "contract_type": "Annual", "sla_tier": "Premium" }}All fields from the create endpoint are accepted. With PATCH, only provided fields are updated. Custom fields are merged — existing keys not included in the request are preserved.
Response:
{ "success": true, "message": "Client updated successfully.", "data": { "id": 2, "company_name": "Globex Corp", // ... full client details }}Delete Client
Section titled “Delete Client”Soft delete a client. The client cannot be deleted if it has active (non-archived) projects.
DELETE /api/v1/clients/{id}Response:
{ "success": true, "message": "Client deleted successfully."}List Client Users
Section titled “List Client Users”Get all users associated with a client.
GET /api/v1/clients/{id}/usersResponse:
{ "success": true, "data": [ { "id": 10, "name": "Jane Smith", "email": "jane@acme.com", "type": "client", "created_at": "2024-02-15T10:30:00.000000Z" }, { "id": 11, "name": "John Doe", "email": "john@acme.com", "type": "client", "created_at": "2024-03-01T09:00:00.000000Z" } ]}Invite User to Client
Section titled “Invite User to Client”Invite a new user to the client portal. The user will receive an email invitation to set up their account.
POST /api/v1/clients/{id}/users/inviteRequest Body:
{ "name": "Bob Wilson", "email": "bob@acme.com"}Response:
{ "success": true, "message": "User invited successfully.", "data": { "id": 12, "name": "Bob Wilson", "email": "bob@acme.com" }}Remove User from Client
Section titled “Remove User from Client”Remove a user from the client. The user account will be soft-deleted.
DELETE /api/v1/clients/{id}/users/{user_id}Response:
{ "success": true, "message": "User deleted successfully."}Examples
Section titled “Examples”Create a Client with Custom Fields
Section titled “Create a Client with Custom Fields”curl -X POST \ -H "Authorization: Bearer your_api_key" \ -H "Content-Type: application/json" \ -d '{ "company_name": "Acme Corporation", "website": "https://acme.com", "contact_person_name": "Jane Smith", "contact_email": "jane@acme.com", "custom_fields": { "contract_type": "Annual", "sla_tier": "Premium" } }' \ https://your-instance.pentestpad.com/api/v1/clientsList Clients with Search and Sorting
Section titled “List Clients with Search and Sorting”curl -H "Authorization: Bearer your_api_key" \ "https://your-instance.pentestpad.com/api/v1/clients?search=acme&sortBy=company_name&sortDirection=asc&per_page=25"Invite a User to a Client
Section titled “Invite a User to a Client”curl -X POST \ -H "Authorization: Bearer your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "Bob Wilson", "email": "bob@acme.com" }' \ https://your-instance.pentestpad.com/api/v1/clients/1/users/inviteJavaScript Example
Section titled “JavaScript Example”// Create a new clientconst newClient = await fetch('/api/v1/clients', { method: 'POST', headers: { 'Authorization': 'Bearer your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ company_name: 'Acme Corporation', website: 'https://acme.com', contact_person_name: 'Jane Smith', contact_email: 'jane@acme.com' })}).then(r => r.json());
// Get client details with usersconst client = await fetch(`/api/v1/clients/${newClient.data.id}`, { headers: { 'Authorization': 'Bearer your_api_key' }}).then(r => r.json());
// Invite a user to the client portalconst invitation = await fetch(`/api/v1/clients/${newClient.data.id}/users/invite`, { method: 'POST', headers: { 'Authorization': 'Bearer your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'Bob Wilson', email: 'bob@acme.com' })}).then(r => r.json());Field Validation
Section titled “Field Validation”Required Fields
Section titled “Required Fields”company_name(string, max 255)
Optional Fields
Section titled “Optional Fields”website(string, valid URL, max 255)address(string, max 255)city(string, max 255)country(string, max 255)industry_id(integer, must reference a valid industry)contact_person_name(string, max 255)contact_person_position(string, max 255)contact_phone(string, max 255)contact_email(string, valid email, max 255)color(string, max 7 characters, e.g.#3B82F6)custom_fields(object, key-value pairs)
Invite User Fields
Section titled “Invite User Fields”name(string) - Full name of the useremail(string, valid email) - Must be unique across all users
Permissions
Section titled “Permissions”Error Responses
Section titled “Error Responses”Client Not Found
Section titled “Client Not Found”{ "success": false, "message": "Client not found."}Validation Error
Section titled “Validation Error”{ "success": false, "message": "The given data was invalid.", "errors": { "company_name": ["The company name field is required."], "website": ["The website field must be a valid URL."] }}Active Projects Constraint
Section titled “Active Projects Constraint”{ "success": false, "message": "Cannot delete client with active projects. Please archive or reassign all projects first."}User Does Not Belong to Client
Section titled “User Does Not Belong to Client”{ "success": false, "message": "This user does not belong to this client."}Duplicate Email on Invite
Section titled “Duplicate Email on Invite”{ "success": false, "message": "The given data was invalid.", "errors": { "email": ["The email has already been taken."] }}