NAV
shell javascript typescript php

Instapage API

Current state of the API: BETA TESTING

What is the Instapage API?

The Instapage API allows developers to interact with the Instapage platform programmatically. By utilizing our API, you can create, update, retrieve, and delete various resources within Instapage, such as landing pages, leads, forms, and more. The API is designed to be RESTful, making it straightforward to integrate with any application or service.

Getting Started

To start using the Instapage API, you'll need to:

  1. Obtain API Credentials: Generate your API key from the Instapage dashboard.
  2. Understand API Endpoints: Familiarize yourself with the available endpoints and their functions.
  3. Make Your First Request: Learn how to authenticate and make basic API requests.

Throughout this documentation, you'll find detailed explanations, code examples, and best practices to help you effectively utilize the Instapage API.

Limitations

API usage limitations are determined by the plan associated with the specific workspace. The token used for requests inherits the permissions of the owner (token creator) who generated it.

Rate Limit: The API allows up to 200 requests per minute. Exceeding this limit will result in a 429 Too Many Requests response status.

Dictionary

Page

In Instapage, a page is a landing page made within the platform [Creating a new page][How do I publish my page to my own domain]. The page is a standalone webpage for a specific marketing campaign that aims to convert visitors into leads or customers[Lead management].

Workspace

In Instapage, a workspace is a designated area for managing landing pages for a company or project. Multiple workspaces can be created, and each workspace keeps its pages, integrations, domains, and other assets separate from other workspaces[Workspace settings and account settings].

Scheduling

Scheduling allows users to set specific dates and times to publish and unpublish landing pages. Scheduling is available for Custom Domain (CNAME) and Demo Page publishing and offers flexibility for campaign management[Scheduling].

Personalization

Personalization involves creating customized experiences for different audience segments on landing pages. This feature allows users to tailor content and design to resonate with specific visitor groups, enhancing engagement and conversion rates[Personalization creating personalized experiences for different audiences].

Leads

A lead is information submitted by a visitor through a form on a landing page. Lead generation is a crucial aspect of digital marketing, and landing pages are often a primary tool for capturing leads. If a form collects a visitor's name, email, city, and zip code, that constitutes a lead[Lead management].

Changelog

2025-03-11

Added

Groups

We introduced a new Groups API to help users manage page groups (folders) within a workspace.

2025-02-27

Added

Team Members

We enhanced the Team Members API to allow better workspace management by enabling bulk invitations, role updates, and removals.

Authorization

To authorize, use this code:

# With shell, you can just pass the correct header with each request
curl "api_endpoint_here" \
  -H "Authorization: Bearer API_KEY"
  await fetch(url, {
    method: 'GET',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
    },
  });
  await fetch(url, {
    method: 'GET',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
    },
  });
        $ch = curl_init($url);

        curl_setopt_array($ch, [
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json',
                'Authorization: Bearer ' . $apiKey
            ],
        ]);

Make sure to replace API_KEY with your API key.

Instapage expects for the API key to be included in all API requests to the server in a header.

Workspaces

Get All Workspaces

Retrieve all workspaces that the provided token has access to.

HTTP Request

GET https://api.instapage.com/v1/workspaces

curl "https://api.instapage.com/v1/workspaces?page=1" \
  -H "Authorization: Bearer API_KEY"
async function fetchWorkspaces(page, apiKey) {
    const response = await fetch(`https://api.instapage.com/v1/workspaces?page=${page}`, {
        headers: {
            'Authorization': `Bearer ${apiKey}`,
        },
    });

    if (!response.ok) {
        throw new Error(`Failed to fetch workspaces: ${response.statusText}`);
    }

    const data = await response.json();
    return data;
}
type Workspace = {
    workspaceId: number;
    ownerId: number;
    workspaceName: string;
    accessLevel: 'owner' | 'editor' | 'manager' | 'viewer';
    createdAt: number;
};

type Meta = {
    page: number;
};

type WorkspacesResponse = {
    data: Workspace[];
    meta: Meta;
};

async function fetchWorkspaces(page: number, apiKey: string): Promise<WorkspacesResponse> {
    const response = await fetch(`https://api.instapage.com/v1/workspaces?page=${page}`, {
        headers: {
            'Authorization': `Bearer ${apiKey}`,
        },
    });

    if (!response.ok) {
        throw new Error(`Failed to fetch workspaces: ${response.statusText}`);
    }

    const data: WorkspacesResponse = await response.json();
    return data;
}
<?php

declare(strict_types=1);

namespace InstapageWorkspacesFetcher;

enum AccessLevel: string
{
    case Owner = 'owner';
    case Editor = 'editor';
    case Manager = 'manager';
    case Viewer = 'viewer';
}

readonly class Workspace
{
    public function __construct(
        public int $workspaceId,
        public int $ownerId,
        public string $workspaceName,
        public AccessLevel $accessLevel,
        public int $createdAt
    ) {}

    public function toArray(): array
    {
        return [
            'workspaceId' => $this->workspaceId,
            'ownerId' => $this->ownerId,
            'workspaceName' => $this->workspaceName,
            'accessLevel' => $this->accessLevel->value,
            'createdAt' => $this->createdAt
        ];
    }

    public static function fromArray(array $data): self
    {
        return new self(
            $data['workspaceId'],
            $data['ownerId'],
            $data['workspaceName'],
            AccessLevel::from($data['accessLevel']),
            $data['createdAt']
        );
    }
}

readonly class Meta
{
    public function __construct(
        public int $page
    ) {}

    public function toArray(): array
    {
        return [
            'page' => $this->page
        ];
    }

    public static function fromArray(array $data): self
    {
        return new self($data['page']);
    }
}

class WorkspacesResponse
{
    /**
     * @param Workspace[] $data
     */
    public function __construct(
        private array $data,
        private Meta $meta
    ) {}

    /**
     * @return Workspace[]
     */
    public function getData(): array
    {
        return $this->data;
    }

    public function getMeta(): Meta
    {
        return $this->meta;
    }
}

class WorkspacesFetcher
{
    public function __construct(
        private string $baseUrl,
        private string $apiKey
    ) {}

    public function fetchWorkspaces(int $page): WorkspacesResponse
    {
        $url = sprintf(
            '%s/v1/workspaces?page=%d',
            $this->baseUrl,
            $page
        );

        $ch = curl_init($url);

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $this->apiKey,
                'Content-Type: application/json'
            ]
        ]);

        $responseBody = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if (curl_errno($ch)) {
            throw new \RuntimeException('CURL Error: ' . curl_error($ch));
        }

        curl_close($ch);

        if ($httpCode !== 200) {
            throw new \RuntimeException("Failed to fetch workspaces: HTTP $httpCode");
        }

        $responseData = json_decode($responseBody, true);

        return new WorkspacesResponse(
            array_map(
                fn($workspaceData) => Workspace::fromArray($workspaceData),
                $responseData['data']
            ),
            Meta::fromArray($responseData['meta'])
        );
    }
}

// Example usage
try {
    $baseUrl = 'https://api.instapage.com';
    $apiKey = 'your_api_key_here';
    $page = 1;

    $fetcher = new WorkspacesFetcher($baseUrl, $apiKey);

    $workspacesResponse = $fetcher->fetchWorkspaces($page);

    // Process workspaces
    foreach ($workspacesResponse->getData() as $workspace) {
        // Do something with each workspace
        print_r($workspace->toArray());
    }

    // Access metadata
    $meta = $workspacesResponse->getMeta();
    print_r($meta->toArray());

} catch (\Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

The above request returns JSON structured like this:

{
  "data": [
    {
      "workspaceId": 1177,
      "ownerId": 1319,
      "workspaceName": "Personal Projects",
      "accessLevel": "owner",
      "createdAt": 1262304000
    },
    {
      "workspaceId": 1801,
      "ownerId": 1637,
      "workspaceName": "Personal Projects",
      "accessLevel": "viewer",
      "createdAt": 1262304000
    },
    {
      "workspaceId": 2637,
      "ownerId": 2517,
      "workspaceName": "Personal Projects",
      "accessLevel": "manager",
      "createdAt": 1262304000
    },
    {
      "workspaceId": 1771,
      "ownerId": 1624,
      "workspaceName": "Personal Projects",
      "accessLevel": "editor",
      "createdAt": 1262304000
    }
  ],
  "meta": {
    "pagination": {
      "currentPage": 1,
      "perPage": 100,
      "totalItemsCount": 4,
      "totalPagesCount": 1,
      "nextPage": null,
      "previousPage": null
    }
  }
}

Headers

Query Parameters

Parameter Type Default Description
page number 1 Specifies which page to fetch. Used for pagination purposes.
name string null Optional name of the workspace to limit the result. Convenient if you already know how your workspace is named. (Case insensitive)

Response JSON structure

JSON Path Type Description
data[].workspaceId number Unique identifier of the workspace.
data[].ownerId number Identifier of the workspace owner.
data[].workspaceName string Name of the workspace.
data[].accessLevel string User's access level to the workspace.
data[].createdAt number Creation date of the workspace in UNIX timestamp format.
meta.pagination.currentPage number Number of the current page of results.
meta.pagination.perPage number Number of items per page.
meta.pagination.totalItemsCount number Total number of items.
meta.pagination.totalPagesCount number Total number of pages.
meta.pagination.nextPage number? Link to the next page (null if none).
meta.pagination.previousPage number? Link to the previous page (null if none).

Response status codes

Status Description
200 The request was processed successfully.
400 Bad request. Validation error — review input parameters.
401 Unauthorized. Authentication failed or missing credentials.
429 Too Many Requests. The server is rejecting requests due to excessive rate of requests. Please slow down and retry after some time.
500 Internal Server Error. An unexpected condition prevented the request from being fulfilled.

Get Single Workspace

Retrieves details of a single workspace by its ID..

HTTP Request

GET https://api.instapage.com/v1/workspaces/{workspaceId}

curl -X GET "https://api.instapage.com/v1/workspaces/{workspaceId}" \
  -H "Authorization: Bearer API_KEY" \
  -H "Content-Type: application/json"
async function getWorkspace(workspaceId, apiKey) {
    const response = await fetch(`https://api.instapage.com/v1/workspaces/${workspaceId}`, {
        method: 'GET',
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json',
        },
    });

    if (!response.ok) {
        throw new Error(`Failed to get workspace: ${response.statusText}`);
    }

    const data = await response.json();
    return data;
}

// Example usage
const apiKey = 'your_api_key_here';
const workspaceId = 12345;

getWorkspace(workspaceId. apiKey)
  .then(workspace => {
    console.log('Workspace:', workspace);
  })
  .catch(error => {
    console.error('Error getting workspace:', error);
  });

type AccessLevel = 'owner' | 'editor' | 'manager' | 'viewer';

interface Workspace {
    workspaceId: number;
    ownerId: number;
    workspaceName: string;
    accessLevel: AccessLevel;
    createdAt: number;
}

class WorkspaceFetcher {
    private baseUrl: string;
    private apiKey: string;

    constructor(baseUrl: string, apiKey: string) {
        this.baseUrl = baseUrl;
        this.apiKey = apiKey;
    }

    async getWorkspace(workspaceId: number): Promise<Workspace> {
        const url = `${this.baseUrl}/v1/workspaces/${workspaceId}`;

        const response = await fetch(url, {
            method: 'GET',
            headers: {
                'Authorization': `Bearer ${this.apiKey}`,
                'Content-Type': 'application/json',
            },
        });

        if (!response.ok) {
          throw new Error(`Failed to get workspace: ${response.statusText}`);
        }

        const responseData = await response.json();
        return responseData.data;
    }
}

// Example usage
const baseUrl = 'https://api.instapage.com';
const apiKey = 'your_api_key_here';
const fetcher = new WorkspaceFetcher(baseUrl, apiKey);
const workspaceId = 12345;

fetcher.getWorkspace(workspaceId)
    .then(workspace => {
        console.log('Workspace:', workspace);
    })
    .catch(error => {
        console.error('Error getting workspace:', error);
    });
<?php

declare(strict_types=1);

namespace InstapageWorkspacesFetcher;

enum AccessLevel: string
{
    case Owner = 'owner';
    case Editor = 'editor';
    case Manager = 'manager';
    case Viewer = 'viewer';
}

readonly class Workspace
{
    public function __construct(
        public int $workspaceId,
        public int $ownerId,
        public string $workspaceName,
        public AccessLevel $accessLevel,
        public int $createdAt
    ) {}

    public static function fromArray(array $data): self
    {
        return new self(
            $data['workspaceId'],
            $data['ownerId'],
            $data['workspaceName'],
            AccessLevel::from($data['accessLevel']),
            $data['createdAt']
        );
    }
}

class WorkspacesFetcher
{
    public function __construct(
        private string $baseUrl,
        private string $apiKey
    ) {}

    public function getWorkspace(int $workspaceId): Workspace
    {
        $url = sprintf('%s/v1/workspaces/%d', $this->baseUrl, $workspaceId);

        $ch = curl_init($url);

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $this->apiKey,
                'Content-Type: application/json'
            ]
        ]);

        $responseBody = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if (curl_errno($ch)) {
            throw new \RuntimeException('CURL Error: ' . curl_error($ch));
        }

        curl_close($ch);

        if ($httpCode !== 200) {
            throw new \RuntimeException("Failed to fetch workspace: HTTP $httpCode");
        }

        $responseData = json_decode($responseBody, true);

        return Workspace::fromArray($responseData['data']);
    }
}

// Example usage
try {
    $baseUrl = 'https://api.instapage.com';
    $apiKey = 'your_api_key_here';
    $workspaceId = 12345;

    $fetcher = new WorkspacesFetcher($baseUrl, $apiKey);

    $workspace = $fetcher->getWorkspace($workspaceId);

    echo 'Workspace retrieved: ' . json_encode($workspace, JSON_PRETTY_PRINT);
} catch (\Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

The above request returns JSON structured like this:

{
  "data": {
      "workspaceId": 2000,
      "ownerId": 1319,
      "workspaceName": "New Workspace Name",
      "accessLevel": "owner",
      "createdAt": 1700304000
  }
}

Headers

Path Parameters

Parameter Type Description
workspaceId number The ID of the workspace to retrieve pages for

Response JSON structure

JSON Path Type Description
data.workspaceId number Unique identifier of the workspace.
data.ownerId number Identifier of the workspace owner.
data.workspaceName string Name of the workspace.
data.accessLevel string User's access level to the workspace.
data.createdAt number Creation date of the workspace in UNIX timestamp format.

Response status codes

Status Description
200 Request was processed successfully.
400 Bad request.
401 Unauthorized. Authentication failed or missing credentials.
404 Workspace not found.
429 Too Many Requests. The server is rejecting requests due to excessive rate of requests.
500 Internal Server Error. An unexpected condition prevented the request from being fulfilled.

Add New Workspace

Create a new workspace for the authenticated user.

Note: Each workspace must have a unique name under the same owner.

HTTP Request

POST https://api.instapage.com/v1/workspaces

curl -X POST "https://api.instapage.com/v1/workspaces" \
  -H "Authorization: Bearer API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "New Workspace"}'
async function createWorkspace(name, apiKey) {
    const response = await fetch(`https://api.instapage.com/v1/workspaces`, {
        method: 'POST',
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({ name }),
    });

    if (!response.ok) {
        throw new Error(`Failed to create workspace: ${response.statusText}`);
    }

    const data = await response.json();
    return data;
}
type AccessLevel = 'owner' | 'editor' | 'manager' | 'viewer';

interface Workspace {
    workspaceId: number;
    ownerId: number;
    workspaceName: string;
    accessLevel: AccessLevel;
    createdAt: number;
}

class WorkspaceCreator {
    private baseUrl: string;
    private apiKey: string;

    constructor(baseUrl: string, apiKey: string) {
        this.baseUrl = baseUrl;
        this.apiKey = apiKey;
    }

    async createWorkspace(name: string): Promise<Workspace> {
        const url = `${this.baseUrl}/v1/workspaces`;

        const payload = JSON.stringify({ name });
        const response = await fetch(url, {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${this.apiKey}`,
                'Content-Type': 'application/json',
                'Content-Length': payload.length.toString(),
            },
            body: payload,
        });

        if (!response.ok) {
            throw new Error(`Failed to create workspace: ${response.statusText}`);
        }

        const responseData = await response.json();
        return responseData.data;
    }
}

// Example usage
const baseUrl = 'https://api.instapage.com';
const apiKey = 'your_api_key_here';
const creator = new WorkspaceCreator(baseUrl, apiKey);

creator.createWorkspace('New Workspace Name')
    .then(workspace => {
        console.log('Created Workspace:', workspace);
    })
    .catch(error => {
        console.error('Error creating workspace:', error);
    });
<?php

declare(strict_types=1);

namespace InstapageWorkspacesCreator;

enum AccessLevel: string
{
    case Owner = 'owner';
    case Editor = 'editor';
    case Manager = 'manager';
    case Viewer = 'viewer';
}

readonly class Workspace
{
    public function __construct(
        public int $workspaceId,
        public int $ownerId,
        public string $workspaceName,
        public AccessLevel $accessLevel,
        public int $createdAt
    ) {}

    public static function fromArray(array $data): self
    {
        return new self(
            $data['workspaceId'],
            $data['ownerId'],
            $data['workspaceName'],
            AccessLevel::from($data['accessLevel']),
            $data['createdAt']
        );
    }
}

class WorkspacesCreator
{
    public function __construct(
        private string $baseUrl,
        private string $apiKey
    ) {}

    public function createWorkspace(string $name): WorkspacesResponse
    {
        $url = sprintf(
            '%s/v1/workspaces',
            $this->baseUrl,
            $page
        );

        $ch = curl_init($url);

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $this->apiKey,
                'Content-Type: application/json'
            ]
        ]);

        $responseBody = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if (curl_errno($ch)) {
            throw new \RuntimeException('CURL Error: ' . curl_error($ch));
        }

        curl_close($ch);

        if ($httpCode !== 200) {
            throw new \RuntimeException("Failed to fetch workspaces: HTTP $httpCode");
        }

        $responseData = json_decode($responseBody, true);

        return Workspace::fromArray($responseData['data']);
    }
}

// Example usage
try {
    $baseUrl = 'https://api.instapage.com';
    $apiKey = 'your_api_key_here';
    $newWorkspaceName = 'workspace-12';

    $creator = new WorkspacesCreator($baseUrl, $apiKey);

    $createResponse = $creator->createWorkspace($newWorkspaceName);
} catch (\Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

The above request returns JSON structured like this:

{
  "data": {
      "workspaceId": 2000,
      "ownerId": 1319,
      "workspaceName": "New Workspace Name",
      "accessLevel": "owner",
      "createdAt": 1700304000
  }
}

Headers

Request Body

Parameter Type Required Description
name string Yes The unique name of the workspace.

Response JSON structure

JSON Path Type Description
data.workspaceId number Unique identifier of the workspace.
data.ownerId number Identifier of the workspace owner.
data.workspaceName string Name of the workspace.
data.accessLevel string User's access level to the workspace.
data.createdAt number Creation date of the workspace in UNIX timestamp format.

Response status codes

Status Description
201 The workspace was created successfully.
400 Bad request. Validation error — review input parameters.
401 Unauthorized. Authentication failed or missing credentials.
409 Conflict. A workspace with the same name already exists.
422 Unprocessable Entity. Limit of workspaces has been reached.
429 Too Many Requests. The server is rejecting requests due to excessive rate of requests.
500 Internal Server Error. An unexpected condition prevented the request from being fulfilled.

Rename Workspace

Updates the name of an existing workspace.

HTTP Request

PATCH https://api.instapage.com/v1/workspaces/{workspaceId}

curl -X PATCH "https://api.instapage.com/v1/workspaces/{workspaceId}" \
  -H "Authorization: Bearer API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "New Workspace Name"}'
async function renameWorkspace(workspaceId, name, apiKey) {
    const response = await fetch(`https://api.instapage.com/v1/workspaces/${workspaceId}`, {
        method: 'PATCH',
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({ name }),
    });

    if (!response.ok) {
        throw new Error(`Failed to rename workspace: ${response.statusText}`);
    }

    const data = await response.json();
    return data;
}


// Example usage
const workspaceId = 123;
const newWorkspaceName = 'Renamed Workspace';
const apiKey = 'your_api_key_here';

renameWorkspace(workspaceId, newWorkspaceName, apiKey)
    .then(data => {
        console.log('Renamed Workspace:', data);
    })
    .catch(error => {
        console.error('Error renaming workspace:', error);
    });
type AccessLevel = 'owner' | 'editor' | 'manager' | 'viewer';

interface Workspace {
    workspaceId: number;
    ownerId: number;
    workspaceName: string;
    accessLevel: AccessLevel;
    createdAt: number;
}

class WorkspaceRenamer {
    private baseUrl: string;
    private apiKey: string;

    constructor(baseUrl: string, apiKey: string) {
        this.baseUrl = baseUrl;
        this.apiKey = apiKey;
    }

    async renameWorkspace(workspaceId: number, newName: string): Promise<Workspace> {
        const url = `${this.baseUrl}/v1/workspaces/${workspaceId}`;

        const payload = JSON.stringify({ name: newName });
        const response = await fetch(url, {
            method: 'PATCH',
            headers: {
                'Authorization': `Bearer ${this.apiKey}`,
                'Content-Type': 'application/json',
                'Content-Length': payload.length.toString(),
            },
            body: payload,
        });

        if (!response.ok) {
            throw new Error(`Failed to rename workspace: ${response.statusText}`);
        }

        const responseData = await response.json();
        return responseData.data;
    }
}

// Example usage
const baseUrl = 'https://api.instapage.com';
const apiKey = 'your_api_key_here';
const renamer = new WorkspaceRenamer(baseUrl, apiKey);

const workspaceId = 123;
const newWorkspaceName = 'Renamed Workspace';

renamer.renameWorkspace(workspaceId, newWorkspaceName)
    .then(workspace => {
        console.log('Renamed Workspace:', workspace);
    })
    .catch(error => {
        console.error('Error renaming workspace:', error);
    });
<?php

declare(strict_types=1);

namespace InstapageWorkspacesRenamer;

enum AccessLevel: string
{
    case Owner = 'owner';
    case Editor = 'editor';
    case Manager = 'manager';
    case Viewer = 'viewer';
}

readonly class Workspace
{
    public function __construct(
        public int $workspaceId,
        public int $ownerId,
        public string $workspaceName,
        public AccessLevel $accessLevel,
        public int $createdAt
    ) {}

    public static function fromArray(array $data): self
    {
        return new self(
            $data['workspaceId'],
            $data['ownerId'],
            $data['workspaceName'],
            AccessLevel::from($data['accessLevel']),
            $data['createdAt']
        );
    }
}

class WorkspacesRenamer
{
    public function __construct(
        private string $baseUrl,
        private string $apiKey
    ) {}

    public function renameWorkspace(int $workspaceId, string $newName): Workspace
    {
        $url = sprintf('%s/v1/workspaces/%d', $this->baseUrl, $workspaceId);

        $payload = json_encode(['name' => $newName]);

        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $this->apiKey,
                'Content-Type: application/json',
            ],
            CURLOPT_CUSTOMREQUEST => 'PATCH',
            CURLOPT_POSTFIELDS => $payload,
        ]);

        $responseBody = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if (curl_errno($ch)) {
            throw new \RuntimeException('CURL Error: ' . curl_error($ch));
        }

        curl_close($ch);

        if ($httpCode !== 200) {
            throw new \RuntimeException("Failed to rename workspace: HTTP $httpCode");
        }

        $responseData = json_decode($responseBody, true);

        return Workspace::fromArray($responseData['data']);
    }
}

