API Documentation

Integrate your systems with powerful REST APIs. Access jobs, candidates, companies, and bookings programmatically.

API Request
GET /api/v1/jobs
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

// Response
{
  "data": [...],
  "pagination": {
    "total": 150
  }
}

Quick Start Guide

Get up and running with the API in three simple steps

1. Generate API Key

Create an API key from your Wizard application settings page. Keep it secure and never share it publicly.

Step 1

3. Build & Integrate

Start building integrations with your existing systems using our comprehensive endpoints.

Step 3
Base URL
https://your-workspace.wizardapp.io/api/v1

SDKs

Official client libraries that call the API for you, in seven languages

One download includes an SDK for each language below. Every SDK covers all the endpoints on this page, uses only its language's standard library and comes with a README and a quick start example.

Python Python 3.8+
JavaScript and TypeScript Node.js 18+
PHP PHP 8.0+
Ruby Ruby 3.0+
Go Go 1.18+
C# and .NET .NET 6+
Java Java 11+

Version 1.0.0. One zip file with a folder for each language, the licence and the changelog. The same files are in our public GitHub repository.

Install

Language
Folder
Add it to your project
Python
python/
pip install "git+https://github.com/wssltd/api-sdk.git@v1.0.0#subdirectory=python"
JavaScript and TypeScript
javascript/
npm install ./javascript
PHP
php/
Composer path repository, or require 'php/autoload.php';
Ruby
ruby/
gem "wizardapplication", git: "https://github.com/wssltd/api-sdk.git", tag: "v1.0.0", glob: "ruby/*.gemspec"
Go
go/
go get github.com/wssltd/api-sdk/go@v1.0.0
C# and .NET
dotnet/
dotnet add reference or dotnet pack
Java
java/
mvn install, then add the dependency

Quick Start

Each example lists your published jobs across every page. The workspace is the first part of your Wizard Application address, so acme for acme.wizardapp.io.

from wizardapplication import WizardApplication

client = WizardApplication(api_key="YOUR_API_KEY", workspace="acme")

for job in client.jobs.iterate(status="published"):
    print(job["title"])
import WizardApplication from 'wizardapplication';

const client = new WizardApplication({ apiKey: 'YOUR_API_KEY', workspace: 'acme' });

for await (const job of client.jobs.iterate({ status: 'published' })) {
  console.log(job.title);
}
$client = new \WizardApplication\Client(['api_key' => 'YOUR_API_KEY', 'workspace' => 'acme']);

foreach ($client->jobs->iterate(['status' => 'published']) as $job) {
    echo $job['title'], PHP_EOL;
}
require "wizardapplication"

client = WizardApplication::Client.new(api_key: "YOUR_API_KEY", workspace: "acme")

client.jobs.iterate(status: "published") { |job| puts job["title"] }
client, err := wa.New("YOUR_API_KEY", wa.WithWorkspace("acme"))
if err != nil {
	log.Fatal(err)
}

err = client.Jobs.Iterate(ctx, wa.Params{"status": "published"}, func(job wa.Record) error {
	fmt.Println(job["title"])
	return nil
})
using var client = new WizardApplicationClient("YOUR_API_KEY", "acme");

await foreach (var job in client.Jobs.IterateAsync(new ListOptions().Where("status", "published")))
{
    Console.WriteLine((string?)job["title"]);
}
WizardApplication client = WizardApplication.builder()
        .apiKey("YOUR_API_KEY")
        .workspace("acme")
        .build();

for (Map<String, Object> job : client.jobs().iterate(Map.of("status", "published"))) {
    System.out.println(job.get("title"));
}

What the SDKs Handle for You

Authentication
Sends your API key as a Bearer token on every request. The key can come from the WIZARDAPP_API_KEY environment variable and the workspace from WIZARDAPP_WORKSPACE.
Pagination
list returns one page with its totals. iterate goes through every page for you.
Errors
A separate error type for each status in Error Handling, with the error code and, for a 422, the problem with each field.
Rate limits
Waits and retries after a per-minute 429, and exposes the rate limit headers from the latest response.
Retries
Retries network errors and 502, 503 and 504 on reads, updates and deletes, so a create is never sent twice.
Security
Sends your key over https only, never follows a redirect, and checks workspace names and IDs before using them in a URL.
Server-side only

Use the SDKs in server-side code. Never put an API key in a web page or a mobile app. The SDKs are licensed under the Wizard Application SDK Licence included in the download, and your use of the API through them is covered by our Terms and Conditions.

Authentication

All API requests require authentication using an API key

Request Headers

Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

Example Request

curl -X GET "https://your-workspace.wizardapp.io/api/v1/jobs" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json"
Security Notice