// Example usage
try {
    $baseUrl = 'https://api.instapage.com';
    $apiKey = 'your_api_key_here';
    $workspaceId = 123;
    $newWorkspaceName = 'Renamed Workspace';

    $renamer = new WorkspacesRenamer($baseUrl, $apiKey);

    $updatedWorkspace = $renamer->renameWorkspace($workspaceId, $newWorkspaceName);
    echo 'Workspace renamed to: ' . $updatedWorkspace->workspaceName;
} catch (\Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

The above request returns JSON structured like this:

{
  "data": {
      "workspaceId": 2000,
      "ownerId": 1319,
      "workspaceName": "New Workspace Name",
      "accessLevel": "owner",
      "createdAt": 1700304000
  }
}

Headers

Path Parameters

Parameter Type Description
workspaceId number The ID of the workspace to update.

Request Body

Field Type Description
name string The new name for the workspace.

Response JSON structure

JSON Path Type Description
data.workspaceId number Unique identifier of the workspace.
data.ownerId number Identifier of the workspace owner.
data.workspaceName string Updated name of the workspace.
data.accessLevel string User's access level to the workspace.
data.createdAt number Creation date of the workspace in UNIX timestamp format.

Response status codes

Status Description
200 Request was processed successfully.
400 Bad request. Invalid input provided.
401 Unauthorized. Authentication failed or missing credentials.
404 Workspace not found.
409 Conflict. The workspace name is already taken.
429 Too Many Requests. The server is rejecting requests due to excessive rate of requests.
500 Internal Server Error. An unexpected condition prevented the request from being fulfilled.

Delete Workspace

Deletes a workspace by its ID.

HTTP Request

DELETE https://api.instapage.com/v1/workspaces/{workspaceId}

curl -X DELETE "https://api.instapage.com/v1/workspaces/{workspaceId}" \
  -H "Authorization: Bearer API_KEY" \
  -H "Content-Type: application/json"
async function deleteWorkspace(workspaceId, apiKey) {
    const response = await fetch(`https://api.instapage.com/v1/workspaces/${workspaceId}`, {
        method: 'DELETE',
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json',
        },
    });

    if (!response.ok) {
        throw new Error(`Failed to delete workspace: ${response.statusText}`);
    }

    return response.json();
}

// Example usage
const workspaceId = 'workspaceId_here';
const apiKey = 'your_api_key_here';

deleteWorkspace(workspaceId, apiKey)
    .then(data => {
        console.log('Workspace deleted:', data);
    })
    .catch(error => {
        console.error('Error deleting workspace:', error);
    });
class WorkspaceDeleter {
    private baseUrl: string;
    private apiKey: string;

    constructor(baseUrl: string, apiKey: string) {
        this.baseUrl = baseUrl;
        this.apiKey = apiKey;
    }

    async deleteWorkspace(workspaceId: string): Promise<void> {
        const url = `${this.baseUrl}/v1/workspaces/${workspaceId}`;

        const response = await fetch(url, {
            method: 'DELETE',
            headers: {
                'Authorization': `Bearer ${this.apiKey}`,
                'Content-Type': 'application/json',
            },
        });

        if (!response.ok) {
            throw new Error(`Failed to delete workspace: ${response.statusText}`);
        }

        console.log('Workspace deleted successfully');
    }
}

// Example usage
const baseUrl = 'https://api.instapage.com';
const apiKey = 'your_api_key_here';
const deleter = new WorkspaceDeleter(baseUrl, apiKey);

deleter.deleteWorkspace('workspaceId_here')
    .then(() => {
        console.log('Workspace deleted');
    })
    .catch(error => {
        console.error('Error deleting workspace:', error);
    });
<?php

declare(strict_types=1);

namespace Instapage\PublicApi\UserInterface\Workspaces;

class WorkspaceDeleter
{
    public function __construct(
        private string $baseUrl,
        private string $apiKey
    ) {}

    public function deleteWorkspace(string $workspaceId): void
    {
        $url = sprintf(
            '%s/v1/workspaces/%s',
            $this->baseUrl,
            $workspaceId
        );

        $ch = curl_init($url);

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $this->apiKey,
                'Content-Type: application/json'
            ],
            CURLOPT_CUSTOMREQUEST => 'DELETE'
        ]);

        $responseBody = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if (curl_errno($ch)) {
            throw new \RuntimeException('CURL Error: ' . curl_error($ch));
        }

        curl_close($ch);

        if ($httpCode !== 200) {
            throw new \RuntimeException("Failed to delete workspace: HTTP $httpCode");
        }
    }
}

// Example usage
try {
    $baseUrl = 'https://api.instapage.com';
    $apiKey = 'your_api_key_here';
    $workspaceId = 'workspaceId_here';

    $deleter = new WorkspaceDeleter($baseUrl, $apiKey);

    $deleter->deleteWorkspace($workspaceId);
} catch (\Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

Headers

Path Parameters

Parameter Type Description
workspaceId number The ID of the workspace to delete.

Response status codes

Status Description
200 Workspace successfully deleted.
400 Bad request.
401 Unauthorized. Authentication failed or missing credentials.
404 Workspace not found.
429 Too Many Requests. The server is rejecting requests due to excessive rate of requests.
500 Internal Server Error. An unexpected condition prevented the request from being fulfilled.

Team Members

Get All Team Members

Retrieve all team members for a specific workspace.

HTTP Request

GET https://api.instapage.com/v1/workspaces/{workspaceId}/team-members

curl "https://api.instapage.com/v1/workspaces/{workspaceId}/team-members" \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json"

Example of body response from request

{
  "data": [
    {
      "userId": 4379,
      "email": "example_user@airslate.com",
      "invitedAt": 1685608225,
      "fullName": "John Smith",
      "accessLevel": "editor",
      "invitationStatus": "accepted",
      "lastLoginAt": 1685608226,
      "lastActivityInWorkspaceAt": null
    },
    {
      "userId": 4377,
      "email": "example1_user@airslate.com",
      "invitedAt": 1684489737,
      "fullName": "John Smith",
      "accessLevel": "manager",
      "invitationStatus": "accepted",
      "lastLoginAt": 1685970113,
      "lastActivityInWorkspaceAt": null
    },
    {
      "userId": 4373,
      "email": "example1_user@airslate.com",
      "invitedAt": null,
      "fullName": "John Smith",
      "accessLevel": "owner",
      "invitationStatus": "accepted",
      "lastLoginAt": 1729173925,
      "lastActivityInWorkspaceAt": 1729520831
    }
  ],
  "meta": []
}
async function fetchTeamMembers(workspaceId, apiKey) {
    const url = `https://api.instapage.com/v1/workspaces/${workspaceId}/team-members`;

    const response = await fetch(url, {
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        },
    });

    if (!response.ok) {
        throw new Error(`Failed to fetch team members: ${response.statusText}`);
    }

    const data = await response.json();
    return data;
}
type TeamMember = {
    userId: number;
    email: string;
    invitedAt: number | null;
    fullName: string;
    accessLevel: string;
    invitationStatus: 'accepted' | 'pending';
    lastLoginAt: number | null;
    lastActivityInWorkspaceAt: number | null;
};

type TeamMembersResponse = {
    data: TeamMember[];
    meta: any;
};

async function fetchTeamMembers(
    workspaceId: number,
    apiKey: string
): Promise<TeamMembersResponse> {
    const url = `https://api.instapage.com/v1/workspaces/${workspaceId}/team-members`;

    const response = await fetch(url, {
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        },
    });

    if (!response.ok) {
        throw new Error(`Failed to fetch team members: ${response.statusText}`);
    }

    const data: TeamMembersResponse = await response.json();
    return data;
}
<?php

declare(strict_types=1);

namespace InstapageTeamMembersFetcher;

enum InvitationStatus: string
{
    case Accepted = 'accepted';
    case Pending = 'pending';
}

readonly class TeamMember
{
    public function __construct(
        public int $userId,
        public string $email,
        public ?int $invitedAt,
        public string $fullName,
        public string $accessLevel,
        public InvitationStatus $invitationStatus,
        public ?int $lastLoginAt,
        public ?int $lastActivityInWorkspaceAt
    ) {}

    public function toArray(): array
    {
        return [
            'userId' => $this->userId,
            'email' => $this->email,
            'invitedAt' => $this->invitedAt,
            'fullName' => $this->fullName,
            'accessLevel' => $this->accessLevel,
            'invitationStatus' => $this->invitationStatus->value,
            'lastLoginAt' => $this->lastLoginAt,
            'lastActivityInWorkspaceAt' => $this->lastActivityInWorkspaceAt
        ];
    }

    public static function fromArray(array $data): self
    {
        return new self(
            $data['userId'],
            $data['email'],
            $data['invitedAt'],
            $data['fullName'],
            $data['accessLevel'],
            InvitationStatus::from($data['invitationStatus']),
            $data['lastLoginAt'],
            $data['lastActivityInWorkspaceAt']
        );
    }
}

class TeamMembersResponse
{
    /**
     * @param TeamMember[] $data
     */
    public function __construct(
        private array $data,
        private array $meta
    ) {}

    /**
     * @return TeamMember[]
     */
    public function getData(): array
    {
        return $this->data;
    }

    public function getMeta(): array
    {
        return $this->meta;
    }
}

class TeamMembersFetcher
{
    public function __construct(
        private string $baseUrl,
        private string $apiKey
    ) {}

    public function fetchTeamMembers(int $workspaceId): TeamMembersResponse
    {
        $url = sprintf(
            '%s/v1/workspaces/%d/team-members',
            $this->baseUrl,
            $workspaceId
        );

        $ch = curl_init($url);

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $this->apiKey,
                'Content-Type: application/json'
            ]
        ]);

        $responseBody = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if (curl_errno($ch)) {
            throw new \RuntimeException('CURL Error: ' . curl_error($ch));
        }

        curl_close($ch);

        if ($httpCode !== 200) {
            throw new \RuntimeException("Failed to fetch team members: HTTP $httpCode");
        }

        $responseData = json_decode($responseBody, true);

        return new TeamMembersResponse(
            array_map(
                fn($memberData) => TeamMember::fromArray($memberData),
                $responseData['data']
            ),
            $responseData['meta']
        );
    }
}

// Example usage
try {
    $baseUrl = 'https://api.instapage.com';
    $apiKey = 'your_api_key_here';
    $workspaceId = 1234;

    $fetcher = new TeamMembersFetcher($baseUrl, $apiKey);

    $teamMembersResponse = $fetcher->fetchTeamMembers($workspaceId);

    // Process team members
    foreach ($teamMembersResponse->getData() as $teamMember) {
        // Do something with each team member
        print_r($teamMember->toArray());
    }

    // Access metadata if needed
    print_r($teamMembersResponse->getMeta());

} catch (\Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

Path Parameters

Parameter Type Description
workspaceId number The ID of the workspace to retrieve team members for

Headers

Response JSON structure

JSON Path Type Description
data[].userId number Unique identifier of the team member.
data[].email string Email address of the team member.
data[].invitedAt number? Timestamp when the team member was invited (null if owner).
data[].fullName string Full name of the team member.
data[].accessLevel string accessLevel of the team member (e.g., editor, manager, owner).
data[].invitationStatus string Status of the invitation (accepted or pending).
data[].lastLoginAt number? Timestamp of the team member's last login.
data[].lastActivityInWorkspaceAt number? Timestamp of the team member's last activity in the workspace.

Response status codes

Status Description
200 The request was processed successfully.
400 Bad request. Validation error — review input parameters.
401 Unauthorized. Authentication failed or missing credentials.
403 Forbidden. The user does not have the necessary permissions.
404 Not Found. The requested resource could not be located.
429 Too Many Requests. The server is rejecting requests due to excessive rate of requests. Please slow down and retry after some time.
500 Internal Server Error. An unexpected condition prevented the request from being fulfilled.

InvitationStatus Enum

The InvitationStatus enum is used to represent the status of a team member's invitation.

This enum provides two possible states for a team member's invitation:

Invite Team Members

Invites multiple team members to join a workspace with specified accessLevels.

HTTP Request

POST https://api.instapage.com/v1/workspaces/{workspaceId}/team-members

curl -X POST \
  https://api.instapage.com/v1/workspaces/{workspaceId}/team-members \
  -H 'Authorization: Bearer {token}' \
  -H 'Content-Type: application/json' \
  -d '[
    {
      "email": "user1@example.com",
      "accessLevel": "viewer"
    },
    {
      "email": "user2@example.com",
      "accessLevel": "manager"
    }
  ]'
async function inviteTeamMembers(workspaceId, teamMembers, apiKey) {
    const response = await fetch(
        `https://api.instapage.com/v1/workspaces/${workspaceId}/team-members`, 
        {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${apiKey}`,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(teamMembers)
        }
    );

    if (!response.ok) {
        const errorData = await response.json();
        throw new Error(`Failed to invite team members: ${errorData.details}`);
    }

    return response.json();
}

// Example usage
const teamMembers = [
    { email: "user1@example.com", accessLevel: "viewer" },
    { email: "user2@example.com", accessLevel: "manager" }
];

try {
    await inviteTeamMembers(workspaceId, teamMembers, apiKey);
    console.log('Team members invited successfully');
} catch (error) {
    console.error('Error inviting team members:', error);
}
type AccessLevel = 'viewer' | 'editor' | 'manager';

interface TeamMemberInvite {
    email: string;
    accessLevel: AccessLevel;
}

async function inviteTeamMembers(
    workspaceId: number,
    teamMembers: TeamMemberInvite[],
    apiKey: string
): Promise<void> {
    const response = await fetch(
        `https://api.instapage.com/v1/workspaces/${workspaceId}/team-members`,
        {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${apiKey}`,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(teamMembers)
        }
    );

    if (!response.ok) {
        const errorData = await response.json();
        throw new Error(`Failed to invite team members: ${errorData.details}`);
    }

    return response.json();
}

// Example usage
const teamMembers: TeamMemberInvite[] = [
    { email: "user1@example.com", accessLevel: "viewer" },
    { email: "user2@example.com", accessLevel: "manager" }
];

try {
    await inviteTeamMembers(workspaceId, teamMembers, apiKey);
    console.log('Team members invited successfully');
} catch (error) {
    console.error('Error inviting team members:', error);
}
<?php

declare(strict_types=1);

namespace InstapageTeamMembers;

enum AccessLevel: string {
    case Viewer = 'viewer';
    case Editor = 'editor';
    case Manager = 'manager';
}

readonly class TeamMemberInvite {
    public function __construct(
        public string $email,
        public AccessLevel $accessLevel
    ) {}

    public function toArray(): array {
        return [
            'email' => $this->email,
            'accessLevel' => $this->accessLevel->value
        ];
    }
}

class TeamMemberInviter {
    public function __construct(
        private string $baseUrl,
        private string $apiKey
    ) {}

    /**
     * @param TeamMemberInvite[] $teamMembers
     */
    public function inviteTeamMembers(
        int $workspaceId,
        array $teamMembers
    ): void {
        $url = sprintf(
            '%s/v1/workspaces/%d/team-members',
            $this->baseUrl,
            $workspaceId
        );

        $requestBody = array_map(
            fn($member) => $member->toArray(),
            $teamMembers
        );

        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $this->apiKey,
                'Content-Type: application/json'
            ],
            CURLOPT_POSTFIELDS => json_encode($requestBody)
        ]);

        $response = curl_exec($ch);
        $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($statusCode !== 201) {
            $errorData = json_decode($response, true);
            throw new \RuntimeException(
                "Failed to invite team members: " . 
                ($errorData['details'] ?? 'Unknown error')
            );
        }
    }
}

// Example usage
try {
    $inviter = new TeamMemberInviter(
        'https://api.instapage.com',
        'your_api_key_here'
    );

    $teamMembers = [
        new TeamMemberInvite('user1@example.com', AccessLevel::Viewer),
        new TeamMemberInvite('user2@example.com', AccessLevel::Manager)
    ];

    $inviter->inviteTeamMembers(123, $teamMembers);
    echo "Team members invited successfully\n";
} catch (\Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

Headers

Path Parameters

Parameter Type Description
workspaceId number The ID of the workspace to invite members to

Request Body

The request body should be an array of objects with the following structure:

Parameter Type Description
email string Email address of the user to invite
accessLevel string accessLevel to assign to the user (viewer, viewer, or manager)

Response Status Codes

Status Description
201 Created. The team members were successfully invited.
400 Bad Request. Invalid input parameters or email format.
401 Unauthorized. Authentication failed.
403 Forbidden. User doesn't have permission to invite members or team member limit exceeded.
404 Not Found. The workspace could not be found.
429 Too Many Requests. The server is rejecting requests due to excessive rate of requests. Please slow down and retry after some time.
500 Internal Server Error. An unexpected error occurred.

Remove Team Members

Remove one or more team members from a workspace. This endpoint supports bulk removal operations.

HTTP Request

DELETE https://api.instapage.com/v1/workspaces/{workspaceId}/team-members

curl -X DELETE \
  "https://api.instapage.com/v1/workspaces/{workspaceId}/team-members" \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '[
    {
      "email": "user1@example.com"
    },
    {
      "email": "user2@example.com"
    }
  ]'

Example of error response:

{
  "title": "InvalidArgumentException",
  "details": "Email \"owner@example.com\" can't be removed from workspace because is owner",
  "meta": {
    "requestedUserId": 4373,
    "requestedPageId": 9910,
    "requestedWorkspaceId": 7068
  }
}
async function removeTeamMembers(workspaceId, emails, apiKey) {
    const url = `https://api.instapage.com/v1/workspaces/${workspaceId}/team-members`;

    const response = await fetch(url, {
        method: 'DELETE',
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        },
        body: JSON.stringify(emails.map(email => ({ email })))
    });

    if (response.status === 201) {
        console.log('Team members removed successfully');
        return;
    }

    const errorData = await response.json();
    throw new Error(`Failed to remove team members: ${errorData.details}`);
}
interface RemoveTeamMemberRequest {
    email: string;
}

interface ErrorResponse {
    title: string;
    details: string;
    meta: {
        requestedUserId: number;
        requestedWorkspaceId: number;
    };
}

async function removeTeamMembers(
    workspaceId: number,
    emails: string[],
    apiKey: string
): Promise<void> {
    const url = `https://api.instapage.com/v1/workspaces/${workspaceId}/team-members`;

    const request: RemoveTeamMemberRequest[] = emails.map(email => ({ email }));

    const response = await fetch(url, {
        method: 'DELETE',
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        },
        body: JSON.stringify(request)
    });

    if (response.status === 201) {
        return;
    }

    const errorData: ErrorResponse = await response.json();
    throw new Error(`Failed to remove team members: ${errorData.details}`);
}
<?php

declare(strict_types=1);

namespace InstapageTeamMemberRemoval;

readonly class RemoveTeamMemberRequest {
    public function __construct(
        public string $email
    ) {}

    public function toArray(): array {
        return [
            'email' => $this->email
        ];
    }
}

readonly class ErrorResponse {
    public function __construct(
        public string $title,
        public string $details,
        public int $requestedUserId,
        public int $requestedWorkspaceId
    ) {}

    public static function fromArray(array $data): self {
        return new self(
            $data['title'],
            $data['details'],
            $data['meta']['requestedUserId'],
            $data['meta']['requestedWorkspaceId']
        );
    }
}

class TeamMembersRemover {
    public function __construct(
        private string $baseUrl,
        private string $apiKey
    ) {}

    /**
     * @param string[] $emails
     * @throws \RuntimeException
     */
    public function removeTeamMembers(int $workspaceId, array $emails): void {
        $url = sprintf(
            '%s/v1/workspaces/%d/team-members',
            $this->baseUrl,
            $workspaceId
        );

        $request = array_map(
            fn(string $email) => (new RemoveTeamMemberRequest($email))->toArray(),
            $emails
        );

        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CUSTOMREQUEST => 'DELETE',
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $this->apiKey,
                'Content-Type: application/json'
            ],
            CURLOPT_POSTFIELDS => json_encode($request)
        ]);

        $responseBody = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if (curl_errno($ch)) {
            throw new \RuntimeException('CURL Error: ' . curl_error($ch));
        }

        curl_close($ch);

        if ($httpCode === 201) {
            return;
        }

        $errorData = json_decode($responseBody, true);
        $error = ErrorResponse::fromArray($errorData);
        throw new \RuntimeException("Failed to remove team members: {$error->details}");
    }
}

// Example usage
try {
    $remover = new TeamMembersRemover(
        'https://api.instapage.com',
        'your_api_key_here'
    );

    $workspaceId = 1234;
    $emails = [
        'user1@example.com',
        'user2@example.com'
    ];

    $remover->removeTeamMembers($workspaceId, $emails);
    echo "Team members removed successfully\n";
} catch (\Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

Headers

Path Parameters

Parameter Type Description
workspaceId number The ID of the workspace to remove members from

Request Body

The request body should be an array of objects, each containing:

Parameter Type Description
email string Email address of the team member

Special Cases

Response Status Codes

Status Description
201 Created. Team members were successfully removed.
400 Bad Request. Invalid input parameters or attempting to remove workspace owner.
401 Unauthorized. Authentication failed or missing credentials.
403 Forbidden. User doesn't have necessary permissions (must be owner or manager).
404 Not Found. Workspace not found.
429 Too Many Requests. The server is rejecting requests due to excessive rate of requests. Please slow down and retry after some time.
500 Internal Server Error. An unexpected condition prevented the request from being fulfilled.

Error Responses

The API returns error responses in the following format:

JSON Path Type Description
title string The type of error that occurred
details string A human-readable description of the error
meta.requestedUserId number ID of the user who made the request
meta.requestedWorkspaceId number ID of the workspace involved

Change Team Member Roles

Updates the roles of existing team members in a workspace. This endpoint allows bulk role updates for multiple team members simultaneously.

HTTP Request

PUT https://api.instapage.com/v1/workspaces/{workspaceId}/team-members

curl -X PUT \
  "https://api.instapage.com/v1/workspaces/{workspaceId}/team-members" \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '[
    {
      "email": "user1@example.com",
      "targetAccessLevel": "viewer"
    },
    {
      "email": "user2@example.com",
      "targetAccessLevel": "viewer"
    }
  ]'
async function updateTeamMemberRoles(workspaceId, roleUpdates, apiKey) {
    const url = `https://api.instapage.com/v1/workspaces/${workspaceId}/team-members`;

    const response = await fetch(url, {
        method: 'PUT',
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        },
        body: JSON.stringify(roleUpdates)
    });

    if (response.status === 201) {
        console.log('Team member roles updated successfully');
    } else {
        const errorData = await response.json();
        throw new Error(`Failed to update roles: ${errorData.details}`);
    }
}

// Example usage
const roleUpdates = [
    {
        email: "user1@example.com",
        targetAccessLevel: "viewer"
    },
    {
        email: "user2@example.com", 
        targetAccessLevel: "viewer"
    }
];

try {
    await updateTeamMemberRoles(workspaceId, roleUpdates, apiKey);
} catch (error) {
    console.error('Error updating team member roles:', error);
}
type AccessLevel = 'viewer' | 'editor' | 'manager';

interface RoleUpdate {
  email: string;
  targetAccessLevel: AccessLevel;
}

interface ErrorResponse {
  title: string;
  details: string;
  meta: {
    requestedUserId: number;
    requestedWorkspaceId: number;
  };
}

async function updateTeamMemberRoles(
  workspaceId: number,
  roleUpdates: RoleUpdate[],
  apiKey: string
): Promise<void> {
  const url = `https://api.instapage.com/v1/workspaces/${workspaceId}/team-members`;

  const response = await fetch(url, {
    method: 'PUT',
    headers: {
      'Authorization': `Bearer ${apiKey}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(roleUpdates)
  });

  if (response.status === 201) {
    console.log('Team member roles updated successfully');
    return;
  }

  const errorData: ErrorResponse = await response.json();
  throw new Error(`Failed to update roles: ${errorData.details}`);
}

// Example usage
const roleUpdates: RoleUpdate[] = [
  {
    email: "user1@example.com",
    targetAccessLevel: "viewer"
  },
  {
    email: "user2@example.com",
    targetAccessLevel: "editor"
  }
];

try {
  await updateTeamMemberRoles(workspaceId, roleUpdates, apiKey);
} catch (error) {
  console.error('Error updating team member roles:', error);
}
<?php

declare(strict_types=1);

namespace InstapageTeamMembers;

enum AccessLevel: string
{
    case Viewer = 'viewer';
    case Editor = 'editor';
    case Manager = 'manager';
}

readonly class RoleUpdate
{
    public function __construct(
        public string $email,
        public AccessLevel $targetAccessLevel
    ) {}

    public function toArray(): array
    {
        return [
            'email' => $this->email,
            'targetAccessLevel' => $this->targetAccessLevel->value
        ];
    }
}

class TeamMemberRoleUpdater
{
    public function __construct(
        private string $baseUrl,
        private string $apiKey
    ) {}

    /**
     * @param RoleUpdate[] $roleUpdates
     * @throws \RuntimeException
     */
    public function updateRoles(int $workspaceId, array $roleUpdates): void
    {
        $url = sprintf(
            '%s/v1/workspaces/%d/team-members',
            $this->baseUrl,
            $workspaceId
        );

        $requestBody = array_map(
            fn(RoleUpdate $update) => $update->toArray(),
            $roleUpdates
        );

        $ch = curl_init($url);

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CUSTOMREQUEST => 'PUT',
            CURLOPT_POSTFIELDS => json_encode($requestBody),
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $this->apiKey,
                'Content-Type: application/json'
            ]
        ]);

        $response = curl_exec($ch);
        $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        curl_close($ch);

        if ($statusCode === 201) {
            return;
        }

        $errorData = json_decode($response, true);
        throw new \RuntimeException(
            sprintf('Failed to update roles: %s', $errorData['details'])
        );
    }
}

// Example usage
try {
    $updater = new TeamMemberRoleUpdater(
        'https://api.instapage.com',
        'your_api_key_here'
    );

    $roleUpdates = [
        new RoleUpdate('user1@example.com', AccessLevel::Viewer),
        new RoleUpdate('user2@example.com', AccessLevel::Editor)
    ];

    $updater->updateRoles(7068, $roleUpdates);
    echo "Team member roles updated successfully\n";
} catch (\Exception $e) {
    echo 'Error: ' . $e->getMessage() . "\n";
}

Headers

Path Parameters

Parameter Type Description
workspaceId number The ID of the workspace containing the team members

Request Body

The request body should be an array of objects with the following structure:

Parameter Type Description
email string Email address of the team member to update
targetAccessLevel string New role to assign (viewer, editor, or manager)

Response Status Codes

Status Description
201 Created. The team member roles were successfully updated.
400 Bad Request. Invalid input parameters or duplicate emails in request.
401 Unauthorized. Authentication failed or missing credentials.
403 Forbidden. The user doesn't have permission to modify roles or attempting to modify the owner's role.
404 Not Found. The workspace was not found or one or more team members don't exist in the workspace.
429 Too Many Requests. The server is rejecting requests due to excessive rate of requests. Please slow down and retry after some time.
500 Internal Server Error. An unexpected condition prevented the request from being fulfilled.

Error Responses

The API may return error responses in the following format:

JSON Path Type Description
title string The type of error that occurred
details string A human-readable description of the error
meta.requestedUserId number ID of the user who made the request
meta.requestedWorkspaceId number ID of the workspace involved

Pages

Get All Pages

Retrieve pages for a specific workspace.

HTTP Request

GET https://api.instapage.com/v1/workspaces/{workspaceId}/pages

curl "https://api.instapage.com/v1/workspaces/{workspaceId}/pages" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json"

The above request returns JSON structured like this:

{
  "data": [
    {
      "id": 9399,
      "title": "My published page",
      "url": "mypage.example.com",
      "publishStatus": "published",
      "publishMethod": "customDomain",
      "createdAt": 1692168365,
      "updatedAt": 1725361407,
      "publishedAt": 1726005213,
      "isDeleted": false,
      "pageType": "standard",
      "totalPersonalizedExperienceCount": 6,
      "isScheduled": false
    },
    {
      "id": 9909,
      "title": "My unpublished page",
      "url": null,
      "publishStatus": "unpublished",
      "publishMethod": "customDomain",
      "createdAt": 1725916359,
      "updatedAt": 1725916362,
      "publishedAt": 1725921862,
      "isDeleted": false,
      "pageType": "standard",
      "totalPersonalizedExperienceCount": 0,
      "isScheduled": true
    }
  ],
  "meta": {
    "pagination": {
      "currentPage": 1,
      "perPage": 100,
      "totalItemsCount": 2,
      "totalPagesCount": 1,
      "nextPage": null,
      "previousPage": null
    }
  }
}
async function fetchPages(workspaceId, page, isDeleted, publishStatus, apiKey) {
    const url = new URL(`https://api.instapage.com/v1/workspaces/${workspaceId}/pages`);
    url.searchParams.append('page', page);
    url.searchParams.append('isDeleted', isDeleted);
    if (publishStatus) {
        url.searchParams.append('publishStatus', publishStatus);
    }

    const response = await fetch(url, {
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        },
    });

    if (!response.ok) {
        throw new Error(`Failed to fetch pages: ${response.statusText}`);
    }

    const data = await response.json();
    return data;
}
type Page = {
    id: number;
    title: string;
    url: string | null;
    publishStatus: 'published' | 'unpublished' | 'publishedHasChanges';
    publishMethod: 'cmsPlugin' | 'customDomain' | 'pageDemo';
    createdAt: number;
    updatedAt: number;
    isDeleted: boolean;
    pageType: 'amp' | 'standard' | 'collectionTemplate' | 'wordpress' | 'drupal';
    totalPersonalizedExperienceCount: number;
    isScheduled: boolean;
};

type PaginationMeta = {
    currentPage: number;
    perPage: number;
    totalItemsCount: number;
    totalPagesCount: number;
    nextPage: number | null;
    previousPage: number | null;
};

type PagesResponse = {
    data: Page[];
    meta: {
        pagination: PaginationMeta;
    };
};

async function fetchPages(
    apiKey: string,
    workspaceId: number,
    page: number,
    isDeleted: boolean,
    publishStatus?: 'published' | 'unpublished' | 'publishedHasChanges',
): Promise<PagesResponse> {
    const url = new URL(`https://api.instapage.com/v1/workspaces/${workspaceId}/pages`);
    url.searchParams.append('page', page.toString());
    url.searchParams.append('isDeleted', isDeleted.toString());
    if (publishStatus) {
        url.searchParams.append('publishStatus', publishStatus);
    }

    const response = await fetch(url.toString(), {
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        },
    });

    if (!response.ok) {
        throw new Error(`Failed to fetch pages: ${response.statusText}`);
    }

    const data: PagesResponse = await response.json();
    return data;
}
<?php

declare(strict_types=1);

namespace InstapagePagesFetcher;

enum PublishStatus: string
{
    case Published = 'published';
    case Unpublished = 'unpublished';
    case PublishedHasChanges = 'publishedHasChanges';
}

enum PublishMethod: string
{
    case CmsPlugin = 'cmsPlugin';
    case CustomDomain = 'customDomain';
    case PageDemo = 'pageDemo';
}

enum PageType: string
{
    case Amp = 'amp';
    case Standard = 'standard';
    case CollectionTemplate = 'collectionTemplate';
    case WordPress = 'wordpress';
    case Drupal = 'drupal';
}

readonly class Page
{
    public function __construct(
        public int $id,
        public string $title,
        public ?string $url,
        public PublishStatus $publishStatus,
        public PublishMethod $publishMethod,
        public int $createdAt,
        public int $updatedAt,
        public bool $isDeleted,
        public PageType $pageType,
        public int $totalPersonalizedExperienceCount,
        public bool $isScheduled
    ) {}

    public function toArray(): array
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'url' => $this->url,
            'publishStatus' => $this->publishStatus->value,
            'publishMethod' => $this->publishMethod->value,
            'createdAt' => $this->createdAt,
            'updatedAt' => $this->updatedAt,
            'isDeleted' => $this->isDeleted,
            'pageType' => $this->pageType->value,
            'totalPersonalizedExperienceCount' => $this->totalPersonalizedExperienceCount,
            'isScheduled' => $this->isScheduled
        ];
    }
}

readonly class PaginationMeta
{
    public function __construct(
        public int $currentPage,
        public int $perPage,
        public int $totalItemsCount,
        public int $totalPagesCount,
        public ?int $nextPage,
        public ?int $previousPage
    ) {}

    public function toArray(): array
    {
        return [
            'currentPage' => $this->currentPage,
            'perPage' => $this->perPage,
            'totalItemsCount' => $this->totalItemsCount,
            'totalPagesCount' => $this->totalPagesCount,
            'nextPage' => $this->nextPage,
            'previousPage' => $this->previousPage
        ];
    }
}

class PagesResponse
{
    /**
     * @param Page[] $data
     */
    public function __construct(
        private array $data,
        private PaginationMeta $paginationMeta
    ) {}

    public function getData(): array
    {
        return $this->data;
    }

    public function getMeta(): PaginationMeta
    {
        return $this->paginationMeta;
    }
}

class PagesFetcher
{
    public function __construct(
        private string $baseUrl,
        private string $apiKey
    ) {}