Never share your API keys or commit them to version control. Store them securely as environment variables.

Error Handling

The API uses standard HTTP status codes and returns error details in JSON format

HTTP Status Codes

Code
Description
200
OK - Request succeeded
201
Created - Resource created successfully
204
No Content - Resource deleted successfully
400
Bad Request - Invalid request format
401
Unauthorized - Invalid or missing API key
402
Payment Required - Add a payment method to the workspace first (adding users)
403
Forbidden - Insufficient permissions
404
Not Found - Resource not found
409
Conflict - The resource already exists (for example a user with that email)
422
Unprocessable Entity - Validation errors
429
Too Many Requests - Rate limit exceeded
500
Internal Server Error - Server error

Error Response Format

{
  "error": "validation_error",
  "message": "Validation failed",
  "errors": {
    "title": ["Title is required"],
    "email": ["Email format is invalid"]
  }
}

Pagination

List endpoints support pagination using query parameters

Query Parameters

Parameter
Default
Description
page
1
Page number
per_page
20
Items per page (max 100)

Response Format

{
  "data": [...],
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total": 150,
    "total_pages": 8
  }
}

Sorting

List endpoints support sorting using query parameters

Query Parameters

Parameter
Default
Description
sort
created_at
Field to sort by (varies by endpoint)
order
desc
Sort direction: asc or desc

Example Request

GET /api/v1/jobs?sort=title&order=asc&page=1&per_page=20

Available Sort Fields by Endpoint

Endpoint
Sortable Fields
/jobs
created_at, updated_at, title, location, status, employment_type, salary_min, salary_max, published_at
/candidates
created_at, updated_at, first_name, last_name, email, status, employment_type, current_job_title, current_company, available_from
/companies
created_at, updated_at, name, industry, status
/bookings
created_at, updated_at, start_datetime, end_datetime, title, status, booking_type
/leads
created_at, updated_at, first_name, last_name, email, company_name, status, source, last_contacted_at
/users
created_at, updated_at, first_name, last_name, email
/content/{type}
created_at, updated_at, title, slug, status, published_at

Rate Limiting

API requests are rate limited based on your subscription plan

Rate Limit Headers

All API responses include headers to help you track your usage:

Header
Description
X-RateLimit-Limit
Maximum requests allowed per minute
X-RateLimit-Remaining
Remaining requests in current window
X-RateLimit-Reset
Unix timestamp when the rate limit resets

Plan Limits

Rate limits vary by subscription plan:

Limit Type
Description
Per Minute
Maximum API requests allowed per minute
Per Month
Total API requests allowed per billing cycle
Rate Limit Exceeded

When you exceed your rate limit, the API returns a 429 Too Many Requests response. Wait until the reset time indicated in the headers before making additional requests.

API Endpoints

Available resources and their operations

Jobs

Manage job postings, vacancies, and recruitment positions