    public function fetchPages(
        int $workspaceId,
        int $page,
        bool $isDeleted,
        ?PublishStatus $publishStatus = null
    ): PagesResponse {
        $url = sprintf(
            '%s/v1/workspaces/%d/pages?page=%d&isDeleted=%s%s',
            $this->baseUrl,
            $workspaceId,
            $page,
            $isDeleted ? 'true' : 'false',
            $publishStatus ? '&publishStatus=' . $publishStatus->value : ''
        );

        $ch = curl_init($url);

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $this->apiKey,
                'Content-Type: application/json'
            ]
        ]);

        $responseBody = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if (curl_errno($ch)) {
            throw new \RuntimeException('CURL Error: ' . curl_error($ch));
        }

        curl_close($ch);

        if ($httpCode !== 200) {
            throw new \RuntimeException("API request failed with status code: $httpCode");
        }

        $responseData = json_decode($responseBody, true);

        return new PagesResponse(
            array_map(fn($pageData) => new Page(
                $pageData['id'],
                $pageData['title'],
                $pageData['url'] ?? null,
                PublishStatus::from($pageData['publishStatus']),
                PublishMethod::from($pageData['publishMethod']),
                $pageData['createdAt'],
                $pageData['updatedAt'],
                $pageData['isDeleted'],
                PageType::from($pageData['pageType']),
                $pageData['totalPersonalizedExperienceCount'],
                $pageData['isScheduled']
            ), $responseData['data']),
            new PaginationMeta(
                $responseData['meta']['pagination']['currentPage'],
                $responseData['meta']['pagination']['perPage'],
                $responseData['meta']['pagination']['totalItemsCount'],
                $responseData['meta']['pagination']['totalPagesCount'],
                $responseData['meta']['pagination']['nextPage'],
                $responseData['meta']['pagination']['previousPage']
            )
        );
    }
}

// Example usage
try {
    $baseUrl = 'https://api.instapage.com';
    $apiKey = 'your_api_key_here';
    $workspaceId = 1234;

    $fetcher = new PagesFetcher($baseUrl, $apiKey);

    $pagesResponse = $fetcher->fetchPages(
        workspaceId: $workspaceId,
        page: 1,
        isDeleted: false,
        publishStatus: PublishStatus::Published
    );

    // Process pages
    foreach ($pagesResponse->getData() as $page) {
        // Do something with each page
        print_r($page->toArray());
    }

    // Access pagination metadata
    $paginationMeta = $pagesResponse->getMeta();
    print_r($paginationMeta->toArray());
} catch (\Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

Headers

Path Parameters

Parameter Type Description
workspaceId number The ID of the workspace to retrieve pages for

Query Parameters

Parameter Type Default Description
page number 1 Specifies which page to fetch. Used for pagination purposes.
isDeleted boolean false When set to true, returns only deleted pages. When false, returns only non-deleted pages.
publishStatus string? null Filter pages by publish status. Possible values: published, unpublished, publishedHasChanges
publishMethod string? null Filter pages by publish method. Possible values: cmsPlugin, customDomain, pageDemo
publishedAfter number? null Filter pages published after the specified UNIX timestamp.
publishedBefore number? null Filter pages published before the specified UNIX timestamp.
createdAfter number? null Filter pages created after the specified UNIX timestamp.
createdBefore number? null Filter pages created before the specified UNIX timestamp.

This endpoint retrieves a list of pages for the specified workspace. The response includes detailed information about each page, such as its ID, title, URL, publish status, and more. The results are paginated, and you can use the page query parameter to navigate through the pages of results.

Response JSON structure

JSON Path Type Description
data[].id number Unique identifier of the page.
data[].title string Title of the page.
data[].url string? URL of the page, null if unpublished.
data[].publishStatus string Current publish status of the page (e.g., published, unpublished).
data[].publishMethod string Method used for publishing the page (e.g., customDomain).
data[].createdAt number Creation timestamp of the page (UNIX format).
data[].updatedAt number Last update timestamp of the page (UNIX format).
data[].publishedAt number? Timestamp of when the page was published (UNIX format), null if unpublished.
data[].isDeleted boolean Indicates whether the page has been deleted.
data[].pageType string Type of the page (e.g., standard).
data[].totalPersonalizedExperienceCount number Total count of personalized experiences for the page.
data[].isScheduled boolean Indicates whether the page is scheduled for publication.
meta.pagination.currentPage number Number of the current page of results.
meta.pagination.perPage number Number of items per page.
meta.pagination.totalItemsCount number Total number of items.
meta.pagination.totalPagesCount number Total number of pages.
meta.pagination.nextPage number? Number of the next page, or null if there is no next page.
meta.pagination.previousPage number? Number of the previous page, or null if there is no previous page.

Response status codes

Status Description
200 The request was processed successfully.
400 Bad request. Validation error — review input parameters.
401 Unauthorized. Authentication failed or missing credentials.
429 Too Many Requests. The server is rejecting requests due to excessive rate of requests. Please slow down and retry after some time.
500 Internal Server Error. An unexpected condition prevented the request from being fulfilled.

Get Page

Retrieve detailed information about a specific page within a workspace.

HTTP Request

GET https://api.instapage.com/v1/workspaces/{workspaceId}/pages/{pageId}

curl "https://api.instapage.com/v1/workspaces/$workspaceId/pages/$pageId" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json"
async function fetchPageDetails(workspaceId, pageId, apiKey) {
    const url = `https://api.instapage.com/v1/workspaces/${workspaceId}/pages/${pageId}`;

    const response = await fetch(url, {
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        }
    });

    if (!response.ok) {
        throw new Error(`Failed to fetch page details: ${response.statusText}`);
    }

    return await response.json();
}
type PublishStatus = 'published' | 'unpublished' | 'publishedHasChanges';
type PublishMethod = 'cmsPlugin' | 'customDomain' | 'pageDemo';
type PageType = 'amp' | 'standard' | 'collectionTemplate' | 'wordpress' | 'drupal';

interface PageResponse {
    data: {
        id: number;
        title: string;
        url: string | null;
        publishStatus: PublishStatus;
        publishMethod: PublishMethod | null;
        createdAt: number;
        updatedAt: number;
        publishedAt: number | null;
        isDeleted: boolean;
        pageType: PageType;
        totalPersonalizedExperienceCount: number;
        isScheduled: boolean;
    };
    meta: Record<string, never>;
}

async function fetchPageDetails(
    workspaceId: number,
    pageId: number,
    apiKey: string
): Promise<PageResponse> {
    const url = `https://api.instapage.com/v1/workspaces/${workspaceId}/pages/${pageId}`;

    const response = await fetch(url, {
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        }
    });

    if (!response.ok) {
        throw new Error(`Failed to fetch page details: ${response.statusText}`);
    }

    return await response.json();
}
<?php

declare(strict_types=1);

namespace InstapagePageFetcher;

enum PublishStatus: string {
    case Published = 'published';
    case Unpublished = 'unpublished';
    case PublishedHasChanges = 'publishedHasChanges';
}

enum PublishMethod: string {
    case CmsPlugin = 'cmsPlugin';
    case CustomDomain = 'customDomain';
    case PageDemo = 'pageDemo';
}

enum PageType: string {
    case Amp = 'amp';
    case Standard = 'standard';
    case CollectionTemplate = 'collectionTemplate';
    case WordPress = 'wordpress';
    case Drupal = 'drupal';
}

readonly class PageDetails {
    public function __construct(
        public int $id,
        public string $title,
        public ?string $url,
        public PublishStatus $publishStatus,
        public ?PublishMethod $publishMethod,
        public int $createdAt,
        public int $updatedAt,
        public ?int $publishedAt,
        public bool $isDeleted,
        public PageType $pageType,
        public int $totalPersonalizedExperienceCount,
        public bool $isScheduled
    ) {}

    public static function fromArray(array $data): self {
        return new self(
            $data['id'],
            $data['title'],
            $data['url'],
            PublishStatus::from($data['publishStatus']),
            $data['publishMethod'] ? PublishMethod::from($data['publishMethod']) : null,
            $data['createdAt'],
            $data['updatedAt'],
            $data['publishedAt'],
            $data['isDeleted'],
            PageType::from($data['pageType']),
            $data['totalPersonalizedExperienceCount'],
            $data['isScheduled']
        );
    }
}

class PageDetailsFetcher {
    public function __construct(
        private string $baseUrl,
        private string $apiKey
    ) {}

    public function fetchPageDetails(int $workspaceId, int $pageId): PageDetails {
        $url = sprintf(
            '%s/v1/workspaces/%d/pages/%d',
            $this->baseUrl,
            $workspaceId,
            $pageId
        );

        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $this->apiKey,
                'Content-Type: application/json'
            ]
        ]);

        $response = curl_exec($ch);
        $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($statusCode !== 200) {
            throw new \RuntimeException("Failed to fetch page details: HTTP $statusCode");
        }

        $data = json_decode($response, true);
        return PageDetails::fromArray($data['data']);
    }
}

// Example usage
try {
    $fetcher = new PageDetailsFetcher(
        'https://api.instapage.com',
        'your_api_key_here'
    );

    $pageDetails = $fetcher->fetchPageDetails(123, 456);
    var_dump($pageDetails);
} catch (\Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

The above request returns JSON structured like this:

{
    "data": {
        "id": 9371,
        "title": "My Landing Page",
        "url": "landing.example.com",
        "publishStatus": "published",
        "publishMethod": "customDomain",
        "createdAt": 1692168365,
        "updatedAt": 1725361407,
        "publishedAt": 1726005213,
        "isDeleted": false,
        "pageType": "standard",
        "totalPersonalizedExperienceCount": 3,
        "isScheduled": false
    },
    "meta": {}
}

Path Parameters

Parameter Type Description
workspaceId number The ID of the workspace containing the page
pageId number The ID of the page to retrieve

Headers

Response JSON Structure

JSON Path Type Description
data.id number Unique identifier of the page
data.title string Title of the page
data.url string? URL where the page is published (null if unpublished)
data.publishStatus string Current publish status (published, unpublished, publishedHasChanges)
data.publishMethod string? Method used for publishing (cmsPlugin, customDomain, pageDemo)
data.createdAt number Creation timestamp (UNIX format)
data.updatedAt number Last update timestamp (UNIX format)
data.publishedAt number? Publication timestamp (UNIX format), null if unpublished
data.isDeleted boolean Indicates if the page has been deleted
data.pageType string Type of page (amp, standard, collectionTemplate, wordpress, drupal)
data.totalPersonalizedExperienceCount number Number of personalized experiences for this page
data.isScheduled boolean Indicates if the page has scheduled publishing

Response Status Codes

Status Description
200 The request was processed successfully
400 Bad request. Invalid page ID or workspace ID
401 Unauthorized. Authentication failed or missing credentials
404 Not Found. The page or workspace could not be found or the page does not belong to workspace
429 Too Many Requests. The server is rejecting requests due to excessive rate of requests. Please slow down and retry after some time.
500 Internal Server Error. An unexpected condition prevented the request from being fulfilled

Publish a Page

Publishes a page with the specified publication method and target URL.

HTTP Request

POST https://api.instapage.com/v1/workspaces/{workspaceId}/pages/{pageId}/publication

curl -X POST \
  https://api.instapage.com/v1/workspaces/{workspaceId}/pages/{pageId}/publication \
  -H 'Authorization: Bearer {token}' \
  -H 'Content-Type: application/json' \
  -d '{
    "targetUrl": {targetUrl},
    "publicationMethod": {publicationMethod}
}'
> Example of body error from request
{
  "title": "InvalidDomainException",
  "details": "The provided domain is not valid",
  "meta": {
    "requestedUserId": 4373,
    "requestedPageId": 9910,
    "requestedWorkspaceId": 7068,
    "requestedPublishMethod": "customDomain"
  }
}
const publishPage = async (targetUrl, publicationMethod, pageId, workspaceId, token) => {
    try {
        const response = await fetch(`https://api.instapage.com/v1/workspaces/${workspaceId}/pages/${pageId}/publication`, {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${token}`,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                targetUrl: targetUrl,
                publicationMethod: publicationMethod,
            })
        });

        if (response.status === 202) {
            console.log('Page publication request accepted');
        } else {
            const errorData = await response.json();
            console.error('Error publishing page:', errorData);
        }
    } catch (error) {
        console.error('An error occurred:', error);
    }
};
type PluginPublicationMethod = 'wordpress' | 'drupal';
type DomainPublicationMethod = 'customDomain' | 'freeDomain';

type PublicationMethod = PluginPublicationMethod | DomainPublicationMethod;

type PublishPageBodyRequest<T extends PublicationMethod> = T extends PluginPublicationMethod
    ? {
        targetUrl: null;
        publicationMethod: T;
    }
    : {
        targetUrl: string;
        publicationMethod: T;
    };

interface ErrorResponse {
    title: string;
    details: string;
    meta: {
        requestedUserId: number;
        requestedPageId: number;
        requestedWorkspaceId: number;
        requestedPublishMethod: string;
    };
}

const publishPage = async (request: PublishPageBodyRequest, pageId: number, workspaceId: number, token: string): Promise<void> => {
    try {
        const response = await fetch(`https://api.instapage.com/v1/workspaces/${workspaceId}/pages/${pageId}/publication`, {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${token}`,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(request)
        });

        if (response.status === 202) {
            console.log('Page publication request accepted');
        } else {
            const errorData: ErrorResponse = await response.json();
            console.error('Error publishing page:', errorData);
        }
    } catch (error) {
        console.error('An error occurred:', error);
    }
};
<?php

declare(strict_types=1);

namespace InstapagePagePublication;

enum PluginPublicationMethod: string
{
    case WordPress = 'wordpress';
    case Drupal = 'drupal';
}

enum DomainPublicationMethod: string
{
    case CustomDomain = 'customDomain';
    case FreeDomain = 'freeDomain';
}

class PublicationMethodValidator
{
    public static function validate(string $method): bool
    {
        return 
            in_array($method, array_column(PluginPublicationMethod::cases(), 'value')) ||
            in_array($method, array_column(DomainPublicationMethod::cases(), 'value'));
    }
}

class PublishPageBodyRequest
{
    public function __construct(
        private ?string $targetUrl,
        private string $publicationMethod
    ) {
        $this->validate();
    }

    private function validate(): void
    {
        // Validate publication method
        if (!PublicationMethodValidator::validate($this->publicationMethod)) {
            throw new \InvalidArgumentException("Invalid publication method");
        }

        // Validate target URL based on publication method
        $isPluginMethod = in_array(
            $this->publicationMethod, 
            array_column(PluginPublicationMethod::cases(), 'value')
        );

        if ($isPluginMethod && $this->targetUrl !== null) {
            throw new \InvalidArgumentException("Plugin publication method cannot have a target URL");
        }

        if (!$isPluginMethod && $this->targetUrl === null) {
            throw new \InvalidArgumentException("Non-plugin publication method requires a target URL");
        }
    }

    public function toArray(): array
    {
        return [
            'targetUrl' => $this->targetUrl,
            'publicationMethod' => $this->publicationMethod
        ];
    }
}

readonly class ErrorResponse
{
    public function __construct(
        public string $title,
        public string $details,
        public int $requestedUserId,
        public int $requestedPageId,
        public int $requestedWorkspaceId,
        public string $requestedPublishMethod
    ) {}

    public static function fromArray(array $data): self
    {
        return new self(
            $data['title'],
            $data['details'],
            $data['meta']['requestedUserId'],
            $data['meta']['requestedPageId'],
            $data['meta']['requestedWorkspaceId'],
            $data['meta']['requestedPublishMethod']
        );
    }

    public function toArray(): array
    {
        return [
            'title' => $this->title,
            'details' => $this->details,
            'meta' => [
                'requestedUserId' => $this->requestedUserId,
                'requestedPageId' => $this->requestedPageId,
                'requestedWorkspaceId' => $this->requestedWorkspaceId,
                'requestedPublishMethod' => $this->requestedPublishMethod
            ]
        ];
    }
}

class PagePublisher
{
    public function __construct(
        private string $baseUrl,
        private string $apiKey
    ) {}

    public function publishPage(
        PublishPageBodyRequest $request, 
        int $pageId, 
        int $workspaceId
    ): void {
        $url = sprintf(
            '%s/v1/workspaces/%d/pages/%d/publication',
            $this->baseUrl,
            $workspaceId,
            $pageId
        );

        $ch = curl_init($url);

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $this->apiKey,
                'Content-Type: application/json'
            ],
            CURLOPT_POSTFIELDS => json_encode($request->toArray())
        ]);

        $responseBody = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if (curl_errno($ch)) {
            throw new \RuntimeException('CURL Error: ' . curl_error($ch));
        }

        curl_close($ch);

        if ($httpCode === 202) {
            echo "Page publication request accepted\n";
            return;
        }

        if ($httpCode !== 200) {
            $errorData = json_decode($responseBody, true);
            $errorResponse = ErrorResponse::fromArray($errorData);

            throw new \RuntimeException(
                "Error publishing page: " . 
                json_encode($errorResponse->toArray())
            );
        }
    }
}

// Example usage
try {
    $baseUrl = 'https://api.instapage.com';
    $apiKey = 'your_api_key_here';
    $workspaceId = 1234;
    $pageId = 5678;

    $publisher = new PagePublisher($baseUrl, $apiKey);

    // Example for plugin publication method (no target URL)
    $pluginRequest = new PublishPageBodyRequest(
        targetUrl: null, 
        publicationMethod: PluginPublicationMethod::WordPress->value
    );

    $publisher->publishPage($pluginRequest, $pageId, $workspaceId);

    // Example for domain publication method (with target URL)
    $domainRequest = new PublishPageBodyRequest(
        targetUrl: 'https://example.com', 
        publicationMethod: DomainPublicationMethod::CustomDomain->value
    );

    $publisher->publishPage($domainRequest, $pageId, $workspaceId);

} catch (\Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

Headers

Path Parameters

Parameter Type Description
workspaceId number The ID of the workspace
pageId number The ID of the page to publish

Request Body

Parameter Type Description
targetUrl string? The URL where the page will be published, if is wordpress or drupal should be null
publicationMethod string The method of publication. Can be wordpress, drupal, customDomain, or freeDomain

Responses

Status Description
202 Accepted. The request has been accepted for processing.
400 Bad Request. Invalid input parameters or publication method not permitted.
401 Unauthorized. Authentication failed (implied by AuthMiddleware).
403 Forbidden. Published pages limit exceeded or user doesn't have necessary permissions.
404 Not Found. The specified page was not found.
429 Too Many Requests. The server is rejecting requests due to excessive rate of requests. Please slow down and retry after some time.
500 Internal Server Error. An unexpected error occurred or publish setup not found.
503 Service Unavailable. Entity-related exception occurred.

Unpublish a Page

Unpublishes a previously published page.

HTTP Request

DELETE https://api.instapage.com/v1/workspaces/{workspaceId}/pages/{pageId}/publication

curl -X DELETE \
  https://api.instapage.com/v1/workspaces/{workspaceId}/pages/{pageId}/publication \
  -H 'Authorization: Bearer {token}' \
  -H 'Content-Type: application/json'

Example of body error from request

{
  "title": "PageIsNotPublishedException",
  "details": "The page \"9910\" is not published",
  "meta": {
    "requestedUserId": 4373,
    "requestedPageId": 9910,
    "requestedWorkspaceId": 7068
  }
}
const unpublishPage = async (pageId, workspaceId, token) => {
    const response = await fetch(`https://api.instapage.com/v1/workspaces/${workspaceId}/pages/${pageId}/publication`, {
        method: 'DELETE',
        headers: {
            'Authorization': `Bearer ${token}`,
            'Content-Type': 'application/json'
        }
    });

    if (response.status === 201) {
        console.log('Page unpublished successfully');
    } else {
        const errorData = await response.json();
        console.error('Error unpublishing page:', errorData);
    }
};
interface ErrorResponse {
    title: string;
    details: string;
    meta: {
        requestedUserId: number;
        requestedPageId: number;
        requestedWorkspaceId: number;
    };
}

const unpublishPage = async (pageId: number, workspaceId: number, token: string) => {
    try {
            const response = await fetch(`https://api.instapage.com/v1/workspaces/${workspaceId}/pages/${pageId}/publication`, {
            method: 'DELETE',
            headers: {
                'Authorization': `Bearer ${token}`,
                'Content-Type': 'application/json'
            }
        });

        if (response.status === 201) {
            console.log('Page unpublished successfully');
        } else {
            const errorData: ErrorResponse = await response.json();
            console.error('Error unpublishing page:', errorData);
        }
    } catch (error) {
        console.error('An error occurred:', error);
    }
};
<?php

declare(strict_types=1);

namespace InstapagePageUnpublication;

readonly class ErrorResponse
{
    public function __construct(
        public string $title,
        public string $details,
        public int $requestedUserId,
        public int $requestedPageId,
        public int $requestedWorkspaceId
    ) {}

    public static function fromArray(array $data): self
    {
        return new self(
            $data['title'],
            $data['details'],
            $data['meta']['requestedUserId'],
            $data['meta']['requestedPageId'],
            $data['meta']['requestedWorkspaceId']
        );
    }

    public function toArray(): array
    {
        return [
            'title' => $this->title,
            'details' => $this->details,
            'meta' => [
                'requestedUserId' => $this->requestedUserId,
                'requestedPageId' => $this->requestedPageId,
                'requestedWorkspaceId' => $this->requestedWorkspaceId
            ]
        ];
    }
}

class PageUnpublisher
{
    public function __construct(
        private string $baseUrl,
        private string $apiKey
    ) {}

    public function unpublishPage(int $pageId, int $workspaceId): void
    {
        $url = sprintf(
            '%s/v1/workspaces/%d/pages/%d/publication',
            $this->baseUrl,
            $workspaceId,
            $pageId
        );

        $ch = curl_init($url);

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CUSTOMREQUEST => 'DELETE',
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $this->apiKey,
                'Content-Type: application/json'
            ]
        ]);

        $responseBody = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if (curl_errno($ch)) {
            throw new \RuntimeException('CURL Error: ' . curl_error($ch));
        }

        curl_close($ch);

        if ($httpCode === 201) {
            echo "Page unpublished successfully\n";
            return;
        }

        if ($httpCode !== 200) {
            $errorData = json_decode($responseBody, true);
            $errorResponse = ErrorResponse::fromArray($errorData);

            throw new \RuntimeException(
                "Error unpublishing page: " . 
                json_encode($errorResponse->toArray())
            );
        }
    }
}

// Example usage
try {
    $baseUrl = 'https://api.instapage.com';
    $apiKey = 'your_api_key_here';
    $workspaceId = 1234;
    $pageId = 5678;

    $unpublisher = new PageUnpublisher($baseUrl, $apiKey);
    $unpublisher->unpublishPage($pageId, $workspaceId);

} catch (\Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

Headers

Path Parameters

Parameter Type Description
workspaceId number The ID of the workspace
pageId number The ID of the page to unpublish

Responses

Status Description
201 Created. The page was successfully unpublished.
400 Bad Request. The page is not published.
401 Unauthorized. Authentication failed.
403 Forbidden. The user doesn't have the necessary permissions.
404 Not Found. The specified page was not found.
429 Too Many Requests. The server is rejecting requests due to excessive rate of requests. Please slow down and retry after some time.
500 Internal Server Error. An unexpected error occurred.

Search Pages Globally

Search for pages across all accessible workspaces by ID, title, or URL.

HTTP Request

GET https://api.instapage.com/v1/pages/search

curl "https://api.instapage.com/v1/pages/search?page=1&id=9371&title=my%20page" \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json"
async function searchPages(page, searchParams, apiKey) {
    const url = new URL('https://api.instapage.com/v1/pages/search');
    url.searchParams.append('page', page);

    // Add optional search parameters
    if (searchParams.id) url.searchParams.append('id', searchParams.id);
    if (searchParams.title) url.searchParams.append('title', searchParams.title);
    if (searchParams.url) url.searchParams.append('url', searchParams.url);

    const response = await fetch(url, {
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        },
    });

    if (!response.ok) {
        throw new Error(`Failed to search pages: ${response.statusText}`);
    }

    return await response.json();
}
type SearchParams = {
    id?: number;
    title?: string;
    url?: string;
};

type SearchResult = {
    id: number;
    workspaceId: number; 
    title: string;
    url: string | null;
};

type SearchResponse = {
    data: SearchResult[];
    meta: {
        requestedPageId: number | null;
        requestedPageTitle: string | null;
        requestedPageUrl: string | null;
        pagination: {
            currentPage: number;
            perPage: number;
            totalItemsCount: number;
            totalPagesCount: number;
            nextPage: number | null;
            previousPage: number | null;
        };
    };
};

async function searchPages(
    page: number,
    searchParams: SearchParams,
    apiKey: string
): Promise<SearchResponse> {
    const url = new URL('https://api.instapage.com/v1/pages/search');
    url.searchParams.append('page', page.toString());

    if (searchParams.id) url.searchParams.append('id', searchParams.id.toString());
    if (searchParams.title) url.searchParams.append('title', searchParams.title);
    if (searchParams.url) url.searchParams.append('url', searchParams.url);

    const response = await fetch(url.toString(), {
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        },
    });

    if (!response.ok) {
        throw new Error(`Failed to search pages: ${response.statusText}`);
    }

    return await response.json();
}
<?php

declare(strict_types=1);

namespace InstapagePageSearch;

readonly class SearchParams
{
    public function __construct(
        public ?int $id = null,
        public ?string $title = null, 
        public ?string $url = null
    ) {}

    public function toQueryString(): string
    {
        $params = [];

        if ($this->id !== null) {
            $params['id'] = $this->id;
        }
        if ($this->title !== null) {
            $params['title'] = $this->title;
        }
        if ($this->url !== null) {
            $params['url'] = $this->url;
        }

        return http_build_query($params);
    }
}

readonly class SearchResult 
{
    public function __construct(
        public int $id,
        public int $workspaceId,
        public string $title,
        public ?string $url
    ) {}

    public static function fromArray(array $data): self
    {
        return new self(
            $data['id'],
            $data['workspaceId'],
            $data['title'],
            $data['url'] ?? null
        );
    }
}

class PageSearcher
{
    public function __construct(
        private string $baseUrl,
        private string $apiKey
    ) {}

    public function searchPages(int $page, SearchParams $params): array
    {
        $queryString = $params->toQueryString();
        $url = sprintf(
            '%s/v1/pages/search?page=%d&%s',
            $this->baseUrl,
            $page,
            $queryString
        );

        $ch = curl_init($url);

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $this->apiKey,
                'Content-Type: application/json'
            ]
        ]);

        $responseBody = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if (curl_errno($ch)) {
            throw new \RuntimeException('CURL Error: ' . curl_error($ch));
        }

        curl_close($ch);

        if ($httpCode !== 200) {
            throw new \RuntimeException("Search request failed: HTTP $httpCode");
        }

        $responseData = json_decode($responseBody, true);

        return array_map(
            fn($result) => SearchResult::fromArray($result),
            $responseData['data']
        );
    }
}

// Example usage
try {
    $searcher = new PageSearcher(
        'https://api.instapage.com',
        'your_api_key_here'
    );

    $params = new SearchParams(
        title: 'Landing Page'
    );

    $results = $searcher->searchPages(1, $params);

    foreach ($results as $result) {
        echo sprintf(
            "Found page: %s (ID: %d, Workspace: %d)\n",
            $result->title,
            $result->id,
            $result->workspaceId
        );
    }
} catch (\Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

The above request returns JSON structured like this:

{
    "data": [
        {
            "id": 9371,
            "workspaceId": 7068,
            "title": "My Landing Page",
            "url": "landing.example.com"
        },
        {
            "id": 9372,
            "workspaceId": 7068,
            "title": "Product Launch Page",
            "url": null
        }
    ],
    "meta": {
        "requestedPageId": null,
        "requestedPageTitle": "page",
        "requestedPageUrl": null,
        "pagination": {
            "currentPage": 1,
            "perPage": 100,
            "totalItemsCount": 2,
            "totalPagesCount": 1,
            "nextPage": null,
            "previousPage": null
        }
    }
}

Query Parameters

Parameter Type Default Description
page number 1 Page number for pagination.
id number null Filter results by page ID.
title string null Filter results by page title (case-insensitive).
url string null Filter results by published URL.

Response JSON structure

JSON Path Type Description
data[].id number Unique identifier of the page.
data[].workspaceId number ID of the workspace containing the page.
data[].title string Title of the page.
data[].url string? Published URL of the page (null if unpublished).
meta.requestedPageId number? The page ID used in the search request.
meta.requestedPageTitle string? The page title used in the search request.
meta.requestedPageUrl string? The URL used in the search request.
meta.pagination.currentPage number Current page number.
meta.pagination.perPage number Number of results per page.
meta.pagination.totalItemsCount number Total number of results found.
meta.pagination.totalPagesCount number Total number of pages available.
meta.pagination.nextPage number? Next page number, null if no more pages.
meta.pagination.previousPage number? Previous page number, null if on first page.

Response status codes

Status Description
200 The request was processed successfully.
400 Bad request. Invalid parameters provided.
401 Unauthorized. Authentication failed or missing credentials.
429 Too Many Requests. The server is rejecting requests due to excessive rate of requests. Please slow down and retry after some time.
500 Internal Server Error. An unexpected condition prevented the request from being fulfilled.

Personalizations

Get All Personalizations

Retrieve all personalizations for a specific page.

HTTP Request

GET https://api.instapage.com/v1/workspaces/{workspaceId}/pages/{pageId}/personalizations

curl "https://api.instapage.com/v1/workspaces/{workspaceId}/pages/{pageId}/personalizations" \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json"

Example of body response from request

{
  "data": [
    {
      "pageId": 9402,
      "personalizationId": "108b2b17-478d-4f8f-9059-003d44a89b39",
      "title": "example page",
      "publishStatus": "published",
      "createdAt": 1696332561,
      "url": "ip.example.com?108b2b17=003d44a89b39&id-param=example-page",
      "publishMethod": "customDomain",
      "isDefaultPersonalization": false,
      "isScheduled": false
    },
    {
      "pageId": 9399,
      "personalizationId": "18d22df0-7198-48ab-8301-9c110f71d667",
      "title": "default example page",
      "publishStatus": "published",
      "createdAt": 1692168365,
      "url": "ip.example.com",
      "publishMethod": "customDomain",
      "isDefaultPersonalization": true,
      "isScheduled": false
    }
  ],
  "meta": {
    "pagination": {
      "currentPage": 1,
      "perPage": 100,
      "totalItemsCount": 2,
      "totalPagesCount": 1,
      "nextPage": null,
      "previousPage": null
    }
  }
}
async function fetchPersonalizations(workspaceId, pageId, apiKey) {
    const url = `https://api.instapage.com/v1/workspaces/${workspaceId}/pages/${pageId}/personalizations`;

    const response = await fetch(url, {
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        },
    });

    if (!response.ok) {
        throw new Error(`Failed to fetch personalizations: ${response.statusText}`);
    }

    const data = await response.json();
    return data;
}
type Personalization = {
    pageId: number;
    personalizationId: string;
    title: string;
    publishStatus: 'published' | 'unpublished';
    createdAt: number;
    url: string | null;
    publishMethod: string;
    isDefaultPersonalization: boolean;
};

type PaginationMeta = {
    current_page: number;
    per_page: number;
    total_items_count: number;
    total_pages_count: number;
    next_page: number | null;
    previous_page: number | null;
};

type PersonalizationsResponse = {
    data: Personalization[];
    meta: {
        pagination: PaginationMeta;
    };
};

async function fetchPersonalizations(
    workspaceId: number,
    pageId: number,
    apiKey: string
): Promise<PersonalizationsResponse> {
    const url = `https://api.instapage.com/v1/workspaces/${workspaceId}/pages/${pageId}/personalizations`;

    const response = await fetch(url, {
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        },
    });

    if (!response.ok) {
        throw new Error(`Failed to fetch personalizations: ${response.statusText}`);
    }

    const data: PersonalizationsResponse = await response.json();
    return data;
}
<?php

declare(strict_types=1);

namespace InstapagePersonalizationsFetcher;

enum PublishStatus: string
{
    case Published = 'published';
    case Unpublished = 'unpublished';
}

readonly class Personalization
{
    public function __construct(
        public int $pageId,
        public string $personalizationId,
        public string $title,
        public PublishStatus $publishStatus,
        public int $createdAt,
        public ?string $url,
        public string $publishMethod,
        public bool $isDefaultPersonalization
    ) {}

    public function toArray(): array
    {
        return [
            'pageId' => $this->pageId,
            'personalizationId' => $this->personalizationId,
            'title' => $this->title,
            'publishStatus' => $this->publishStatus->value,
            'createdAt' => $this->createdAt,
            'url' => $this->url,
            'publishMethod' => $this->publishMethod,
            'isDefaultPersonalization' => $this->isDefaultPersonalization
        ];
    }

    public static function fromArray(array $data): self
    {
        return new self(
            $data['pageId'],
            $data['personalizationId'],
            $data['title'],
            PublishStatus::from($data['publishStatus']),
            $data['createdAt'],
            $data['url'] ?? null,
            $data['publishMethod'],
            $data['isDefaultPersonalization']
        );
    }
}

readonly class PaginationMeta
{
    public function __construct(
        public int $currentPage,
        public int $perPage,
        public int $totalItemsCount,
        public int $totalPagesCount,
        public ?int $nextPage,
        public ?int $previousPage
    ) {}

    public function toArray(): array
    {
        return [
            'current_page' => $this->currentPage,
            'per_page' => $this->perPage,
            'total_items_count' => $this->totalItemsCount,
            'total_pages_count' => $this->totalPagesCount,
            'next_page' => $this->nextPage,
            'previous_page' => $this->previousPage
        ];
    }

    public static function fromArray(array $data): self
    {
        return new self(
            $data['current_page'],
            $data['per_page'],
            $data['total_items_count'],
            $data['total_pages_count'],
            $data['next_page'],
            $data['previous_page']
        );
    }
}

class PersonalizationsResponse
{
    /**
     * @param Personalization[] $data
     */
    public function __construct(
        private array $data,
        private PaginationMeta $paginationMeta
    ) {}

    public function getData(): array
    {
        return $this->data;
    }

    public function getMeta(): PaginationMeta
    {
        return $this->paginationMeta;
    }
}

class PersonalizationsFetcher
{
    public function __construct(
        private string $baseUrl,
        private string $apiKey
    ) {}

    public function fetchPersonalizations(
        int $workspaceId,
        int $pageId
    ): PersonalizationsResponse {
        $url = sprintf(
            '%s/v1/workspaces/%d/pages/%d/personalizations',
            $this->baseUrl,
            $workspaceId,
            $pageId
        );

        $ch = curl_init($url);

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $this->apiKey,
                'Content-Type: application/json'
            ]
        ]);

        $responseBody = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if (curl_errno($ch)) {
            throw new \RuntimeException('CURL Error: ' . curl_error($ch));
        }

        curl_close($ch);

        if ($httpCode !== 200) {
            throw new \RuntimeException("Failed to fetch personalizations: HTTP $httpCode");
        }

        $responseData = json_decode($responseBody, true);

        return new PersonalizationsResponse(
            array_map(
                fn($personalizationData) => Personalization::fromArray($personalizationData), 
                $responseData['data']
            ),
            PaginationMeta::fromArray($responseData['meta']['pagination'])
        );
    }
}