GET /api/v1/jobs List all jobs with pagination and filtering jobs.read
Query Parameters
{
  "page": 1,
  "per_page": 20,
  "status": "published",
  "employment_type": "permanent",
  "search": "developer"
}
Response
{
  "data": [
    {
      "id": "uuid",
      "title": "string",
      "reference_code": "string",
      "location": "string",
      "employment_type": "permanent|contractor|interim|contract_to_perm|freelance|temporary",
      "status": "draft|published|closed|filled|on_hold|cancelled",
      "salary_min": 50000,
      "salary_max": 70000,
      "created_at": "2024-01-01T00:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total": 150,
    "total_pages": 8
  }
}
GET /api/v1/jobs/{id} Retrieve a single job by ID jobs.read
Response
{
  "data": {
    "id": "uuid",
    "title": "string",
    "reference_code": "string",
    "slug": "string",
    "department": "string",
    "location": "string",
    "remote_type": "on_site|remote|hybrid",
    "employment_type": "permanent|contractor|interim|contract_to_perm|freelance|temporary",
    "experience_level": "entry|mid|senior|lead|executive",
    "salary_min": 50000,
    "salary_max": 70000,
    "salary_currency": "GBP",
    "salary_type": "annual",
    "show_salary": true,
    "day_rate_min": 400,
    "day_rate_max": 500,
    "rate_currency": "GBP",
    "fee_type": "percentage|fixed",
    "fee_percentage": 15,
    "placement_fee": 10000,
    "description": "string",
    "requirements": "string",
    "responsibilities": "string",
    "benefits": "string",
    "positions_available": 1,
    "application_deadline": "2024-12-31",
    "start_date": "2024-02-01",
    "required_skills": "string",
    "preferred_skills": "string",
    "qualifications": "string",
    "status": "draft|published|closed|filled|on_hold|cancelled",
    "published_at": "2024-01-01T00:00:00Z",
    "allow_applications": true,
    "enable_public_page": true,
    "company_id": "uuid",
    "assigned_to": "uuid",
    "created_at": "2024-01-01T00:00:00Z",
    "updated_at": "2024-01-01T00:00:00Z"
  }
}
POST /api/v1/jobs Create a new job posting jobs.write
Request Body
{
  "title": "string (required)",
  "location": "string (required)",
  "employment_type": "permanent|contractor|interim (required)",
  "description": "string (required)",
  "company_id": "uuid",
  "department": "string",
  "remote_type": "on_site|remote|hybrid",
  "experience_level": "entry|mid|senior|lead|executive",
  "salary_min": 50000,
  "salary_max": 70000,
  "salary_currency": "GBP",
  "salary_type": "annual|monthly|hourly",
  "show_salary": true,
  "day_rate_min": 400,
  "day_rate_max": 500,
  "rate_currency": "GBP",
  "fee_type": "percentage|fixed",
  "fee_percentage": 15,
  "placement_fee": 10000,
  "requirements": "string",
  "responsibilities": "string",
  "benefits": "string",
  "positions_available": 1,
  "application_deadline": "2024-12-31",
  "start_date": "2024-02-01",
  "required_skills": "string",
  "preferred_skills": "string",
  "qualifications": "string",
  "status": "draft|published",
  "allow_applications": true,
  "application_email": "string",
  "application_url": "string",
  "enable_public_page": true,
  "enable_ai_matching": true,
  "meta_title": "string",
  "meta_description": "string",
  "featured": false,
  "internal_notes": "string",
  "assigned_to": "uuid"
}
Response (201 Created)
{
  "data": { ... },
  "message": "Job created successfully"
}
PUT /api/v1/jobs/{id} Update an existing job jobs.write
Request Body
{
  "title": "string",
  "location": "string",
  "employment_type": "permanent|contractor|interim",
  "description": "string",
  "status": "draft|published|closed|filled|on_hold|cancelled",
  ... // All fields from POST are accepted
}
Response
{
  "data": { ... },
  "message": "Job updated successfully"
}
DELETE /api/v1/jobs/{id} Delete a job posting jobs.write
Response
{
  "message": "Job deleted successfully"
}

Candidates

Manage candidate profiles, CVs, and applicant data

GET /api/v1/candidates List all candidates with pagination and search candidates.read
Query Parameters
{
  "page": 1,
  "per_page": 20,
  "status": "new_lead",
  "search": "john"
}
Response
{
  "data": [
    {
      "id": "uuid",
      "first_name": "string",
      "last_name": "string",
      "email": "string",
      "phone": "string",
      "employment_type": "permanent|contractor|interim",
      "status": "new_lead|screening|submitted|interviewing|offer_made|placed|rejected",
      "current_job_title": "string",
      "current_company": "string",
      "created_at": "2024-01-01T00:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total": 500,
    "total_pages": 25
  }
}
GET /api/v1/candidates/{id} Retrieve a single candidate by ID candidates.read
Response
{
  "data": {
    "id": "uuid",
    "first_name": "string",
    "last_name": "string",
    "email": "string",
    "phone": "string",
    "mobile": "string",
    "address_line1": "string",
    "address_line2": "string",
    "city": "string",
    "state_province": "string",
    "postal_code": "string",
    "country": "string",
    "linkedin_url": "string",
    "portfolio_url": "string",
    "github_url": "string",
    "date_of_birth": "1990-01-01",
    "nationality": "string",
    "employment_type": "permanent|contractor|interim|contract_to_perm|freelance|temporary",
    "employment_status": "actively_looking|open_to_offers|passive|not_looking|placed|blacklisted",
    "current_salary": 50000,
    "expected_salary": 60000,
    "salary_currency": "GBP",
    "current_day_rate": 400,
    "expected_day_rate": 450,
    "rate_currency": "GBP",
    "notice_period_days": 30,
    "available_from": "2024-02-01",
    "current_job_title": "string",
    "current_company": "string",
    "years_of_experience": 5,
    "industry": "string",
    "skills": "string",
    "qualifications": "string",
    "cv_file_path": "string",
    "status": "new_lead|screening|submitted|interviewing|offer_made|offer_accepted|placed|rejected|on_hold|withdrawn",
    "source": "string",
    "rating": 5,
    "preferred_locations": "string",
    "willing_to_relocate": true,
    "right_to_work": "string",
    "security_clearance": "string",
    "languages": "string",
    "ir35_status": "inside|outside|unknown|not_applicable",
    "umbrella_company": "string",
    "limited_company_name": "string",
    "notes": "string",
    "internal_notes": "string",
    "assigned_to": "uuid",
    "created_at": "2024-01-01T00:00:00Z",
    "updated_at": "2024-01-01T00:00:00Z"
  }
}
POST /api/v1/candidates Create a new candidate record candidates.write
Request Body
{
  "first_name": "string (required)",
  "last_name": "string (required)",
  "email": "string (required)",
  "employment_type": "permanent|contractor|interim (required)",
  "phone": "string",
  "mobile": "string",
  "address_line1": "string",
  "address_line2": "string",
  "city": "string",
  "state_province": "string",
  "postal_code": "string",
  "country": "string",
  "linkedin_url": "string",
  "portfolio_url": "string",
  "github_url": "string",
  "date_of_birth": "1990-01-01",
  "nationality": "string",
  "employment_status": "actively_looking|open_to_offers|passive|not_looking",
  "current_salary": 50000,
  "expected_salary": 60000,
  "salary_currency": "GBP",
  "current_day_rate": 400,
  "expected_day_rate": 450,
  "rate_currency": "GBP",
  "notice_period_days": 30,
  "available_from": "2024-02-01",
  "current_job_title": "string",
  "current_company": "string",
  "years_of_experience": 5,
  "industry": "string",
  "skills": "string",
  "qualifications": "string",
  "source": "string",
  "rating": 5,
  "preferred_locations": "string",
  "willing_to_relocate": true,
  "right_to_work": "string",
  "security_clearance": "string",
  "languages": "string",
  "ir35_status": "inside|outside|unknown|not_applicable",
  "umbrella_company": "string",
  "limited_company_name": "string",
  "notes": "string",
  "internal_notes": "string",
  "assigned_to": "uuid"
}
Response (201 Created)
{
  "data": { ... },
  "message": "Candidate created successfully"
}
PUT /api/v1/candidates/{id} Update candidate information candidates.write
Request Body
{
  "first_name": "string",
  "last_name": "string",
  "email": "string",
  "employment_type": "permanent|contractor|interim",
  "status": "new_lead|screening|submitted|interviewing|offer_made|placed|rejected",
  ... // All fields from POST are accepted
}
Response
{
  "data": { ... },
  "message": "Candidate updated successfully"
}
DELETE /api/v1/candidates/{id} Delete a candidate record candidates.write
Response
{
  "message": "Candidate deleted successfully"
}

Companies

Manage client companies, contacts, and business relationships

GET /api/v1/companies List all companies with pagination companies.read
Query Parameters
{
  "page": 1,
  "per_page": 20,
  "status": "active",
  "search": "acme"
}
Response
{
  "data": [
    {
      "id": "uuid",
      "name": "string",
      "email": "string",
      "phone": "string",
      "industry": "string",
      "status": "prospect|active|inactive|on_hold|archived",
      "jobs_count": 5,
      "created_at": "2024-01-01T00:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total": 100,
    "total_pages": 5
  }
}
GET /api/v1/companies/{id} Retrieve a single company by ID companies.read
Response
{
  "data": {
    "id": "uuid",
    "name": "string",
    "legal_name": "string",
    "trading_name": "string",
    "company_number": "string",
    "email": "string",
    "phone": "string",
    "website": "string",
    "industry": "string",
    "company_size": "1-10|11-50|51-200|201-500|501-1000|1000+",
    "founded_year": 2010,
    "description": "string",
    "primary_contact_name": "string",
    "primary_contact_email": "string",
    "primary_contact_phone": "string",
    "primary_contact_title": "string",
    "status": "prospect|active|inactive|on_hold|archived",
    "billing_email": "string",
    "payment_terms": "string",
    "contract_start_date": "2024-01-01",
    "contract_end_date": "2025-01-01",
    "fee_percentage": 15,
    "fee_type": "percentage|fixed|retainer",
    "linkedin_url": "string",
    "twitter_url": "string",
    "internal_notes": "string",
    "tags": "string",
    "jobs_count": 5,
    "active_jobs_count": 2,
    "placements_count": 10,
    "account_manager_id": "uuid",
    "created_at": "2024-01-01T00:00:00Z",
    "updated_at": "2024-01-01T00:00:00Z"
  }
}
POST /api/v1/companies Create a new company record companies.write
Request Body
{
  "name": "string (required)",
  "email": "string (required)",
  "legal_name": "string",
  "trading_name": "string",
  "company_number": "string",
  "phone": "string",
  "website": "string",
  "industry": "string",
  "company_size": "1-10|11-50|51-200|201-500|501-1000|1000+",
  "founded_year": 2010,
  "description": "string",
  "primary_contact_name": "string",
  "primary_contact_email": "string",
  "primary_contact_phone": "string",
  "primary_contact_title": "string",
  "status": "prospect|active",
  "billing_email": "string",
  "payment_terms": "string",
  "contract_start_date": "2024-01-01",
  "contract_end_date": "2025-01-01",
  "fee_percentage": 15,
  "fee_type": "percentage|fixed|retainer",
  "linkedin_url": "string",
  "twitter_url": "string",
  "internal_notes": "string",
  "tags": "string",
  "account_manager_id": "uuid"
}
Response (201 Created)
{
  "data": { ... },
  "message": "Company created successfully"
}
PUT /api/v1/companies/{id} Update company information companies.write
Request Body
{
  "name": "string",
  "email": "string",
  "status": "prospect|active|inactive|on_hold|archived",
  ... // All fields from POST are accepted
}
Response
{
  "data": { ... },
  "message": "Company updated successfully"
}
DELETE /api/v1/companies/{id} Delete a company record companies.write
Response
{
  "message": "Company deleted successfully"
}

Bookings

Manage interviews, placements, and scheduled events

GET /api/v1/bookings List all bookings with date filtering bookings.read
Query Parameters
{
  "page": 1,
  "per_page": 20,
  "status": "scheduled",
  "booking_type": "interview",
  "start_date": "2024-01-01",
  "end_date": "2024-12-31",
  "search": "string"
}
Response
{
  "data": [
    {
      "id": "uuid",
      "booking_type": "interview|contract|permanent|internal|consultation|site_visit",
      "title": "string",
      "start_datetime": "2024-01-15T10:00:00Z",
      "end_datetime": "2024-01-15T11:00:00Z",
      "status": "draft|scheduled|confirmed|in_progress|completed|cancelled|rescheduled",
      "candidate_id": "uuid",
      "job_id": "uuid",
      "company_id": "uuid",
      "created_at": "2024-01-01T00:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total": 50,
    "total_pages": 3
  }
}
GET /api/v1/bookings/{id} Retrieve a single booking by ID bookings.read
Response
{
  "data": {
    "id": "uuid",
    "booking_type": "interview|contract|permanent|internal|consultation|site_visit",
    "title": "string",
    "description": "string",
    "candidate_id": "uuid",
    "job_id": "uuid",
    "company_id": "uuid",
    "lead_id": "uuid",
    "start_datetime": "2024-01-15T10:00:00Z",
    "end_datetime": "2024-01-15T11:00:00Z",
    "all_day": false,
    "interview_type": "phone|video|in_person",
    "interview_location": "string",
    "interview_panel": "string",
    "meeting_link": "string",
    "meeting_platform": "zoom|teams|google_meet",
    "meeting_id": "string",
    "meeting_password": "string",
    "meeting_join_url": "string",
    "contract_type": "fixed_term|temporary|ongoing|project_based",
    "day_rate": 500,
    "contract_value": 50000,
    "payment_terms": "string",
    "ir35_status": "inside|outside|not_applicable",
    "contract_notes": "string",
    "offer_accepted_date": "2024-01-10",
    "annual_salary": 60000,
    "placement_fee": 10000,
    "notice_period_days": 30,
    "probation_period_months": 3,
    "status": "draft|scheduled|confirmed|in_progress|completed|cancelled|rescheduled",
    "contact_name": "string",
    "contact_email": "string",
    "contact_phone": "string",
    "location": "string",
    "requirements": "string",
    "internal_notes": "string",
    "assigned_to": "uuid",
    "timezone": "Europe/London",
    "cancellation_reason": "string",
    "created_at": "2024-01-01T00:00:00Z",
    "updated_at": "2024-01-01T00:00:00Z"
  }
}
POST /api/v1/bookings Create a new booking bookings.write
Request Body
{
  "booking_type": "interview|contract|permanent|internal|consultation|site_visit (required)",
  "title": "string",
  "description": "string",
  "candidate_id": "uuid (required for interview/contract/permanent)",
  "job_id": "uuid (required for interview/contract/permanent)",
  "company_id": "uuid (required for interview/contract/permanent)",
  "lead_id": "uuid (for consultation bookings)",
  "start_datetime": "2024-01-15T10:00:00Z (required)",
  "end_datetime": "2024-01-15T11:00:00Z (required for interview/contract)",
  "all_day": false,
  "interview_type": "phone|video|in_person",
  "interview_location": "string",
  "interview_panel": "string",
  "meeting_link": "string",
  "meeting_platform": "zoom|teams|google_meet",
  "contract_type": "fixed_term|temporary|ongoing|project_based",
  "day_rate": 500,
  "contract_value": 50000,
  "payment_terms": "string",
  "ir35_status": "inside|outside|not_applicable",
  "contract_notes": "string",
  "annual_salary": 60000,
  "placement_fee": 10000,
  "notice_period_days": 30,
  "probation_period_months": 3,
  "status": "draft|scheduled|confirmed",
  "contact_name": "string",
  "contact_email": "string",
  "contact_phone": "string",
  "location": "string",
  "requirements": "string",
  "internal_notes": "string",
  "assigned_to": "uuid",
  "timezone": "Europe/London"
}
Response (201 Created)
{
  "data": { ... },
  "message": "Booking created successfully"
}
PUT /api/v1/bookings/{id} Update booking details bookings.write
Request Body
{
  "title": "string",
  "description": "string",
  "start_datetime": "2024-01-15T10:00:00Z",
  "end_datetime": "2024-01-15T11:00:00Z",
  "status": "draft|scheduled|confirmed|in_progress|completed|cancelled|rescheduled",
  "cancellation_reason": "string (when cancelling)",
  ... // All fields from POST are accepted
}
Response
{
  "data": { ... },
  "message": "Booking updated successfully"
}
DELETE /api/v1/bookings/{id} Delete a booking bookings.write
Response
{
  "message": "Booking deleted successfully"
}

Leads

Manage leads and prospects in your sales pipeline

GET /api/v1/leads List all leads with filtering options leads.read
Query Parameters
{
  "page": 1,
  "per_page": 20,
  "status": "lead|prospect",
  "source": "website",
  "assigned_to": "uuid",
  "search": "john"
}
Response
{
  "data": [
    {
      "id": "uuid",
      "first_name": "string",
      "last_name": "string",
      "email": "string",
      "phone": "string",
      "company_name": "string",
      "status": "lead|prospect",
      "source": "string",
      "created_at": "2024-01-01T00:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total": 200,
    "total_pages": 10
  }
}
GET /api/v1/leads/{id} Retrieve a single lead by ID leads.read
Response
{
  "data": {
    "id": "uuid",
    "first_name": "string",
    "last_name": "string",
    "email": "string",
    "phone": "string",
    "mobile": "string",
    "company_name": "string",
    "customer_type": "individual|business",
    "status": "lead|prospect",
    "address": "string",
    "city": "string",
    "county": "string",
    "postcode": "string",
    "country": "string",
    "website": "string",
    "linkedin_url": "string",
    "billing_address": "string",
    "billing_city": "string",
    "billing_county": "string",
    "billing_postcode": "string",
    "billing_country": "string",
    "industry": "string",
    "job_title": "string",
    "notes": "string",
    "source": "string",
    "tags": "string",
    "assigned_to": "uuid",
    "lead_status_id": "uuid",
    "last_contacted_at": "2024-01-01T00:00:00Z",
    "created_at": "2024-01-01T00:00:00Z",
    "updated_at": "2024-01-01T00:00:00Z"
  }
}
POST /api/v1/leads Create a new lead leads.write
Request Body
{
  "email": "string (required)",
  "lead_status_id": "uuid (required)",
  "first_name": "string",
  "last_name": "string",
  "company_name": "string (at least one name field required)",
  "phone": "string",
  "mobile": "string",
  "customer_type": "individual|business",
  "status": "lead|prospect",
  "address": "string",
  "city": "string",
  "county": "string",
  "postcode": "string",
  "country": "string",
  "website": "string",
  "linkedin_url": "string",
  "billing_address": "string",
  "billing_city": "string",
  "billing_county": "string",
  "billing_postcode": "string",
  "billing_country": "string",
  "industry": "string",
  "job_title": "string",
  "notes": "string",
  "source": "string",
  "tags": "string",
  "assigned_to": "uuid"
}
Response (201 Created)
{
  "data": { ... },
  "message": "Lead created successfully"
}
PUT /api/v1/leads/{id} Update lead details leads.write
Request Body
{
  "first_name": "string",
  "last_name": "string",
  "email": "string",
  "status": "lead|prospect",
  "lead_status_id": "uuid",
  ... // All fields from POST are accepted
}
Response
{
  "data": { ... },
  "message": "Lead updated successfully"
}
DELETE /api/v1/leads/{id} Delete a lead leads.write
Response
{
  "message": "Lead deleted successfully"
}
POST /api/v1/leads/{id}/convert Convert a lead to an active customer leads.write
Request Body
{
  // No body required
}
Response
{
  "data": {
    "id": "uuid",
    "status": "active",
    "converted_at": "2024-01-15T10:00:00Z",
    ...
  },
  "message": "Lead converted to customer successfully"
}

Users

List your team and add or import team members. Each user you add is a paid seat, so a key that adds users needs the per-seat charge accepted when you create it: tick Users - Create and update and the charge box under Settings, API Keys. Users can't be deleted through the API.

Passwords and invitations

The API never sets or returns passwords. Every user you add, one at a time or in an import, gets their own invitation email with a link to choose a password, which must meet your workspace's password rules. Until they accept, the user shows as invited and can't sign in; once they accept they become active.

Invitation emails are sent straight away, one per user. To add users without emailing them yet (for example to import your team before launch day), set "send_invitation": false and send the invitations later with POST /api/v1/users/{id}/invitation. That endpoint also resends an invitation someone has lost; the link stays the same, so an earlier email still works.

GET /api/v1/users List team members with filtering options users.read
Query Parameters
{
  "page": 1,
  "per_page": 20,
  "search": "sam",
  "email": "sam@example.com",
  "status": "active|invited"
}
Response
{
  "data": [
    {
      "id": "uuid",
      "email": "string",
      "first_name": "string",
      "last_name": "string",
      "job_title": "string",
      "phone": "string",
      "role_id": "uuid",
      "role": "string",
      "department_id": "uuid",
      "department": "string",
      "manager_id": "uuid",
      "is_admin": false,
      "status": "active|invited|inactive",
      "last_login_at": "2024-01-01T00:00:00Z",
      "created_at": "2024-01-01T00:00:00Z",
      "updated_at": "2024-01-01T00:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total": 42,
    "total_pages": 3
  }
}
GET /api/v1/users/{id} Retrieve a single user by ID users.read
Response
{
  "data": {
    "id": "uuid",
    "email": "string",
    "first_name": "string",
    "last_name": "string",
    "role": "string",
    "department": "string",
    "manager_id": "uuid",
    "status": "active|invited|inactive",
    ... // Same fields as the list
  }
}
POST /api/v1/users Add a team member and send their invitation users.write
Request Body
{
  "email": "string (required)",
  "first_name": "string (required)",
  "last_name": "string (required)",
  "job_title": "string",
  "phone": "string",
  "phone_dial_code": "44",
  "role": "string (role name) or role_id: uuid",
  "department": "string (department name) or department_id: uuid",
  "manager_email": "string or manager_id: uuid",
  "send_invitation": true
}

A manager is required unless the role is Administrator, and a department is required when departments are switched on. The user is emailed an invitation to choose their password; set send_invitation to false to send it later with POST /api/v1/users/{id}/invitation. The workspace's plan limit and allowed email domains apply.

Response (201 Created)
{
  "data": { ... }
}
Errors
// 403: the key can't add users
{ "error": "seat_charges_not_accepted", "message": "..." }

// 403: the plan's team member limit is reached
{ "error": "plan_limit_reached", "message": "..." }

// 409: a user with this email already exists
{ "error": "already_exists", "message": "..." }

// 422: validation
{
  "error": "validation_failed",
  "message": "Validation failed",
  "fields": { "manager_id": ["Manager is required"] }
}
POST /api/v1/users/import Import up to 100 team members in one request users.write
Request Body
{
  "users": [
    {
      "email": "alex@example.com",
      "first_name": "Alex",
      "last_name": "Morgan",
      "role": "Administrator"
    },
    {
      "email": "sam@example.com",
      "first_name": "Sam",
      "last_name": "Lee",
      "role": "Team Member",
      "department": "Operations",
      "manager_email": "alex@example.com"
    }
  ]
}

Each user takes the same fields as creating one. Users are added in order, so manager_email can name someone earlier in the same import. Each user succeeds or fails on its own, and an email that already exists is skipped, so an import can safely be run again.

Response
{
  "data": [
    { "index": 0, "email": "alex@example.com", "status": "created", "user": { ... } },
    { "index": 1, "email": "sam@example.com", "status": "skipped",
      "error": { "error": "already_exists", "message": "..." } }
  ],
  "summary": { "created": 1, "skipped": 1, "failed": 0 }
}
PUT /api/v1/users/{id} Update a user's details users.write
Request Body
{
  "first_name": "string",
  "last_name": "string",
  "job_title": "string",
  "phone": "string",
  "role": "string or role_id: uuid",
  "department": "string or department_id: uuid",
  "manager_email": "string or manager_id: uuid"
}

Only the fields you send are changed. A user's email address can only be changed in Wizard Application.

Response
{
  "data": { ... }
}
POST /api/v1/users/{id}/invitation Send or resend a user's invitation email users.write
Request Body
{
  // No body required
}

For a user who hasn't accepted their invitation yet. Use it after creating or importing users with "send_invitation": false, or when someone has lost the email.

Response
{
  "data": { ... },
  "message": "Invitation sent"
}

// 409: the user has already accepted
{ "error": "already_accepted", "message": "..." }

Content

Access your content management system - content types and content items

GET /api/v1/content-types List all content types content.read
Query Parameters
{
  "page": 1,
  "per_page": 20
}
Response
{
  "data": [
    {
      "id": "uuid",
      "name": "string",
      "slug": "string",
      "description": "string",
      "icon": "string",
      "is_system": false,
      "is_active": true,
      "created_at": "2024-01-01T00:00:00Z",
      "updated_at": "2024-01-01T00:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total": 10,
    "total_pages": 1
  }
}
GET /api/v1/content-types/{id} Retrieve a content type with its fields content.read
Response
{
  "data": {
    "id": "uuid",
    "name": "string",
    "slug": "string",
    "description": "string",
    "icon": "string",
    "is_system": false,
    "is_active": true,
    "fields": [
      {
        "id": "uuid",
        "name": "string",
        "field_key": "string",
        "field_type": "text|textarea|rich_text|number|select|multi_select|date|datetime|boolean|image|file|url|email|phone",
        "is_required": true,
        "is_title_field": false,
        "placeholder": "string",
        "help_text": "string",
        "config": "{}",
        "display_order": 1
      }
    ],
    "created_at": "2024-01-01T00:00:00Z",
    "updated_at": "2024-01-01T00:00:00Z"
  }
}
GET /api/v1/content/{type} List items of a content type (by slug or ID) content.read
Query Parameters
{
  "page": 1,
  "per_page": 20,
  "status": "published|draft",
  "search": "string"
}
Response
{
  "data": [
    {
      "id": "uuid",
      "title": "string",
      "slug": "string",
      "status": "draft|published",
      "published_at": "2024-01-01T00:00:00Z",
      "created_at": "2024-01-01T00:00:00Z",
      "updated_at": "2024-01-01T00:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total": 50,
    "total_pages": 3
  }
}
GET /api/v1/content/{type}/{id} Retrieve a single content item with field values content.read
Response
{
  "data": {
    "id": "uuid",
    "title": "string",
    "slug": "string",
    "status": "draft|published",
    "fields": {
      "field_key_1": "value",
      "field_key_2": "value",
      "field_key_3": ["multi", "select", "values"]
    },
    "published_at": "2024-01-01T00:00:00Z",
    "created_at": "2024-01-01T00:00:00Z",
    "updated_at": "2024-01-01T00:00:00Z"
  }
}
POST /api/v1/content/{type} Create a new content item content.write
Request Body
{
  "title": "string (required)",
  "slug": "string",
  "status": "draft|published",
  "fields": {
    "field_key_1": "value",
    "field_key_2": "value",
    "field_key_3": ["multi", "select", "values"]
  }
}
Response (201 Created)
{
  "data": {
    "id": "uuid",
    "title": "string",
    "slug": "string",
    "status": "draft",
    "created_at": "2024-01-01T00:00:00Z"
  },
  "message": "Content item created successfully"
}
PUT /api/v1/content/{type}/{id} Update a content item content.write
Request Body
{
  "title": "string",
  "slug": "string",
  "status": "draft|published",
  "fields": {
    "field_key_1": "new value",
    "field_key_2": "new value"
  }
}
Response
{
  "data": {
    "id": "uuid",
    "title": "string",
    "slug": "string",
    "status": "published",
    "updated_at": "2024-01-01T00:00:00Z"
  },
  "message": "Content item updated successfully"
}
DELETE /api/v1/content/{type}/{id} Delete a content item content.write
Response
{
  "message": "Content item deleted successfully"
}

Precisa de ajuda com a integração?

O suporte a integrações está disponível diretamente dentro do Wizard Application. Inicie sessão e envie um pedido de suporte a partir do menu da conta para obter assistência técnica, endpoints personalizados ou funcionalidades enterprise.

FAQ

Perguntas frequentes

Perguntas comuns sobre a nossa API e integrações.

Pode gerar uma chave API a partir da página de definições da sua aplicação Wizard Application. Navegue até Definições > Chaves API e clique em 'Gerar nova chave'. Mantenha a sua chave API segura e nunca a partilhe publicamente.

Os limites de taxa variam consoante o plano e podem mudar ao longo do tempo. Os cabeçalhos de limite de taxa estão incluídos em todas as respostas da API.

Ver os limites de taxa atuais na nossa página de Planos