// Example usage
try {
    $baseUrl = 'https://api.instapage.com';
    $apiKey = 'your_api_key_here';
    $workspaceId = 1234;
    $pageId = 5678;

    $fetcher = new PersonalizationsFetcher($baseUrl, $apiKey);

    $personalizationsResponse = $fetcher->fetchPersonalizations($workspaceId, $pageId);

    // Process personalizations
    foreach ($personalizationsResponse->getData() as $personalization) {
        // Do something with each personalization
        print_r($personalization->toArray());
    }

    // Access pagination metadata
    $paginationMeta = $personalizationsResponse->getMeta();
    print_r($paginationMeta->toArray());

} catch (\Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

Path Parameters

Parameter Type Description
workspaceId number The ID of the workspace
pageId number The ID of the page to retrieve personalizations for

Headers

Response JSON structure

JSON Path Type Description
data[].pageId number Unique identifier of the page.
data[].personalizationId string Unique identifier for the personalization experience.
data[].title string Title of the page.
data[].publishStatus string Current publish status of the page (e.g., published).
data[].createdAt number Creation timestamp of the page (UNIX format).
data[].url string URL where the page is published.
data[].publishMethod string Method used for publishing the page (e.g., customDomain).
data[].isDefaultPersonalization boolean Indicates whether this is the default personalization experience.
data[].isScheduled boolean Indicates whether the page is scheduled for publication.
meta.pagination.currentPage number Number of the current page of results.
meta.pagination.perPage number Number of items per page.
meta.pagination.totalItemsCount number Total number of items.
meta.pagination.totalPagesCount number Total number of pages.
meta.pagination.nextPage number? Number of the next page, or null if there is no next page.
meta.pagination.previousPage number? Number of the previous page, or null if there is no previous page.

This endpoint retrieves all personalizations for the specified page. The response includes detailed information about each personalization, such as its ID, title, publish status, and URL. The results are paginated, and you can use the pagination metadata to navigate through the pages of results if necessary.

Response status codes

Status Description
200 The request was processed successfully.
400 Bad request. Validation error — review input parameters.
401 Unauthorized. Authentication failed or missing credentials.
429 Too Many Requests. The server is rejecting requests due to excessive rate of requests. Please slow down and retry after some time.
500 Internal Server Error. An unexpected condition prevented the request from being fulfilled.

Analytics

Get statistical data

Retrieve statistical data related to pages and experiences in a bulk.

HTTP Request

POST https://api.instapage.com/v1/workspaces/:workspaceId/analytics

curl "https://api.instapage.com/v1/workspaces/$workspaceId/analytics" \
  -H "Authorization: Bearer $API_KEY"
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json' \
  --data '{
    "visited": 0,
    "pages": [
      20476657,
      10716956,
      10842011
    ],
    "timeframe": {
      "start": 0,
      "end": 1726150655561
    },
    "grouping": ["pageId"],
    "interval": "yearly"
  }'
async function fetchAnalytics(workspaceId, options, apiKey) {
  const url =`https://api.instapage.com/v1/workspaces/${workspaceId}/analytics`;
  const response = await fetch(url, {
    method: 'POST',
    body: JSON.stringify(options),
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${apiKey}`,
    },
  });

  if (!response.ok) {
    throw new Error(`Failed to fetch workspaces: ${response.statusText}`);
  }

  const data = await response.json();
  return data;
}
type AnalyticsFetchOptions = {
  pages: number[];
  interval: 'daily' | 'hourly' | 'monthly' | 'yearly';
  grouping?: ('pageId' | 'variationId')[];
  timeframe?: {
    start: number;
    end: number;
  };
  visited?: number;
  device?: 'any' | 'desktop' | 'mobile';
};

type AnalyticsFetchResponse = {
  data: {
    key: {
      pageId?: number;
      date?: number;
      variationId?: number;
    };
    visit: number;
    conversion: number;
    leads: number;
  }[];
};

async function fetchAnalytics(workspaceId: number, options: AnalyticsFetchOptions, apiKey: string) {
  const url =`https://api.instapage.com/v1/workspaces/${workspaceId}/analytics`;
  const response = await fetch(url, {
    method: 'POST',
    body: JSON.stringify(options),
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${apiKey}`,
    },
  });

  if (!response.ok) {
    throw new Error(`Failed to fetch workspaces: ${response.statusText}`);
  }

  const data = await response.json();
  return data as AnalyticsFetchResponse;
}
<?php

declare(strict_types=1);

namespace InstapageAnalytics;

class AnalyticsFetchOptions
{
    public function __construct(
        public readonly array $pages,
        public readonly string $interval,
        public readonly ?array $grouping = null,
        public readonly ?array $timeframe = null,
        public readonly ?int $visited = null,
        public readonly ?string $device = null
    ) {}

    public function toArray(): array
    {
        $options = [
            'pages' => $this->pages,
            'interval' => $this->interval,
        ];

        if ($this->grouping !== null) {
            $options['grouping'] = $this->grouping;
        }

        if ($this->timeframe !== null) {
            $options['timeframe'] = $this->timeframe;
        }

        if ($this->visited !== null) {
            $options['visited'] = $this->visited;
        }

        if ($this->device !== null) {
            $options['device'] = $this->device;
        }

        return $options;
    }
}

class AnalyticsFetchResponse
{
    public function __construct(
        public readonly array $data
    ) {}

    public static function fromArray(array $responseData): self
    {
        return new self($responseData);
    }
}

class InstapageAnalyticsFetcher
{

    public function __construct(
        private readonly string $baseUrl,
        private readonly string $apiKey
    ) {}

    public function fetchAnalytics(
        int $workspaceId, 
        AnalyticsFetchOptions $options
    ): AnalyticsFetchResponse {
        $url = sprintf(
            '%s/v1/workspaces/%d/analytics', 
            $this->baseUrl, 
            $workspaceId
        );

        $ch = curl_init($url);

        curl_setopt_array($ch, [
            CURLOPT_POST => true,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json',
                'Authorization: Bearer ' . $this->apiKey
            ],
            CURLOPT_POSTFIELDS => json_encode($options->toArray(), JSON_THROW_ON_ERROR)
        ]);

        $responseBody = curl_exec($ch);

        if ($responseBody === false) {
            throw new \RuntimeException('Curl request failed: ' . curl_error($ch));
        }

        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($httpCode < 200 || $httpCode >= 300) {
            throw new \RuntimeException(sprintf(
                'API request failed with status code %d: %s', 
                $httpCode, 
                $responseBody
            ));
        }

        $responseData = json_decode($responseBody, true, 512, JSON_THROW_ON_ERROR);
        return AnalyticsFetchResponse::fromArray($responseData);
    }
}

// Example usage
try {
    $baseUrl = 'https://api.instapage.com';
    $apiKey = 'your_api_key_here';
    $fetcher = new InstapageAnalyticsFetcher($apiKey, $baseUrl);

    $options = new AnalyticsFetchOptions(
        pages: [1, 2, 3],
        interval: 'daily',
        grouping: ['date'],
        timeframe: [
            'start' => time() - 30 * 24 * 60 * 60, // 30 days ago
            'end' => time()
        ]
    );

    $response = $fetcher->fetchAnalytics(123, $options);
    print_r($response->data);
} catch (\JsonException $e) {
    // Handle JSON encoding/decoding errors
    echo "JSON Error: " . $e->getMessage();
} catch (\RuntimeException $e) {
    // Handle API request errors
    echo "API Request Error: " . $e->getMessage();
}

The above request returns JSON structured like this:

{
    "data": [
        {
            "key": {
                "pageId": 10842011,
                "date": 1727275000
            },
            "visit": 42,
            "conversion": 5,
            "leads": 5
        },
        {
            "key": {
                "pageId": 10716956,
                "date": 1727276000
            },
            "visit": 1,
            "conversion": 1,
            "leads": 1
        },
        {
            "key": {
                "pageId": 10716956,
                "date": 1727277000
            },
            "visit": 1,
            "conversion": 0,
            "leads": 0
        },
        {
            "key": {
                "pageId": 10842011,
                "date": 1727278000
            },
            "visit": 181,
            "conversion": 0,
            "leads": 0
        }
    ]
}

The key depends on grouping used and will behave differently for different grouping requests.

Path Parameters

Parameter Type Description
workspaceId number Specifies which workspace to use.

Headers

Body Parameters

Content-type should be of type application/json.

JSON Path Type Default Description
pages number[] null Specifies the pages for which the API should return statistical data. Note: You can provide up to 100 page IDs at once.
interval string monthly Specifies the time interval for aggregating data. Options include daily, hourly, monthly, or yearly.
device string any Determines the device type filter. Can be set to any, desktop, or mobile visits.
timeframe.start number 0 Defines the starting timestamp (in seconds) for fetching data.
timeframe.end number 'current time' Defines the ending timestamp (in seconds) for the data retrieval period.
traffic string blended Specifies the type of traffic to include: blended, organic, or paid.
grouping string[] [] Defines additional grouping for the data. Options include pageId and variationId.
visited number null Filters data based on unique actions. A value of 1 includes only returning visitors; a value of 0 includes only unique actions.

Response JSON structure

JSON Path Type Description
data[].key Object Object containing unique identifiers. Structure varies based on the request.
data[].key.pageId number (optional) Page ID, part of the key, optional - reflects grouping of request.
data[].key.date number (optional) Date in UNIX timestamp (seconds), part of the key, optional - reflects grouping of request.
data[].key.variationId number (optional) Variation ID, part of the key, optional - reflects grouping of request.
data[].visit number Total number of visits associated with the key.
data[].conversion number Total number of conversions associated with the key.
data[].leads number Total number of leads associated with the key.

Response status codes

Status Description
200 The request was processed successfully.
400 Bad request. Validation error — review input parameters.
401 Unauthorized. Authentication failed or missing credentials.
403 Forbidden. The user does not have the necessary permissions.
404 Not Found. The requested resource could not be located.
429 Too Many Requests. The server is rejecting requests due to excessive rate of requests. Please slow down and retry after some time.
500 Internal Server Error. An unexpected condition prevented the request from being fulfilled.

Form Submissions

Form submissions refer to the data collected when a user successfully fills out and submits a form on your landing page.

Retrieve Form Submissions

Fetch form submission data from specified pages, with optional filtering by time range.

HTTP Request

POST https://api.instapage.com/v1/workspaces/{workspaceId}/submissions

curl "https://api.instapage.com/v1/workspaces/7068/submissions" \
  -H "Authorization: Bearer API_KEY" \
  -H "Content-Type: application/json" \
  --data '{"pages": [9371, 9370], "timeframe":  {
      "start": 1717259412,
      "end": 1727251907
      }
  }'
async function fetchSubmissions(workspaceId, pages, timerange, nextPageToken, apiKey) {
    const url = new URL(`https://api.instapage.com/v1/workspaces/${workspaceId}/submissions`);
    const response = await fetch(url, {
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        },
        method: 'POST',
        body: JSON.stringify({ pages, ...timerange ? { timerange } : null, nextPageToken })
    });

    if (!response.ok) {
        throw new Error(`Failed to fetch pages: ${response.statusText}`);
    }

    const data = await response.json();
    return data;
}
type Filters = {
    pages: number[];
    timerange?: {
        start: number;
        end: number;
    };
    nextPageToken?: string;
};

type Submission = {
  id: string;
  pageId: number;
  variationName: string;
  variationCustomName: string;
  createdAt: number;
  fields: Record<string, string>;
}


type SubmissionsResponse = {
    data: Submission[];
    meta: {
        nextPageToken: string | null;
        limit: number;
    };
};

async function fetchFormSubmissions(
    apiKey: string,
    workspaceId: number;
    filters: Options;
): Promise<SubmissionsResponse> {
    const url = new URL(`https://api.instapage.com/v1/workspaces/${workspaceId}/pages`);
    const json = JSON.stringify(filters);

    const response = await fetch(url.toString(), {
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        },
        method: 'POST',
        body: json,
    });

    if (!response.ok) {
        throw new Error(`Failed to fetch submissions: ${response.statusText}`);
    }

    const data: SubmissionsResponse = await response.json();
    return data;
}
<?php

declare(strict_types=1);

namespace InstapageSubmissionsFetcher;

readonly class ApiConfig
{
    public function __construct(
        public string $baseUrl,
        public string $apiKey,
        public int $workspaceId
    ) {}
}

readonly class Filters
{
    public function __construct(
        private array $pages,
        private ?array $timerange = null,
        private ?string $nextPageToken = null
    ) {}

    public function toArray(): array
    {
        $filters = ['pages' => $this->pages];

        if ($this->timerange !== null) {
            $filters['timerange'] = $this->timerange;
        }

        if ($this->nextPageToken !== null) {
            $filters['nextPageToken'] = $this->nextPageToken;
        }

        return $filters;
    }
}

class Submission
{
    public function __construct(
        private string $id,
        private int $pageId,
        private string $variationName,
        private string $variationCustomName,
        private int $createdAt,
        private array $fields
    ) {}

    public function toArray(): array
    {
        return [
            'id' => $this->id,
            'pageId' => $this->pageId,
            'variationName' => $this->variationName,
            'variationCustomName' => $this->variationCustomName,
            'createdAt' => $this->createdAt,
            'fields' => $this->fields
        ];
    }
}

class SubmissionsResponse
{
    public function __construct(
        private array $data,
        private ?string $nextPageToken,
        private int $limit
    ) {}

    public function getData(): array
    {
        return $this->data;
    }

    public function getNextPageToken(): ?string
    {
        return $this->nextPageToken;
    }

    public function getLimit(): int
    {
        return $this->limit;
    }
}

class SubmissionsFetcher
{
    public function __construct(private ApiConfig $apiConfig) {}

    public function fetchFormSubmissions(Filters $filters): SubmissionsResponse
    {
        $url = sprintf(
            '%s/v1/workspaces/%d/pages',
            $this->apiConfig->baseUrl,
            $this->apiConfig->workspaceId
        );

        $ch = curl_init($url);

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $this->apiConfig->apiKey,
                'Content-Type: application/json'
            ],
            CURLOPT_POSTFIELDS => json_encode($filters->toArray())
        ]);

        $responseBody = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if (curl_errno($ch)) {
            throw new \RuntimeException('CURL Error: ' . curl_error($ch));
        }

        curl_close($ch);

        if ($httpCode !== 200) {
            throw new \RuntimeException("API request failed with status code: $httpCode");
        }

        $responseData = json_decode($responseBody, true);

        return new SubmissionsResponse(
            array_map(fn($submissionData) => new Submission(
                $submissionData['id'],
                $submissionData['pageId'],
                $submissionData['variationName'],
                $submissionData['variationCustomName'],
                $submissionData['createdAt'],
                $submissionData['fields']
            ), $responseData['data']),
            $responseData['meta']['nextPageToken'] ?? null,
            $responseData['meta']['limit']
        );
    }
}

// Example usage
try {
   $baseUrl = 'https://api.instapage.com';
   $apiKey = 'your_api_key_here';
   $workspaceId = 1234;
   $apiConfig = new ApiConfig($baseUrl, $apiKey, $workspaceId);


    $fetcher = new SubmissionsFetcher($apiConfig);

    $filters = new Filters(
        pages: [1, 2, 3],
        timerange: ['start' => time() - 86400, 'end' => time()],
        nextPageToken: null
    );

    $submissionsResponse = $fetcher->fetchFormSubmissions($filters);

    // Process submissions
    foreach ($submissionsResponse->getData() as $submission) {
        // Do something with each submission
        print_r($submission->toArray());
    }

    // Check for next page
    $nextPageToken = $submissionsResponse->getNextPageToken();
} catch (\Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

The above request returns JSON structured like this:

{
    "meta": {
        "limit": 100,
        "nextPageToken": "6672e0f595fd7364f4c8973f"
    },
    "data": {
        "submissions": [
            {
                "id": "66797c440bf4f63b67fd1054",
                "pageId": 9371,
                "variationName": "A",
                "variationCustomName": "A",
                "createdAt": 1727261810,
                "fields": {
                    "form-field-1": "value-of-form",
                }
            },
            {
                "id": "66797c3e0bf4f63b67fd1053",
                "pageId": 9371,
                "variationName": "A",
                "variationCustomName": "A",
                "createdAt": 1727261811,
                "fields": {
                    "Email": "email@example.com",
                }
            },
            {
                "id": "66795e1323047c1af4cca224",
                "pageId": 9370,
                "variationName": "A",
                "variationCustomName": "A",
                "createdAt": 0,
                "fields": {
                    "Name": "xdxd",
                }
            },
            {
                "id": "6672e0f595fd7364f4c8973f",
                "pageId": 9370,
                "variationName": "A",
                "variationCustomName": "A",
                "createdAt": 1727261813,
                "fields": {
                    "Email": "customer1@example.com",
                }
            }
        ]
    }
}

Path Parameters

Parameter Type Description
workspaceId number The ID of the workspace to retrieve submissions for

Headers

Body Parameters

JSON Path Type Default Description
pages number[] [] A list of page IDs to filter form submissions. Note: You can provide up to 100 page IDs at once.
timeframe.start number null Defines the start of the time range for filtering leads, specified in seconds.
timeframe.end number null Defines the end of the time range for filtering leads, specified in seconds.
nextPageToken string null Token for pagination; retrieves the next set of form submissions when provided.

Response JSON structure

JSON Path Type Description
data[].id string Unique identifier for the submission.
data[].pageId number ID of the page related to the submission.
data[].variationName string Name of the variation used for the submission.
data[].variationCustomName string Custom name of the variation used for the submission.
data[].createdAt number Timestamp (in UNIX seconds) of when the submission was created.
data[].fields Object Key-value pairs representing submission fields.
meta.nextPageToken string? Token for fetching the next page of submissions, or null if there is no next page.
meta.limit number Maximum number of submissions returned per page.

This endpoint allows retrieval of form submissions from multiple pages in a single request. The data limit is capped at 100 submissions per page. To retrieve additional pages, use the nextPageToken.

When the number of retrieved submissions is less than the limit, an empty array is returned, or nextPageToken is null, it indicates that no further submissions are available from the endpoint.

Response status codes

Status Description
200 The request was processed successfully.
400 Bad request. Some filter parameters are most likely not valid.
401 Unauthorized. Authentication failed or missing credentials.
403 Forbidden. The user does not have the necessary permissions.
404 Not Found. The requested resource could not be located.
429 Too Many Requests. The server is rejecting requests due to excessive rate of requests. Please slow down and retry after some time.
500 Internal Server Error. An unexpected condition prevented the request from being fulfilled.

Experiments

Get All Experiments

Retrieve all experiments for a specific workspace with optional filtering by status.

HTTP Request

GET https://api.instapage.com/v1/workspaces/{workspaceId}/experiments

curl "https://api.instapage.com/v1/workspaces/$workspaceId/experiments?status[]=DRAFT&status[]=ENDED&page=1" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json"
async function fetchExperiments(workspaceId, statuses, page, apiKey) {
    const url = new URL(`https://api.instapage.com/v1/workspaces/${workspaceId}/experiments`);

    if (statuses && statuses.length) {
        statuses.forEach(status => url.searchParams.append('status[]', status));
    }
    if (page) {
        url.searchParams.append('page', page);
    }

    const response = await fetch(url, {
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        },
    });

    if (!response.ok) {
        throw new Error(`Failed to fetch experiments: ${response.statusText}`);
    }

    return await response.json();
}
type ExperimentType = 'Manual' | 'AI';
type ExperimentStatus = 'DRAFT' | 'RUNNING' | 'ENDED' | 'ARCHIVED';

type Experiment = {
    experimentId: number;
    experimentName: string;
    pageId: number;
    publishedPageUrl: string;
    experimentType: ExperimentType;
    experimentStatus: ExperimentStatus;
    createdAt: number;
    startedAt: number | null;
    endedAt: number | null;
    createdBy: number;
};

type PaginationMeta = {
    currentPage: number;
    perPage: number;
    totalItemsCount: number;
    totalPagesCount: number;
    nextPage: number | null;
    previousPage: number | null;
};

type ExperimentsResponse = {
    data: Experiment[];
    meta: {
        pagination: PaginationMeta;
    };
};

async function fetchExperiments(
    workspaceId: number,
    apiKey: string,
    statuses?: ExperimentStatus[],
    page?: number,
): Promise<ExperimentsResponse> {
    const url = new URL(`https://api.instapage.com/v1/workspaces/${workspaceId}/experiments`);

    if (statuses?.length) {
        statuses.forEach(status => url.searchParams.append('status[]', status));
    }
    if (page) {
        url.searchParams.append('page', page);
    }

    const response = await fetch(url.toString(), {
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        },
    });

    if (!response.ok) {
        throw new Error(`Failed to fetch experiments: ${response.statusText}`);
    }

    return await response.json();
}
<?php

declare(strict_types=1);

namespace InstapageExperimentsFetcher;

enum ExperimentType: string
{
    case MANUAL = 'Manual';
    case AI = 'AI';
}

enum ExperimentStatus: string
{
    case DRAFT = 'DRAFT';
    case RUNNING = 'RUNNING';
    case ENDED = 'ENDED';
    case ARCHIVED = 'ARCHIVED';
}

readonly class Experiment
{
    public function __construct(
        public int $experimentId,
        public string $name,
        public int $pageId,
        public string $publishedPageUrl,
        public ExperimentType $type,
        public ExperimentStatus $status,
        public int $createdAt,
        public int $createdBy,
        public ?int $startedAt,
        public ?int $endedAt
    ) {}

    public static function fromArray(array $data): self
    {
        return new self(
            $data['experimentId'],
            $data['experimentName'],
            $data['pageId'],
            $data['publishedPageUrl'],
            ExperimentType::from($data['experimentType']),
            ExperimentStatus::from($data['experimentStatus']),
            $data['createdAt'],
            $data['createdBy'],
            $data['startedAt'],
            $data['endedAt']
        );
    }
}

class ExperimentsFetcher
{
    public function __construct(
        private string $baseUrl,
        private string $apiKey
    ) {}

    /**
     * @param ExperimentStatus[] $statuses
     */
    public function fetchExperiments(
        int $workspaceId,
        array $statuses = [],
        int $page = 1
    ): array {
        $url = sprintf(
            '%s/v1/workspaces/%d/experiments',
            $this->baseUrl,
            $workspaceId
        );

        $queryParams = ['page' => $page];
        if (!empty($statuses)) {
            $queryParams['status'] = array_map(fn($status) => $status->value, $statuses);
        }

        $url .= '?' . http_build_query($queryParams, '', '&', PHP_QUERY_RFC3986);

        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $this->apiKey,
                'Content-Type: application/json'
            ]
        ]);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($httpCode !== 200) {
            throw new \RuntimeException("API request failed with status $httpCode");
        }

        $data = json_decode($response, true);
        return array_map(fn($item) => Experiment::fromArray($item), $data['data']);
    }
}

The above request returns JSON structured like this:

{
    "data": [
        {
            "experimentId": 8,
            "experimentName": "example-experiment-ab",
            "pageId": 9399,
            "publishedPageUrl": "example-page-ab.pagedemo.co",
            "experimentType": "Manual",
            "experimentStatus": "ENDED",
            "createdAt": 1695820734,
            "createdBy": 1234,
            "startedAt": 1696346707,
            "endedAt": 1728330460
        },
        {
            "experimentId": 11,
            "experimentName": "example-experiment-ai",
            "pageId": 9389,
            "publishedPageUrl": "example-page-ai.pagedemo.co",
            "experimentType": "AI",
            "experimentStatus": "DRAFT",
            "createdAt": 1695827954,
            "createdBy": 1234,
            "startedAt": null,
            "endedAt": null
        }
    ],
    "meta": {
        "pagination": {
            "currentPage": 1,
            "perPage": 100,
            "totalItemsCount": 2,
            "totalPagesCount": 1,
            "nextPage": null,
            "previousPage": null
        }
    }
}

Path Parameters

Parameter Type Description
workspaceId number The ID of the workspace to retrieve experiments for

Query Parameters

Parameter Type Default Description
status[] string[] [] Filter experiments by status. Can include multiple values: DRAFT, RUNNING, ENDED, or ARCHIVED
page number 1 Page number for pagination

Headers

Response JSON Structure

JSON Path Type Description
data[].experimentId number Unique identifier for the experiment
data[].experimentName string Name of the experiment
data[].pageId number ID of the page associated with the experiment
data[].publishedPageUrl string URL where the experiment page is published
data[].experimentType string Type of experiment: Manual or AI
data[].experimentStatus string Current status: DRAFT, RUNNING, ENDED, or ARCHIVED
data[].createdAt number Creation timestamp (UNIX format)
data[].createdBy number user ID of the experiment creator
data[].startedAt number? Start timestamp (UNIX format), null if not started
data[].endedAt number? End timestamp (UNIX format), null if not ended
meta.pagination.currentPage number Current page number
meta.pagination.perPage number Number of items per page
meta.pagination.totalItemsCount number Total number of items
meta.pagination.totalPagesCount number Total number of pages
meta.pagination.nextPage number? Next page number, null if no next page
meta.pagination.previousPage number? Previous page number, null if no previous page

Response Status Codes

Status Description
200 The request was processed successfully
400 Bad request - Invalid status value or pagination parameters
401 Unauthorized - Authentication failed or missing credentials
404 Not Found - The requested workspace was not found
429 Too Many Requests - The server is rejecting requests due to excessive rate of requests
500 Internal Server Error - An unexpected condition prevented the request from being fulfilled

Groups

Get All Groups

Retrieve all groups (folders) for a specific workspace.

HTTP Request

GET https://api.instapage.com/v1/workspaces/{workspaceId}/groups

curl "https://api.instapage.com/v1/workspaces/{workspaceId}/groups" \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json"
async function fetchGroups(workspaceId, apiKey) {
    const url = `https://api.instapage.com/v1/workspaces/${workspaceId}/groups`;

    const response = await fetch(url, {
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        },
    });

    if (!response.ok) {
        throw new Error(`Failed to fetch groups: ${response.statusText}`);
    }

    return await response.json();
}
type Group = {
    id: number;
    name: string;
    pages: number[];
};

type PaginationMeta = {
    currentPage: number;
    perPage: number;
    totalItemsCount: number;
    totalPagesCount: number;
    nextPage: number | null;
    previousPage: number | null;
};

type GroupsResponse = {
    data: Group[];
    meta: {
        workspaceId: number;
        pagination: PaginationMeta;
    };
};

async function fetchGroups(
    workspaceId: number,
    apiKey: string
): Promise<GroupsResponse> {
    const url = `https://api.instapage.com/v1/workspaces/${workspaceId}/groups`;

    const response = await fetch(url, {
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        },
    });

    if (!response.ok) {
        throw new Error(`Failed to fetch groups: ${response.statusText}`);
    }

    return await response.json();
}
<?php

declare(strict_types=1);

namespace InstapageGroupsFetcher;

readonly class Group
{
    public function __construct(
        public int $id,
        public string $name,
        public array $pages
    ) {}

    public static function fromArray(array $data): self
    {
        return new self(
            $data['id'],
            $data['name'],
            $data['pages'] ?? []
        );
    }

    public function toArray(): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'pages' => $this->pages
        ];
    }
}

readonly class PaginationMeta
{
    public function __construct(
        public int $currentPage,
        public int $perPage,
        public int $totalItemsCount,
        public int $totalPagesCount,
        public ?int $nextPage,
        public ?int $previousPage
    ) {}

    public static function fromArray(array $data): self
    {
        return new self(
            $data['currentPage'],
            $data['perPage'],
            $data['totalItemsCount'],
            $data['totalPagesCount'],
            $data['nextPage'],
            $data['previousPage']
        );
    }
}

class GroupsResponse
{
    /**
     * @param Group[] $data
     */
    public function __construct(
        private array $data,
        private int $workspaceId,
        private PaginationMeta $paginationMeta
    ) {}

    /**
     * @return Group[]
     */
    public function getData(): array
    {
        return $this->data;
    }

    public function getWorkspaceId(): int
    {
        return $this->workspaceId;
    }

    public function getPaginationMeta(): PaginationMeta
    {
        return $this->paginationMeta;
    }
}

class GroupsFetcher
{
    public function __construct(
        private string $baseUrl,
        private string $apiKey
    ) {}

    public function fetchGroups(int $workspaceId): GroupsResponse
    {
        $url = sprintf(
            '%s/v1/workspaces/%d/groups',
            $this->baseUrl,
            $workspaceId
        );

        $ch = curl_init($url);

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $this->apiKey,
                'Content-Type: application/json'
            ]
        ]);

        $responseBody = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if (curl_errno($ch)) {
            throw new \RuntimeException('CURL Error: ' . curl_error($ch));
        }

        curl_close($ch);

        if ($httpCode !== 200) {
            throw new \RuntimeException("Failed to fetch groups: HTTP $httpCode");
        }

        $responseData = json_decode($responseBody, true);

        return new GroupsResponse(
            array_map(
                fn($groupData) => Group::fromArray($groupData),
                $responseData['data']
            ),
            $responseData['meta']['workspaceId'],
            PaginationMeta::fromArray($responseData['meta']['pagination'])
        );
    }
}

// Example usage
try {
    $baseUrl = 'https://api.instapage.com';
    $apiKey = 'your_api_key_here';
    $workspaceId = 7068;

    $fetcher = new GroupsFetcher($baseUrl, $apiKey);

    $groupsResponse = $fetcher->fetchGroups($workspaceId);

    // Process groups
    foreach ($groupsResponse->getData() as $group) {
        // Do something with each group
        print_r($group->toArray());
    }

} catch (\Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

The above request returns JSON structured like this:

{
  "data": [
    {
      "id": 7356,
      "name": "Medusa Dragon",
      "pages": []
    },
    {
      "id": 7355,
      "name": "Speedball",
      "pages": []
    },
    {
      "id": 7340,
      "name": "testg",
      "pages": [
        9399
      ]
    }
  ],
  "meta": {
    "workspaceId": 7068,
    "pagination": {
      "currentPage": 1,
      "perPage": 100,
      "totalItemsCount": 16,
      "totalPagesCount": 1,
      "nextPage": null,
      "previousPage": null
    }
  }
}

Path Parameters

Parameter Type Description
workspaceId number The ID of the workspace to retrieve groups for

Headers

Query Parameters

Parameter Type Default Description
page number 1 Page number for pagination

Response JSON structure

JSON Path Type Description
data[].id number Unique identifier of the group
data[].name string Name of the group
data[].pages number[] Array of page IDs that belong to the group
meta.workspaceId number ID of the workspace the groups belong to
meta.pagination.currentPage number Current page number
meta.pagination.perPage number Number of items per page
meta.pagination.totalItemsCount number Total number of groups available
meta.pagination.totalPagesCount number Total number of pages
meta.pagination.nextPage number? Next page number (null if there is no next page)
meta.pagination.previousPage number? Previous page number (null if on first page)

Response status codes

Status Description
200 The request was processed successfully
400 Bad request. Validation error — review input parameters
401 Unauthorized. Authentication failed or missing credentials
403 Forbidden. The user does not have the necessary permissions
404 Not Found. The requested workspace could not be located
429 Too Many Requests. The server is rejecting requests due to excessive rate of requests. Please slow down and retry after some time
500 Internal Server Error. An unexpected condition prevented the request from being fulfilled

Create Group

Create a new group (folder) in a workspace.

HTTP Request

POST https://api.instapage.com/v1/workspaces/{workspaceId}/groups

curl -X POST "https://api.instapage.com/v1/workspaces/{workspaceId}/groups" \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "New Group"}'
async function createGroup(workspaceId, name, apiKey) {
    const url = `https://api.instapage.com/v1/workspaces/${workspaceId}/groups`;

    const response = await fetch(url, {
        method: 'POST',
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({ name })
    });

    if (response.statusCode !== 201) {
        throw new Error(`Failed to create group: ${response.statusText}`);
    }

    return await response.json();
}
type GroupResponse = {
    data: {
        id: number;
        name: string;
        pages: number[];
    };
    meta: {
        workspaceId: number;
    };
};

async function createGroup(
    workspaceId: number,
    name: string,
    apiKey: string
): Promise<GroupResponse> {
    const url = `https://api.instapage.com/v1/workspaces/${workspaceId}/groups`;

    const response = await fetch(url, {
        method: 'POST',
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({ name })
    });

    if (response.statusCode !== 201) {
        throw new Error(`Failed to create group: ${response.statusText}`);
    }

    return await response.json();
}
<?php

declare(strict_types=1);

namespace InstapageGroupCreator;

readonly class Group
{
    public function __construct(
        public int $id,
        public string $name,
        public array $pages
    ) {}

    public static function fromArray(array $data): self
    {
        return new self(
            $data['id'],
            $data['name'],
            $data['pages'] ?? []
        );
    }

    public function toArray(): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'pages' => $this->pages
        ];
    }
}

class GroupCreator
{
    public function __construct(
        private string $baseUrl,
        private string $apiKey
    ) {}

    public function createGroup(int $workspaceId, string $name): Group
    {
        $url = sprintf(
            '%s/v1/workspaces/%d/groups',
            $this->baseUrl,
            $workspaceId
        );

        $payload = json_encode(['name' => $name]);

        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => $payload,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $this->apiKey,
                'Content-Type: application/json'
            ]
        ]);

        $responseBody = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if (curl_errno($ch)) {
            throw new \RuntimeException('CURL Error: ' . curl_error($ch));
        }

        curl_close($ch);

        if ($httpCode !== 201) {
            throw new \RuntimeException("Failed to create group: HTTP $httpCode");
        }

        $responseData = json_decode($responseBody, true);
        return Group::fromArray($responseData['data']);
    }
}

// Example usage
try {
    $baseUrl = 'https://api.instapage.com';
    $apiKey = 'your_api_key_here';
    $workspaceId = 7068;
    $groupName = 'New Group';

    $creator = new GroupCreator($baseUrl, $apiKey);

    $newGroup = $creator->createGroup($workspaceId, $groupName);
    echo "Group created with ID: " . $newGroup->id . " and name: " . $newGroup->name;
} catch (\Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

The above request returns JSON structured like this:

{
  "data": {
    "id": 7357,
    "name": "New Group",
    "pages": []
  },
  "meta": {
    "workspaceId": 7068
  }
}

Path Parameters

Parameter Type Description
workspaceId number The ID of the workspace to create the group in

Headers

Request Body

Parameter Type Required Description
name string Yes The name of the new group

Response JSON structure

JSON Path Type Description
data.id number Unique identifier of the created group
data.name string Name of the group
data.pages number[] Array of page IDs (empty for new groups)
meta.workspaceId number ID of the workspace the group belongs to

Response status codes

Status Description
201 The request was processed successfully
400 Bad request. Invalid name or other parameter
401 Unauthorized. Authentication failed or missing credentials
403 Forbidden. The user does not have the necessary permissions
404 Not Found. The requested workspace could not be located
409 Conflict. A group with the same name already exists
413 Payload Too Large. Group name exceeds character limit
429 Too Many Requests. The server is rejecting requests due to excessive rate of requests. Please slow down and retry after some time
500 Internal Server Error. An unexpected condition prevented the request from being fulfilled

Update Group

Update an existing group (folder) in a workspace.

HTTP Request

PUT https://api.instapage.com/v1/workspaces/{workspaceId}/groups/{groupId}

curl -X PUT "https://api.instapage.com/v1/workspaces/{workspaceId}/groups/{groupId}" \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Updated Group Name"}'
async function updateGroup(workspaceId, groupId, name, apiKey) {
    const url = `https://api.instapage.com/v1/workspaces/${workspaceId}/groups/${groupId}`;

    const response = await fetch(url, {
        method: 'PUT',
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({ name })
    });

    if (!response.ok) {
        throw new Error(`Failed to update group: ${response.statusText}`);
    }

    return response.status === 200;
}
async function updateGroup(
    workspaceId: number,
    groupId: number,
    name: string,
    apiKey: string
): Promise<boolean> {
    const url = `https://api.instapage.com/v1/workspaces/${workspaceId}/groups/${groupId}`;

    const response = await fetch(url, {
        method: 'PUT',
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({ name })
    });

    if (!response.ok) {
        throw new Error(`Failed to update group: ${response.statusText}`);
    }

    return response.status === 200;
}
<?php

declare(strict_types=1);

namespace InstapageGroupUpdater;

class GroupUpdater
{
    public function __construct(
        private string $baseUrl,
        private string $apiKey
    ) {}

    public function updateGroup(int $workspaceId, int $groupId, string $name): bool
    {
        $url = sprintf(
            '%s/v1/workspaces/%d/groups/%d',
            $this->baseUrl,
            $workspaceId,
            $groupId
        );

        $payload = json_encode(['name' => $name]);

        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CUSTOMREQUEST => 'PUT',
            CURLOPT_POSTFIELDS => $payload,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $this->apiKey,
                'Content-Type: application/json'
            ]
        ]);

        $responseBody = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if (curl_errno($ch)) {
            throw new \RuntimeException('CURL Error: ' . curl_error($ch));
        }

        curl_close($ch);

        if ($httpCode !== 200) {
            throw new \RuntimeException("Failed to update group: HTTP $httpCode");
        }

        return true;
    }
}

// Example usage
try {
    $baseUrl = 'https://api.instapage.com';
    $apiKey = 'your_api_key_here';
    $workspaceId = 7068;
    $groupId = 7357;
    $newName = 'Updated Group Name';

    $updater = new GroupUpdater($baseUrl, $apiKey);

    $result = $updater->updateGroup($workspaceId, $groupId, $newName);
    if ($result) {
        echo "Group updated successfully.";
    }
} catch (\Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

Path Parameters

Parameter Type Description
workspaceId number The ID of the workspace containing the group
groupId number The ID of the group to update

Headers

Request Body

Parameter Type Required Description
name string Yes New name for the group

Response status codes

Status Description
200 The request was processed successfully
400 Bad request. Invalid name or other parameter
401 Unauthorized. Authentication failed or missing credentials
403 Forbidden. The user does not have the necessary permissions
404 Not Found. The group or workspace could not be located
409 Conflict. A group with the same name already exists
413 Payload Too Large. Group name exceeds character limit
429 Too Many Requests. The server is rejecting requests due to excessive rate of requests. Please slow down and retry after some time
500 Internal Server Error. An unexpected condition prevented the request from being fulfilled

Delete Group

Delete a group (folder) from a workspace.

HTTP Request

DELETE https://api.instapage.com/v1/workspaces/{workspaceId}/groups/{groupId}

curl -X DELETE "https://api.instapage.com/v1/workspaces/{workspaceId}/groups/{groupId}" \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json"
async function deleteGroup(workspaceId, groupId, apiKey) {
    const url = `https://api.instapage.com/v1/workspaces/${workspaceId}/groups/${groupId}`;

    const response = await fetch(url, {
        method: 'DELETE',
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        }
    });

    if (!response.ok) {
        throw new Error(`Failed to delete group: ${response.statusText}`);
    }

    return response.status === 200;
}
async function deleteGroup(
    workspaceId: number,
    groupId: number,
    apiKey: string
): Promise<boolean> {
    const url = `https://api.instapage.com/v1/workspaces/${workspaceId}/groups/${groupId}`;

    const response = await fetch(url, {
        method: 'DELETE',
        headers: {
            'Authorization': `Bearer ${apiKey}`,
            'Content-Type': 'application/json'
        }
    });

    if (!response.ok) {
        throw new Error(`Failed to delete group: ${response.statusText}`);
    }

    return response.status === 200;
}
<?php

declare(strict_types=1);

namespace InstapageGroupDeleter;

class GroupDeleter
{
    public function __construct(
        private string $baseUrl,
        private string $apiKey
    ) {}

    public function deleteGroup(int $workspaceId, int $groupId): bool
    {
        $url = sprintf(
            '%s/v1/workspaces/%d/groups/%d',
            $this->baseUrl,
            $workspaceId,
            $groupId
        );

        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CUSTOMREQUEST => 'DELETE',
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $this->apiKey,
                'Content-Type: 'application/json'
            ]
        ]);

        $responseBody = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if (curl_errno($ch)) {
            throw new \RuntimeException('CURL Error: ' . curl_error($ch));
        }

        curl_close($ch);

        if ($httpCode !== 200) {
            throw new \RuntimeException("Failed to delete group: HTTP $httpCode");
        }

        return true;
    }
}

// Example usage
try {
    $baseUrl = 'https://api.instapage.com';
    $apiKey = 'your_api_key_here';
    $workspaceId = 7068;
    $groupId = 7357;

    $deleter = new GroupDeleter($baseUrl, $apiKey);

    $result = $deleter->deleteGroup($workspaceId, $groupId);
    if ($result) {
        echo "Group deleted successfully.";
    }
} catch (\Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

Path Parameters

Parameter Type Description
workspaceId number The ID of the workspace containing the group
groupId number The ID of the group to delete

Headers

Response status codes

Status Description
200 The request was processed successfully and the group was deleted
400 Bad request. Group contains pages and cannot be deleted
401 Unauthorized. Authentication failed or missing credentials
403 Forbidden. The user does not have the necessary permissions
404 Not Found. The group or workspace could not be located
429 Too Many Requests. The server is rejecting requests due to excessive rate of requests. Please slow down and retry after some time
500 Internal Server Error. An unexpected condition prevented the request from being fulfilled

Instapage API Examples

This document provides examples of how to interact with the Instapage API using different programming languages. Each example demonstrates how to fetch workspaces, pages, form submissions, and analytics data from Instapage.

Table of Contents

  1. Node.js TypeScript Example
  2. Node.js JavaScript Example
  3. PHP Example

Node.js TypeScript Example

node -v # Should be v22.9.0
npm -v # Should be 10.8.3
node --experimental-strip-types example.ts # Replace example.ts with your file name
import fs from 'fs';
import { finished } from 'stream/promises';
import https from 'https';

class InstapageAPI {
    constructor(token) {
        this.token = token;
        this.baseURL = 'https://api.instapage.com/v1';
    }

    getAllWorkspaces() {
        return this.request('/workspaces');
    }

    request(endpoint, method, data) {
        method = method || 'GET';
        const url = this.baseURL + endpoint;
        const options = {
            method: method,
            headers: {
                'Authorization': 'Bearer ' + this.token,
                'Content-Type': 'application/json'
            }
        };

        return new Promise((resolve, reject) => {
            const req = https.request(url, options, (res) => {
                let responseBody = '';
                res.on('data', (chunk) => {
                    responseBody += chunk;
                });
                res.on('end', () => {
                    if (res.statusCode >= 200 && res.statusCode < 300) {
                        resolve(JSON.parse(responseBody));
                    } else {
                        reject(new Error('HTTP Error: ' + res.statusCode + ', URL: ' + url + ', RESPONSE: ' + responseBody));
                    }
                });
            });

            req.on('error', (error) => {
                reject(new Error('Request error: ' + error.message));
            });

            if (method === 'POST' && data) {
                req.write(JSON.stringify(data));
            }

            req.end();
        });
    }

    getAllPages(workspaceId) {
        return this.request('/workspaces/' + workspaceId + '/pages');
    }

    getFormSubmissions(workspaceId, pageIds) {
        const self = this;
        return new Promise((resolve, reject) => {
            let results = [];
            const maxOfRounds = Math.ceil(pageIds.length / 100);
            let currentRound = 0;

            function processRound() {
                if (currentRound >= maxOfRounds) {
                    resolve(results);
                    return;
                }

                const selectedPageIds = pageIds.slice(currentRound * 100, (currentRound + 1) * 100);
                const data = {
                    pages: selectedPageIds,
                    timeframe: {
                        start: Math.floor(Date.now() / 1000) - 30 * 24 * 60 * 60,
                        end: Math.floor(Date.now() / 1000)
                    }
                };

                self.request('/workspaces/' + workspaceId + '/submissions', 'POST', data)
                    .then(function(response) {
                        results = results.concat(response.data.submissions);
                        currentRound++;
                        processRound();
                    })
                    .catch(reject);
            }

            processRound();
        });
    }

    getAnalytics(workspaceId, pageIds) {
        const self = this;
        return new Promise((resolve, reject) => {
            let results = [];
            const maxOfRounds = Math.ceil(pageIds.length / 100);
            let currentRound = 0;

            function processRound() {
                if (currentRound >= maxOfRounds) {
                    resolve(results);
                    return;
                }

                const selectedPageIds = pageIds.slice(currentRound * 100, (currentRound + 1) * 100);
                const data = {
                    pages: selectedPageIds,
                    interval: 'daily',
                    timeframe: {
                        start: Math.floor(Date.now() / 1000) - 30 * 24 * 60 * 60,
                        end: Math.floor(Date.now() / 1000)
                    },
                    grouping: ['pageId']
                };

                self.request('/workspaces/' + workspaceId + '/analytics', 'POST', data)
                    .then(function(response) {
                        results = results.concat(response.data);
                        currentRound++;
                        processRound();
                    })
                    .catch(reject);
            }

            processRound();
        });
    }
}

function createCsv(filename, data, headers) {
    return new Promise((resolve, reject) => {
        const csvContent = [
            headers.join(','),
            ...data.map(row => row.map(String).join(','))
        ].join('\n');

        fs.writeFile(filename, csvContent, function(err) {
            if (err) {
                reject(err);
            } else {
                console.log('CSV file "' + filename + '" created successfully.');
                resolve();
            }
        });
    });
}

function main() {
    const token = ''; // Replace with your actual API token
    const api = new InstapageAPI(token);

    api.getAllWorkspaces()
        .then(function(response) {
            const workspaces = response.data;
            console.log('Found ' + workspaces.length + ' workspaces');

            const allLeads = [];
            const allAnalytics = [];

            function processWorkspace(index) {
                if (index >= workspaces.length) {
                    return Promise.all([
                        createCsv('leads.csv', allLeads, ['Workspace ID', 'Workspace Name', 'Page ID', 'Submission ID', 'Created At', 'Fields']),
                        createCsv('analytics.csv', allAnalytics, ['Workspace ID', 'Workspace Name', 'Page ID', 'Date', 'Visits', 'Conversions', 'Leads'])
                    ]);
                }

                const workspace = workspaces[index];
                console.log('Processing workspace: ' + workspace.workspaceName + ' (ID: ' + workspace.workspaceId + ')');

                return api.getAllPages(workspace.workspaceId)
                    .then(function(response) {
                        const pages = response.data;
                        console.log('Found ' + pages.length + ' pages in workspace ' + workspace.workspaceName);

                        const pageIds = pages.map(function(page) { return page.id; });

                        return Promise.all([
                            api.getFormSubmissions(workspace.workspaceId, pageIds),
                            api.getAnalytics(workspace.workspaceId, pageIds)
                        ]);
                    })
                    .then(function([submissions, analytics]) {
                        submissions.forEach(function(submission) {
                            allLeads.push([
                                workspace.workspaceId,
                                workspace.workspaceName,
                                submission.pageId,
                                submission.id,
                                submission.createdAt,
                                JSON.stringify(submission.fields)
                            ]);
                        });

                        analytics.forEach(function(analytic) {
                            allAnalytics.push([
                                workspace.workspaceId,
                                workspace.workspaceName,
                                analytic.key.pageId,
                                analytic.key.date,
                                analytic.visit,
                                analytic.conversion,
                                analytic.leads
                            ]);
                        });

                        return processWorkspace(index + 1);
                    });
            }

            return processWorkspace(0);
        })
        .then(function() {
            console.log('All data processed successfully.');
        })
        .catch(function(error) {
            console.error('An error occurred:', error.message);
        });
}

main();

Code Overview

This example uses TypeScript with Node.js version 22.9.0. It demonstrates how to:

  1. Authenticate with the Instapage API
  2. Fetch all workspaces
  3. For each workspace, fetch all pages
  4. Get form submissions for each page
  5. Get analytics data for each page
  6. Export the collected data to CSV files

Key Components

Endpoints Used

  1. /workspaces: GET request to fetch all workspaces
  2. /workspaces/{workspaceId}/pages: GET request to fetch all pages in a workspace
  3. /workspaces/{workspaceId}/submissions: POST request to fetch form submissions
  4. /workspaces/{workspaceId}/analytics: POST request to fetch analytics data

Results

The script generates two CSV files: 1. leads.csv: Contains form submission data 2. analytics.csv: Contains analytics data for each page

Node.js JavaScript Example

node -v # Should be v22.9.0
npm -v # Should be 10.8.3
node example.js # Replace example.js with your file name
const fs = require('fs');
const https = require('https');

class InstapageAPI {
    constructor(token) {
        this.token = token;
        this.baseURL = 'https://api.instapage.com/v1';
    }

    getAllWorkspaces() {
        return this.request('/workspaces');
    }

    request(endpoint, method, data) {
        method = method || 'GET';
        const url = this.baseURL + endpoint;
        const options = {
            method: method,
            headers: {
                'Authorization': 'Bearer ' + this.token,
                'Content-Type': 'application/json'
            }
        };

        return new Promise((resolve, reject) => {
            const req = https.request(url, options, (res) => {
                let responseBody = '';
                res.on('data', (chunk) => {
                    responseBody += chunk;
                });
                res.on('end', () => {
                    if (res.statusCode >= 200 && res.statusCode < 300) {
                        resolve(JSON.parse(responseBody));
                    } else {
                        reject(new Error('HTTP Error: ' + res.statusCode + ', URL: ' + url + ', RESPONSE: ' + responseBody));
                    }
                });
            });

            req.on('error', (error) => {
                reject(new Error('Request error: ' + error.message));
            });

            if (method === 'POST' && data) {
                req.write(JSON.stringify(data));
            }

            req.end();
        });
    }

    getAllPages(workspaceId) {
        return this.request('/workspaces/' + workspaceId + '/pages');
    }

    getFormSubmissions(workspaceId, pageIds) {
        const self = this;
        return new Promise((resolve, reject) => {
            let results = [];
            const maxOfRounds = Math.ceil(pageIds.length / 100);
            let currentRound = 0;

            function processRound() {
                if (currentRound >= maxOfRounds) {
                    resolve(results);
                    return;
                }

                const selectedPageIds = pageIds.slice(currentRound * 100, (currentRound + 1) * 100);
                const data = {
                    pages: selectedPageIds,
                    timeframe: {
                        start: Math.floor(Date.now() / 1000) - 30 * 24 * 60 * 60,
                        end: Math.floor(Date.now() / 1000)
                    }
                };

                self.request('/workspaces/' + workspaceId + '/submissions', 'POST', data)
                    .then(function(response) {
                        results = results.concat(response.data.submissions);
                        currentRound++;
                        processRound();
                    })
                    .catch(reject);
            }

            processRound();
        });
    }

    getAnalytics(workspaceId, pageIds) {
        const self = this;
        return new Promise((resolve, reject) => {
            let results = [];
            const maxOfRounds = Math.ceil(pageIds.length / 100);
            let currentRound = 0;

            function processRound() {
                if (currentRound >= maxOfRounds) {
                    resolve(results);
                    return;
                }

                const selectedPageIds = pageIds.slice(currentRound * 100, (currentRound + 1) * 100);
                const data = {
                    pages: selectedPageIds,
                    interval: 'daily',
                    timeframe: {
                        start: Math.floor(Date.now() / 1000) - 30 * 24 * 60 * 60,
                        end: Math.floor(Date.now() / 1000)
                    },
                    grouping: ['pageId']
                };

                self.request('/workspaces/' + workspaceId + '/analytics', 'POST', data)
                    .then(function(response) {
                        results = results.concat(response.data);
                        currentRound++;
                        processRound();
                    })
                    .catch(reject);
            }

            processRound();
        });
    }
}

function createCsv(filename, data, headers) {
    return new Promise((resolve, reject) => {
        const csvContent = [
            headers.join(','),
            ...data.map(row => row.map(String).join(','))
        ].join('\n');

        fs.writeFile(filename, csvContent, function(err) {
            if (err) {
                reject(err);
            } else {
                console.log('CSV file "' + filename + '" created successfully.');
                resolve();
            }
        });
    });
}

function main() {
    const token = ''; // Replace with your actual API token
    const api = new InstapageAPI(token);

    api.getAllWorkspaces()
        .then(function(response) {
            const workspaces = response.data;
            console.log('Found ' + workspaces.length + ' workspaces');

            const allLeads = [];
            const allAnalytics = [];

            function processWorkspace(index) {
                if (index >= workspaces.length) {
                    return Promise.all([
                        createCsv('leads.csv', allLeads, ['Workspace ID', 'Workspace Name', 'Page ID', 'Submission ID', 'Created At', 'Fields']),
                        createCsv('analytics.csv', allAnalytics, ['Workspace ID', 'Workspace Name', 'Page ID', 'Date', 'Visits', 'Conversions', 'Leads'])
                    ]);
                }

                const workspace = workspaces[index];
                console.log('Processing workspace: ' + workspace.workspaceName + ' (ID: ' + workspace.workspaceId + ')');

                return api.getAllPages(workspace.workspaceId)
                    .then(function(response) {
                        const pages = response.data;
                        console.log('Found ' + pages.length + ' pages in workspace ' + workspace.workspaceName);

                        const pageIds = pages.map(function(page) { return page.id; });

                        return Promise.all([
                            api.getFormSubmissions(workspace.workspaceId, pageIds),
                            api.getAnalytics(workspace.workspaceId, pageIds)
                        ]);
                    })
                    .then(function(results) {
                        const submissions = results[0];
                        const analytics = results[1];

                        submissions.forEach(function(submission) {
                            allLeads.push([
                                workspace.workspaceId,
                                workspace.workspaceName,
                                submission.pageId,
                                submission.id,
                                submission.createdAt,
                                JSON.stringify(submission.fields)
                            ]);
                        });

                        analytics.forEach(function(analytic) {
                            allAnalytics.push([
                                workspace.workspaceId,
                                workspace.workspaceName,
                                analytic.key.pageId,
                                analytic.key.date,
                                analytic.visit,
                                analytic.conversion,
                                analytic.leads
                            ]);
                        });

                        return processWorkspace(index + 1);
                    });
            }

            return processWorkspace(0);
        })
        .then(function() {
            console.log('All data processed successfully.');
        })
        .catch(function(error) {
            console.error('An error occurred:', error.message);
        });
}

main();

This example is similar to the TypeScript version but uses plain JavaScript. The functionality and endpoints used are the same.

PHP Example

php -v # Should be PHP 7.4.33 (cli)
php example.php # Replace example.php with your file name
<?php

class InstapageAPI
{
    private $token;
    private $baseURL = 'https://api.instapage.com/v1';

    public function __construct($token)
    {
        $this->token = $token;
    }

    public function getAllWorkspaces()
    {
        $response = $this->request('/workspaces');
        return $response['data'];
    }

    private function request($endpoint, $method = 'GET', $data = null)
    {
        $url = $this->baseURL . $endpoint;
        $headers = [
            'Authorization: Bearer ' . $this->token,
            'Content-Type: application/json'
        ];

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

        if ($method === 'POST') {
            curl_setopt($ch, CURLOPT_POST, true);
            if ($data) {
                curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
            }
        }

        $response = curl_exec($ch);

        if (curl_errno($ch)) {
            throw new Exception('Curl error: ' . curl_error($ch));
        }

        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($httpCode >= 200 && $httpCode < 300) {
            return json_decode($response, true);
        } else {
            throw new Exception("HTTP Error: $httpCode, URL: $url, RESPONSE: $response");
        }
    }

    public function getAllPages($workspaceId)
    {
        $response = $this->request("/workspaces/$workspaceId/pages");
        return $response['data'];
    }

    public function getFormSubmissions($workspaceId, $pageIds)
    {
        $results = [];
        $currentRound = 0;
        $maxOfRounds = ceil(count($pageIds) / 100);
        while ($currentRound < $maxOfRounds) {
            $selectedPageIds = array_slice($pageIds, $currentRound * 100, 100);
            $data = [
                'pages' => $selectedPageIds,
                'timeframe' => [
                    'start' => strtotime('-30 days'),
                    'end' => time()
                ]
            ];
            $response = $this->request("/workspaces/$workspaceId/submissions", 'POST', $data);
            $results = [...$results, ...$response['data']['submissions']];
            $currentRound += 1;
        }

        return $results;
    }

    public function getAnalytics($workspaceId, $pageIds)
    {
        $results = [];
        $currentRound = 0;
        $maxOfRounds = ceil(count($pageIds) / 100);
        while ($currentRound < $maxOfRounds) {
            $selectedPageIds = array_slice($pageIds, $currentRound * 100, 100);
            $data = [
                'pages' => $selectedPageIds,
                'interval' => 'daily',
                'timeframe' => [
                    'start' => strtotime('-30 days'),
                    'end' => time()
                ],
                'grouping' => ['pageId']
            ];
            $response = $this->request("/workspaces/$workspaceId/analytics", 'POST', $data);
            $results = [...$results, ...$response['data']];
            $currentRound += 1;
        }
        return $results;
    }
}

function createCsv($filename, $data, $headers)
{
    $fp = fopen($filename, 'w');
    fputcsv($fp, $headers);
    foreach ($data as $row) {
        fputcsv($fp, $row);
    }
    fclose($fp);
    echo "CSV file '$filename' created successfully.\n";
}

function main()
{
    $token = ''; // Replace with your actual API token
    $api = new InstapageAPI($token);

    try {
        $workspaces = $api->getAllWorkspaces();
        echo "Found " . count($workspaces) . " workspaces\n";

        $allLeads = [];
        $allAnalytics = [];

        foreach ($workspaces as $workspace) {
            echo "Processing workspace: {$workspace['workspaceName']} (ID: {$workspace['workspaceId']})\n";
            $pages = $api->getAllPages($workspace['workspaceId']);
            echo "Found " . count($pages) . " pages in workspace {$workspace['workspaceName']}\n";

            $pageIds = array_column($pages, 'id');

            // Fetch and process leads
            $submissions = $api->getFormSubmissions($workspace['workspaceId'], $pageIds);
            foreach ($submissions as $submission) {
                $allLeads[] = [
                    $workspace['workspaceId'],
                    $workspace['workspaceName'],
                    $submission['pageId'],
                    $submission['id'],
                    $submission['createdAt'],
                    json_encode($submission['fields'])
                ];
            }

            // Fetch and process analytics
            $analytics = $api->getAnalytics($workspace['workspaceId'], $pageIds);
            foreach ($analytics as $analytic) {
                $allAnalytics[] = [
                    $workspace['workspaceId'],
                    $workspace['workspaceName'],
                    $analytic['key']['pageId'],
                    $analytic['key']['date'],
                    $analytic['visit'],
                    $analytic['conversion'],
                    $analytic['leads']
                ];
            }
        }

        // Create CSV for leads
        createCsv('leads.csv', $allLeads, ['Workspace ID', 'Workspace Name', 'Page ID', 'Submission ID', 'Created At', 'Fields']);

        // Create CSV for analytics
        createCsv('analytics.csv', $allAnalytics, ['Workspace ID', 'Workspace Name', 'Page ID', 'Date', 'Visits', 'Conversions', 'Leads']);

    } catch (Exception $e) {
        echo "An error occurred: " . $e->getMessage() . "\n";
    }
}

main();

Code Overview

This example uses PHP 7.4.33 and demonstrates the same functionality as the Node.js examples.

Key Differences

Conclusion

These examples demonstrate how to interact with the Instapage API to collect workspace, page, form submission, and analytics data. The process is similar across all three implementations (TypeScript, JavaScript, and PHP), with the main differences being in language-specific syntax and HTTP request handling.

Remember to replace the empty token string with your actual Instapage API token before running any of these scripts. Also, ensure you have the necessary permissions to access the data you're requesting through the API.