# 360° project
Source: https://viewerdocs.planpoint.io/360
This new feature allows you to create a 360º outlook of your project’s environment and enhance your user‘s experience. Please note you need more than one rendering or photo of your project to enable this feature.
**Change the icon** You can change the 360º icon to any SVG file of your choice. This allows for different experiences, like switching levels, changing buildings, etc. Please read below.
Access the configuration module within your project dashboard and navigate to the **Exterior** tab.

Arrange the desired views in the preferred sequence for presentation within your project. Simply click on the **plus** button to incorporate various views into the display order.
**Important tip:** Upload your images in the desired order for display

After organizing the images, you need to draw the simple polygons on each floor of each render. Just click on **Draw** or **Redraw** and repeat this process until finished.

## Review and edit
You can navigate the different views just by clicking here:

## Changing the 360º icon
You can change Planpoint's default 360º icon to any SVG file. You can only upload one file. This option is available in Content > Exterior.
## Troubleshooting
Here's how to solve some common problems when setting up a 360º project.
Please try refreshing the page.
This feature is only available in Planpoint V2. Please go to your V2 dashboard.
# Allocations
Source: https://viewerdocs.planpoint.io/allocations
The allocation feature is a brand-new feature to Planpoint. It allows you to assign limited access to floors and units for preferred people, whether it is VIP brokers working on your project or even stakeholders.
By using this feature, you will be able to create a custom Planpoint with the attributed units for a specific person that will require a password in order to access it. Please view the video below for step-by-step guide:
**Now that you’ve watched the video, let’s dive deeper into the details. Below, you’ll find a step-by-step guide with images to help you better understand the process.**
Under the **Allocations** tab, you can allocate restricted access to floors and units for designated individuals, be it VIP brokers contributing to your project or key stakeholders. Utilizing this functionality enables you to generate a personalized Planpoint with designated units for a particular individual, requiring a password for access.
* Start by clicking + new allocation

* Then simply give a title for this allocation
* Specify a password
* Select the units you want this allocation to apply and save


* At the bottom of the page you can see all the allocations you have setup for this project

# Amenities and parking
Source: https://viewerdocs.planpoint.io/amenities-parkings
This new feature allows you to add amenities and parking spaces to your Planpoint.
Adding either amenities or parking spaces is very easy, simply follow these steps:
Go to your units module and add a unit.
Now, select the type of unit you wish to add. Choose between **Amenity** or **Parking**.
Go to the **Floors** tab and click on **Draw floorplan** on the desired units.
To incorporate images into your amenities, navigate to the **Units** tab. Find the desire unit and select the **Cover** button and upload the image you wish to use as the main one.
Following the addition of your cover image, you may include additional pictures by clicking the **Gallery** button.
Remember that you can always see your work-in-progress in the **[Style and Embed](https://viewerdocs.planpoint.io/preview-embed)** tab
# Analytics
Source: https://viewerdocs.planpoint.io/analytics
Track views, downloads, favourites and leads across your units, understand demand, and share the numbers as a PDF, spreadsheet or AI written summary
The **Analytics** module turns everything visitors do in your plan viewer into charts you can act on: which units get opened, which ones convert into leads, where your audience is, how a price change moved demand, and what buyers searched for before they ever clicked a unit.
You will find it in your dashboard sidebar under **Sales & Marketing → Analytics**. It works the same way for a single project, a group (multi-phase) and an enterprise, with a few extras that only apply to the bigger scopes.
## The headline numbers
Every Analytics page opens with five cards summarising the whole scope:
| Card | What it counts |
| - | - |
| **Total Units** | Units (or commercial spaces) currently in the scope |
| **Total Views** | Times a unit page was opened |
| **Downloads** | PDFs and other assets saved from a unit |
| **Favorites** | Units added to a visitor's shortlist |
| **Total Leads** | Information requests submitted against a unit |
Units you have excluded in the **Configuration** panel don't contribute views, downloads, favourites or leads to any chart, total or export.
## Choosing the period
Most tabs have a **Per Date** filter with four options:
* **All Time** — everything ever recorded
* **Last 30 Days**
* **Last Week**
* **Custom** — opens a calendar so you can pick any start and end date
Click **Custom**, click a start date, then click an end date, and the charts reload for that window. Unless you change it, the custom window is the previous calendar month, which is also the period used by the monthly PDF report.
## Filtering the charts
Depending on the tab, you also get:
* **Per Availability** — narrow to a status such as Available, Reserved or Sold. The exact options come from your own units.
* **Per Bedroom Type** — narrow to studios, 1 bedroom, 2 bedrooms and so on (residential projects).
* **Per Channel** — split **Web** traffic (your public embed) from **Superframe** traffic (an in‑office sales screen). This filter only appears once at least one Superframe visit has been recorded, so projects that never ran a sales-office screen don't see an empty split.
Filters stack: pick *Last 30 Days* + *Available* + *2 bedrooms* and every chart on the tab follows.
**Price impact** and **Also viewed** have no filters. Both are calculated over fixed windows across all recorded visits, so a date filter would suggest a narrowing that doesn't actually happen.
## Paging through big charts
Charts show **20 rows at a time**, sorted strongest first. Underneath you'll find **Previous** / **Next** buttons and a label such as `1–20 of 576`, so you always know where you are in the list. Exports and the PDF report are not paginated, they contain the full list.
## The tabs
Tabs appear in this order. Any tab that has nothing to show is hidden automatically rather than displayed empty.
### Unit
Bar charts ranking your individual units, with three sub-tabs: **Views**, **Downloads** and **Leads**. This is the fastest way to see your best and worst performing stock.
### Funnel
The **Conversion funnel** shows three stages, **Views → Downloads → Leads**, with each stage's total and its percentage of views (views themselves are always 100%). Use it to see where you lose people: plenty of views but almost no downloads is a very different problem from lots of downloads and no leads.
### Also viewed
"People who opened this unit also opened…". Pick a unit and see which other units share the most visitors. Great for spotting which plans compete with each other, and for suggesting a realistic second option when a buyer's first choice is gone.
This is built from an anonymous per-browser id. It never identifies a person. Before a visitor has opened at least two units, the tab remains visible with an empty state explaining what activity it needs.
### Bedroom types / Area
The same **Views / Downloads / Leads** breakdown, grouped by bedroom count. On commercial projects this tab is called **Area** instead and groups by size band: Under 500 sq ft, 500 – 1,000 sq ft, 1,000 – 2,500 sq ft, 2,500 – 5,000 sq ft and 5,000+ sq ft.
### Demand vs supply
Two views:
* **Comparison** — share of views (demand) against share of remaining inventory (supply), per bedroom type or area band. Where demand runs ahead of supply, you're likely underpriced or short on that type; the reverse suggests stock that needs help.
* **Remaining supply** — what's actually left, by bedroom type or area range.
Gap points are calculated as **supply share minus demand share**. A negative gap means demand is stronger than the available supply; a positive gap means supply is ahead of demand.
Sold and leased units are not counted as remaining supply.
### Price impact
For every recorded price change, this compares views in the **14 days before** against the **14 days after**, so you can see whether a reprice actually moved demand. The tooltip shows the old and new price, the change, and views and leads either side.
The tab remains visible before any price history has been recorded and explains that it is waiting for a change. A unit's very first price doesn't count as a change.
### Search
**Enterprise only.** What people typed into your enterprise searchbox, whether or not they clicked anything: **Bedrooms**, **Property type**, **Neighbourhood**, **Price range** and **Status**. This is genuine unmet demand, it tells you what buyers wanted before they saw what you actually have.
The tab remains visible before any search activity has been recorded and explains that it is waiting for visitors to use the enterprise searchbox.
### Geography
A map of approximate visitor locations, with sub-tabs for **Views**, **Downloads**, **Favorites** and **Leads**. Locations are derived from request metadata (city, region, country), never from a lead's form details.
When older activity predates location tracking, Analytics shows how many events have location data out of the full total. The map and ranking only include the located events, while the headline cards continue to include all activity.
The tab remains visible before location data is available and explains that locations will appear as new activity is recorded.
### Heatmaps
Your floorplans and site plans with the units shaded by attention: the more a unit was opened, the stronger it shows. Projects get a heatmap per floor (or per space on commercial projects), plus an overall "most popular floors" view. Groups and enterprises show the same thing nested per project.
## Filtering an enterprise by project
On an enterprise, a **Projects** panel sits at the top of Analytics, above the totals.
Every project in the enterprise starts selected, and the counter reads something like **12 of 12 selected**.
Projects work like tags: click one to drop it from the numbers, click it again to bring it back. The dashboard reloads and shows **Updating analytics...** while it recalculates.
As soon as at least one project is deselected, a **Select all** button appears to put you back to the full enterprise.
The selection is applied everywhere, not just on the charts: KPI totals, every tab, the spreadsheet and JSON exports, the PDF report and the AI summary all follow the projects you picked.
The **Search** tab shows an empty state while a subset of projects is selected. Searchbox queries are made across the whole enterprise before a visitor picks a project, so they can't honestly be attributed to individual projects. Select all projects to see search demand again.Scheduled monthly report emails always cover the full enterprise. The project selection applies to what you're looking at, and to reports you download or send yourself.
## AI Analytics assistant
At the bottom of the page, **AI Analytics assistant** turns whatever is currently in scope into a plain-language read of the numbers.
Click **Start the assistant** (it becomes **Regenerate summary** once a summary exists) and you get:
* A one line headline
* **Highlights** — what stands out
* **Watch out for** — risks, gaps and data caveats
* **Suggested next steps** — concrete actions
A few things worth knowing:
* Each new summary costs **one AI credit**. Regenerating a summary for data that hasn't changed is free, it's served from cache and clearly labelled as such.
* If generation fails, the credit is refunded automatically.
* Summaries respect your current scope: date range, and on an enterprise, the projects you selected.
* The assistant only receives the aggregated numbers behind the charts. It never receives your leads' names, emails, phone numbers or any other personal detail.
* The footer tells you which model produced the summary and whether it came from cache. It is a reading of your numbers, so always sense-check anything surprising against the charts.
## Reports and exports
The **Reports & exports** panel gives you three ways to take the numbers with you.
A designed, presentation-ready summary of the period, with the KPI totals, unit rankings, bedroom or area breakdowns, demand vs supply, leads and conversion, channels, geography, price impact, also viewed and search demand. Ideal for investors, owners and weekly sales meetings.
The current stats as an `.xlsx` workbook, split into sheets: Summary, Units, Bedroom Types, Area Ranges, Channels, Geography, Leads, By Floor, Price Changes, Price Impact, Also Viewed and Searches. Use it to pivot, sort and merge with your own CRM data.
The same data as a structured JSON payload, for developers feeding Planpoint numbers into another system or a BI tool.
## Configuration
The **Configuration** panel controls which traffic counts and who hears about it.
A comma separated list of IP addresses to ignore, for example `203.0.113.10, 198.51.100.4`. Use it to keep your own sales team, agency and office visits out of the numbers.
Click the button (it reads **None excluded** or **3 excluded**) to open the picker, search by unit name and tick anything that shouldn't be measured, such as test units, model suites or staff-only stock. Their activity is then left out of the charts, the totals and the exports.
A comma separated list of email addresses that should receive the PDF report each month. The send button next to the field emails the current report immediately, which is handy for testing the list or sharing an update mid-month.
## A note on privacy
Analytics is built on aggregated, anonymous behaviour. Visit counts, approximate locations from request metadata, and an anonymous per-browser id used only to work out which units were opened in the same session. Lead contact details live in the **Leads** module and are never mixed into the charts, the exports or anything sent to the AI assistant.
# Get Floors
Source: https://viewerdocs.planpoint.io/api-documentation/endpoint/floors/get
GET /floors
Fetch floors
# Get Floor
Source: https://viewerdocs.planpoint.io/api-documentation/endpoint/floors/id/get
GET /floors/{id}
Fetch a floor
# Update Floor
Source: https://viewerdocs.planpoint.io/api-documentation/endpoint/floors/id/patch
PATCH /floor/{id}
# Create Floor
Source: https://viewerdocs.planpoint.io/api-documentation/endpoint/floors/post
POST /floors
Create a new floor
# Get Groups
Source: https://viewerdocs.planpoint.io/api-documentation/endpoint/groups/get
GET /groups
# Get Group
Source: https://viewerdocs.planpoint.io/api-documentation/endpoint/groups/id/get
GET /groups/{id}
Fetch a group
# Update Group
Source: https://viewerdocs.planpoint.io/api-documentation/endpoint/groups/id/patch
PATCH /groups/{id}
Update an existing group by Id
# Create Group
Source: https://viewerdocs.planpoint.io/api-documentation/endpoint/groups/post
POST /groups
Create a new group
# Get Leads
Source: https://viewerdocs.planpoint.io/api-documentation/endpoint/leads/get
GET /leads
Fetch leads
# Get Projects
Source: https://viewerdocs.planpoint.io/api-documentation/endpoint/projects/get
GET /projects
Fetch projects
# Get Project
Source: https://viewerdocs.planpoint.io/api-documentation/endpoint/projects/id/get
GET /project/{id}
Fetch a project
# Update Project
Source: https://viewerdocs.planpoint.io/api-documentation/endpoint/projects/id/patch
PATCH /project/{id}
Update an existing project by Id
# Create Project
Source: https://viewerdocs.planpoint.io/api-documentation/endpoint/projects/post
POST /projects
Create a new project
# Get Units
Source: https://viewerdocs.planpoint.io/api-documentation/endpoint/units/get
GET /units
Fetch units
# Delete Unit
Source: https://viewerdocs.planpoint.io/api-documentation/endpoint/units/id/delete
DELETE /units/{id}
This can only be done by the logged in unit.
# Get Unit
Source: https://viewerdocs.planpoint.io/api-documentation/endpoint/units/id/get
GET /units/{id}
Fetch a unit
# Update Unit
Source: https://viewerdocs.planpoint.io/api-documentation/endpoint/units/id/patch
PATCH /units/{id}
Update an existing unit by Id
# Create Unit
Source: https://viewerdocs.planpoint.io/api-documentation/endpoint/units/post
POST /units
Create a new unit
# Login
Source: https://viewerdocs.planpoint.io/api-documentation/endpoint/user/login
POST /users/login
## Step-by-Step Guide: Planpoint Login API
### 1. **Prepare Your Request Body**
You'll need to send a JSON payload with the following fields:
* `username`: Your email address (required, must be valid email format)
* `password`: Your password
### 2. **Set Up the HTTP Request**
Configure a POST request with:
* **Method**: POST
* **URL**: `https://app.planpoint.io/api/users/login`
* **Content-Type**: `application/json`
### 3. **Standard Login Flow**
For regular user login, send this request body:
json
`{
"username": "your-email@example.com",
"password": "your-password"
}`
Example using cURL:
bash
`curl --request POST \ --url https://app.planpoint.io/api/users/login \ --header 'Content-Type: application/json' \ --data '{
"username": "your-email@example.com",
"password": "your-password"
}'`
### 4. **Handle the Response**
**Success Response (200):**
json
`{
"message": "Login successful",
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}`
The response includes:
* `access_token`: JWT token for authenticating future API requests
* HTTP-only cookies are automatically set in your browser:
* `planpoint`: Access token (expires in 1 day for regular users, 90 days for Zapier)
* `planpointRefresh`: Refresh token (expires in 7 days, not set for Zapier users)
**Error Responses:**
* **400**: Invalid request body (username not an email, etc.)
* **401**: User not found, incorrect credentials, or unauthorized
* **403**: Not allowed (for impersonation attempts)
* **405**: Method not allowed (if not using POST)
* **500**: Server error
### 5. **Use the Access Token**
For subsequent API requests, use the `access_token` from the response in your Authorization header:
bash
`Authorization: Bearer YOUR_ACCESS_TOKEN`
# Introduction to Planpoint API
Source: https://viewerdocs.planpoint.io/api-documentation/introduction
In this section, we will be exploring our public RESTful API.
If you're looking for more than simply communicating with Planpoint, you can look into our [SDK](/sdk-documentation/introduction).
Planpoint facilitates technological practices to help developers seamlessly integrate their project's data into other software.
Planpoint API is an advanced programming interface that allows your software to communicate with our services. Exposing our services through a RESTful API makes integrations with your application way easier and smoother.
In this section, we will be exploring our public RESTful API. We will explore how developers can make use of our API to create, view, and delete units and projects, through standardized REST requests.
## Sandbox Account for Developers
If you would like to test our API with demo projects in a sandbox account, please contact support and describe your project, who the end client is and what's the goal.
## Endpoints
The Planpoint API features endpoints for every common item of the Planpoint Viewer. This includes projects, groups, enterprises and units. Each of these items have dedicated endpoints that can be consumed by third party applications.
## Authorization
Planpoint API authorizes requests with a valid bearer token. A bearer token is an authorization token that must be included in the header of every request made to Planpoint API.
## Response Status Codes
Planpoint API response status is reflected in the status codes returned with each response. Here is a list of status codes with their corresponding meaning:
* 200 OK: Response Successful. The response body will contain relevant data.
* 400 Bad Request: The request was invalid. This can be caused by missing fields, etc.
* 401 Unauthorized: Authentication failed. Usually caused by invalid bearer tokens.
* 403 Forbidden: Authorization to resources failed. The user has a valid bearer token, but is not authorized to access requested data.
* 500 Internal Server Error: Unexpected error server-side.
## Fetch Projects
Returns all projects found in a namespace that a host has access to.
`POST
/api/projects/find`
```JavaScript JavaScript using Axios theme={null}
async function fetchProject() {
try {
const response = await axios({
method: 'POST',
headers: {
'content-type': 'application/json'
},
data: {
namespace: namespace,
hostName: hostName
},
url: '/api/projects/find'
})
setProject(response.data)
} catch (err) {
console.error(err)
}
}
```
## Fetch Groups
Returns all groups found in a namespace that a host has access to.
`POST
/api/groups/find`
```JavaScript JavaScript using Axios theme={null}
async function fetchGroup() {
try {
const response = await axios({
method: 'POST',
headers: {
'content-type': 'application/json',
},
data: {
namespace: namespace,
hostName: hostName
},
url: '/api/groups/find'
})
setGroup(response.data)
} catch (err) {
console.error(err)
}
}
```
## Fetch Enterprises
Returns all enterprises found in a namespace that a host has access to.
`POST
/api/enterprises/find`
```JavaScript JavaScript using Axios theme={null}
async function fetchEnterprise() {
try {
const response = await axios({
method: 'POST',
headers: {
'content-type': 'application/json',
},
data: {
namespace: namespace,
hostName: hostName
},
url: '/api/enterprises/find'
})
setEnterprise(response.data)
} catch (err) {
console.error(err)
}
}
```
# Checklist
Source: https://viewerdocs.planpoint.io/checklist
This checklist is designed to guide you through a successful Planpoint launch, from planning and preparation to execution.
### Cloud folder
The first thing you will need is a cloud folder in which you organize all the necessary content at the same place. You can then share this folder with your provider or with us.
### Property Images
You need one or many rendering(s) of your project. It cand also be a photo or many photos of your building. The required format is JPG. The maximum weight is 1MB, anything under is better. Images should not exceed 1000px horizontally.
* Use your best money-shot for this main image.
* If you have a multi-phase project, use a bird's eye-view of the project for the group image. [View a group project here.](https://www.planpoint.io/types/rentals)
* If you wish to use our [360° project feature](https://www.planpoint.io/new-releases/360-project), gather all the best shots from all around the building.
**PRO TIP:** Vertical images will look better than horizontal images, just like the one below:
### Floors
You also need all the floor plates for all floors of your building. Each of them need to be separated for each floor and saved in JPG format. Consider adding the following elements to provide a better experience for your clients:
* Compass
* Landscaping
* Parking area
* Streets and directions
* Natural features like rivers, mountains, etc.
* Design cleaned out of construction or architectural details
Here's a good example:
### Unit layouts
All unit layout plans must be created in two versions:
* **One JPG version** for the plan viewer. This is the first thing you see while looking at a specific unit.
* **One PDF version** for the download PDF button on every unit page.
When units span more than one floor, the **PDF** can contain multiple pages, but the **JPG** version of the same unit must be separated into multiple separate images - they will appear as a gallery.
### Unit list
You must have your project's unit list with all important information such as unit name, area, number of bedrooms, price, availability, occupancy dates, inclusions, etc.
**PRO TIP:** We provide an Excel [template that you can download](https://app.planpoint.io/assets/template.xlsx) and use as the basis for your unit list.
Please view the video below to understand the proper formatting to be used in your document:
### Optional content
Planpoint allows you to add images for each unit. Please resize your images to max 1800px horizontally and no more than 1MB per image - images that are compressed will load faster for your clients! We recommend using free tools such as [TinyJPG](https://tinyjpg.com) and [Squoosh](https://squoosh.app).
Here's some ideas of what you can display:
* interiors of units like kitchen, bathroom, dining room
* exterior views from the point of view of the unit
* project highlights
Planpoint allows you to add 3D tours for each unit in your project. There's two different technologies for this. The base 3D tour is the one you see below, which 3D artists can create in any typical rendering software as a '360 image'. It can also be a simple Matterport tour.
The second one is the [next-gen 3D tour](https://www.planpoint.io/new-releases/next-gen-3d-tours) which allows for dynamic choice of finishes, element selection and room measurements.
You can also include renderings or photos of your amenities such as the pool, the terrace, the interior courtyard and use our **Amenities** feature to showcase them.
## What kind of plan viewer are you creating?
It's important to take note of the various requirements for different types of plan viewer before going any further.
Condominium projects and new construction rental buildings.
Single-family home developments projects and pure land projects.
Existing multifamily buildings offering appartments for rent.
Retail, office and industrial properties for lease and sale.
# Collections
Source: https://viewerdocs.planpoint.io/collections
Group related units into curated collections that visitors can browse in the viewer
Collections let you organize units into groups such as **City Studios**, **Penthouses**, or **Investment Units**. When a project has collections, visitors first see the collection list and can open a collection to browse its assigned units.
Open your project, go to **Content**, and select the **Collections** tab. Click **+ New collection**, enter a name, and click **Create**.
Use a clear, unique name because it is shown to visitors and used to connect units to the collection.
Click **Assign units** beside the collection. Units already in the collection are selected when the panel opens. Keep the units that should remain, select or deselect a floor to change all of its units at once, or select and deselect individual units. Use **Select all** when the collection should contain every unit in the project, then click **Apply collection**.
Applying replaces the collection's membership with the units currently selected in the panel. Deselected units are removed from this collection. The collection name shown beneath a unit indicates its current assignment, and selecting a unit from another collection moves it automatically. To remove every unit, click **Clear**, then **Apply collection**.
Return to **Collections** and click **Edit** beside the collection. You can configure:
* **Name**: the title visitors see.
* **Link slug**: the final URL segment used for a pretty-path link, such as `city-studios` in `yoursite.com/pricelist/city-studios`.
* **Image**: the collection cover image. Upload a PNG or JPEG within the dashboard's file-size limit.
* **Message**: optional supporting text shown on the collection card.
* **Featured**: visually emphasizes the collection in the viewer.
Changes save as you make them. Click **Done** to close the panel.
Drag collection rows up or down to control their order in the viewer. The unit count beside each collection helps you confirm that assignments are connected.
Click **Copy link** to copy a URL that opens the viewer directly on that collection. For other linking options, see [Deep Linking to specific units](/link-units#linking-to-a-collection).
Open the project viewer. The collection cards appear before the unit list. Select a collection and confirm that it contains the expected units and that its image, message, and featured styling appear correctly.
Collection assignments use the collection name. If you rename a collection after assigning units, open **Assign units**, select the affected floors or units, and apply the renamed collection again. Before deleting a collection, reassign its units in bulk or clear them individually from the **Units** tab because deleting the collection does not clear their existing assignment.
## Managing collections
* **Assign units**: edit the complete collection membership by selecting or deselecting floors and individual units, then apply everything in one action.
* **Reorder**: drag a row to change where the collection appears.
* **Copy link**: copy a direct link to the collection.
* **Edit**: update its name, link slug, image, message, or featured status.
* **Delete**: permanently remove the collection. Only project owners and administrators can delete collections.
You can still change one unit at a time from its **Edit** panel in the [Units](/units) tab.
# Colors
Source: https://viewerdocs.planpoint.io/colors
The Color module allows you to customize the color palette of the plan viewer so it better reflects your brand and visual preferences. You can define colors for key interface elements, including the background of the viewer, hover interactions where floors and plans are highlighted, buttons and button text, general text, and unit status indicators such as available, reserved, sold, and featured.
Exterior shapes use the **Hover** color by default. To use the status colors on the exterior instead, enable **Availabilities** and **Use availability colors on exterior** under **Settings → Customization → Availabilities**. See [Exterior](/exterior#exterior-hover-colors) for how colors are selected when a floor contains units with different statuses.
All changes are applied immediately, allowing you to preview and fine-tune your styling in real time. Colors can be set using any HEX or RGB value, providing full flexibility and precision.
If you want to edit your color scheme, simply follow the instructions below:
Go to **Settings**. Under **Style & Embed**, select **Customize Style**.
Once there, select **Color Scheme**.
You can make use of transparency by using the transparency slider as you see in the video below. A slightly transparent color is preferable over a completely opaque one, as it will show some details about the building and floor plan.
# Conversion Tracking
Source: https://viewerdocs.planpoint.io/conversion-tracking
This page explains how to use Conversion Tracking for Planpoint.
### Here's a video guide:
### If you’re using Planpoint’s default Lead Gen Form
Additionally, you can also make use of UTM parameters to keep track of where specific leads are coming from.
You can use the **Redirect URL** to point to a thank you page on your website and Planpoint will dynamically add the specific UTM parameters that were present on the page when he filled up the form.
So, for example, let’s imagine you have the following setup:
* Your Planpoint Viewer is embedded at [www.project.com/plans](http://www.project.com/plans) and;
* IYour redirect page after the form is completed is [www.project.com/thank-you](http://www.project.com/thank-you);
* You’re running an advertising campaign that adds various UTMs such as `?utm_source=google` to the base URL;
* So, [www.project.com/plans](http://www.project.com/plans) becomes [www.project.com/plans?utm\_source=google](http://www.project.com/plans?utm_source=google) ;
* After the visitor fills up the form, he’s automatically redirected to [www.project.com/thank-you?utm\_source=google](http://www.project.com/thank-you?utm_source=google) where `?utm_source=google` was added dynamically.
# Custom buttons
Source: https://viewerdocs.planpoint.io/custom-buttons
The **Custom Button** feature allows you to add an almost infinite number of options to your units view, because it simply links to any given URL. You can also change the button text and icon.
### Here's a video guide:
# Custom CSS
Source: https://viewerdocs.planpoint.io/custom-css
Take full control of your viewer's styling with your own CSS, written and previewed live inside the style editor.
When the style editor's themes, colors and fonts aren't enough, you can write your own CSS. Your rules load **after** the default Planpoint styles, so you only need to write what you want to change.
Custom CSS is layered on top of the default theme — never publish a copy of the whole default stylesheet. If you do, your viewer freezes at that version of the design and stops picking up future product updates and fixes.
## Before you begin
* Your embed URLs need `?customCss=true` for the custom styles to load (see [Step 4](#step-4-add-the-url-parameter)).
* Nested elements must be targeted with wildcard selectors such as `[class*="unitTile"]` — plain class names won't work (see [Understanding CSS selectors](#understanding-css-selectors)).
***
## Video Guide for Visual Learners
***
## How to set up custom CSS
### Step 1: Open the CSS editor
1. Go to **Style & Embed** → **Style**
2. Click **Customize** to open the style editor
3. In the toolbar at the bottom of the preview, click the **`>` Custom CSS** button
The left sidebar turns into a code editor, and the preview on the right stays live.
The editor opens on a short comment block — an empty starting point that changes nothing until you write your first rule.
### Step 2: Write your rules
Type in the editor and the preview updates instantly — no upload, no reload.
* Pick a block from **Insert snippet** — Brand colours, Filter bar, Unit cards, Unit detail
* CTA buttons, Status badges, and more. Each one is pre-filled with the current default values, so you edit instead of starting from a blank page.
* Click **Select element**, then click anything in the preview. Planpoint works out the right selector for it, drops an empty rule into the editor and lists the element's current values as comments you can uncomment and edit. Press Esc to cancel. If the selector is already in your file, the cursor jumps to it instead.
* Use the **Desktop / Tablet / Mobile** buttons to check your styles at every breakpoint.
* Drag the sidebar's right edge to give the editor more room — the width is remembered.
* Collapse the sidebar (the **`‹`** button) for a full-width preview; your work is kept.
* Right-click an element in the preview and choose **Inspect** to find the selector you need.
* Click **View default theme** to read the current default stylesheet **for reference** — read it to find selectors, but don't paste it into the editor.
Add the **Brand colours** snippet first. It defines the variables the other snippets read, so one colour change carries through every block you add afterwards.
#### Available snippets
| Snippet | What it covers |
| - | - |
| **Brand colours** | `--pp-brand-*` variables every other snippet reads |
| **Typography** | Base font family and the price type scale |
| **Filter bar** | Filter wrapper background and dropdown toggles |
| **Unit cards (grid)** | Card radius, border and hover lift |
| **Unit list (table)** | Table headers and row hover |
| **Unit detail + CTA buttons** | Unit card, "Request info" buttons, shortlist button |
| **Status badges** | Available / sold / leased / reserved / on hold |
| **Portal header** | Header bar and its call-to-action buttons |
| **Floor plan canvas** | Canvas container and its loading placeholder |
| **Map points of interest** | Pins, popup cards and category pills |
| **Hide an element** | A `display: none` starting point |
The searchbox editor has its own set: shell, filters row, dropdown menus, search button, range sliders and chips.
### Step 3: Save and publish
Click **Save & publish** (or press ⌘/Ctrl + S). The status above the editor tells you where you stand: *Nothing overridden yet*, *Unsaved changes* or *Published*.
Publishing uploads your stylesheet and turns custom CSS on for this viewer — there's no separate toggle to flip anymore.
The links under the button cover everything else:
| Button | What it does |
| - | - |
| **View default theme** | Opens the default stylesheet in a new tab, as a reference |
| **Import .css** | Loads a `.css` file from your computer into the editor (max 1.5 MB) |
| **Download** | Saves the editor's current content as a `.css` file |
| **Published file** | Opens the stylesheet that's currently live |
| **Revert** | Discards unsaved changes and restores the published version |
| **Remove** | Stops using custom CSS on this viewer |
Every save uploads a new file, so your previous versions stay available — nothing is overwritten.
### Step 4: Add the URL parameter
Custom CSS only loads on embeds that ask for it:
**Before:**
```html theme={null}
```
**After:**
```html theme={null}
```
***
## Group, enterprise and searchbox stylesheets
Each surface has its own stylesheet, edited the same way:
| Surface | Where to find it |
| - | - |
| **Project** | Project **Style & Embed** → **Style** → **Customize** → **`>` Custom CSS** |
| **Group** | Group **Style & Embed** → **Style** → **Customize** → **`>` Custom CSS** |
| **Enterprise** | Enterprise **Settings** → **Style** → **Customize** → **`>` Custom CSS** |
| **Searchbox** | Enterprise **Settings** → **Searchbox** → **Custom CSS** → **Open style editor** |
The searchbox uses the same editor. When you open it from an enterprise, a **Viewer / Searchbox** switch appears at the top of the sidebar so you can move between the two stylesheets — the preview and the snippet list follow along. Searchbox selectors aren't scoped to `[data-pp-embed]`, since the searchbox is its own page.
***
## Understanding CSS selectors
The viewer is built with CSS Modules, so class names get a unique suffix (`unitTile` becomes something like `Style1_unitTile__a1B2c`). Target elements with the stable `data-pp-*` attributes and with `[class*="…"]` wildcards.
**✅ Correct selectors that work:**
```css theme={null}
/* Data attribute selectors for main containers */
[data-pp-embed] /* Main embed wrapper */
[data-pp-container] /* Inner container */
[data-pp-layout] /* Layout container */
[data-pp-header] /* Portal header bar */
[data-pp-cta-desktop] /* Header CTA button (desktop) */
[data-pp-cta-mobile] /* Header CTA button (mobile) */
[data-pp-filters] /* Filters container */
[data-pp-filters-wrapper] /* Filters wrapper with background */
[data-pp-glass-filters] /* Glass-style filter variant */
[data-pp-unit-grid] /* Unit grid */
[data-pp-unit-list] /* Unit list table */
[data-pp-unit-view] /* Unit view container */
[data-pp-amenity-view] /* Amenity view container */
[data-pp-commerce-view] /* Commerce view container */
[data-pp-canvas] /* Canvas/floor plan area */
[data-pp-modal] /* Modal containers */
/* Scope-specific selectors */
[data-pp-scope="project"] /* Project view */
[data-pp-scope="floor"] /* Floor view */
[data-pp-scope="unit"] /* Unit detail view */
/* Class wildcard selectors for nested elements */
[data-pp-embed] [class*="unitTile"] /* Unit cards */
[data-pp-embed] [class*="unitTileBody"] /* Card body */
[data-pp-embed] [class*="unitTilePrice"] /* Price display */
[data-pp-embed] [class*="unitTileAttrs"] /* Attributes container */
[data-pp-embed] [class*="badge"] /* Status badges */
[data-pp-embed] [class*="dropdownToggle"] /* Filter dropdowns */
[data-pp-embed] [class*="dropdownMenu"] /* Dropdown menus */
[data-pp-embed] [class*="unitCardAction"] /* Action buttons */
[data-pp-embed] [class*="shortlistAction"] /* Favorite button */
/* Scope-specific selectors */
[data-pp-scope="project"] [data-pp-layout] /* Project view layout */
[data-pp-scope="floor"] [data-pp-layout] /* Floor view layout */
[data-pp-scope="unit"] [class*="unitCard"] /* Unit detail card */
```
**❌ Incorrect selectors that won't work:**
```css theme={null}
/* These data attribute selectors are NOT implemented */
[data-pp-button] /* Use [class*="button"] or [class*="unitCardAction"] */
[data-pp-unit-tile] /* Use [class*="unitTile"] instead */
[data-pp-badge] /* Use [class*="badge"] instead */
[data-pp-dropdown] /* Use [class*="dropdown"] instead */
[data-pp-list] /* Use [data-pp-unit-list] or [data-pp-unit-grid] */
[data-pp-floor] /* Use [data-pp-scope="floor"] instead */
/* Plain class names won't work due to CSS Modules */
.header
.unitTile
.badge
/* This attribute doesn't exist */
[data-theme="showcase"]
```
### Common elements you can style
| Element | Selector | What it controls |
| - | - | - |
| Main container | `[data-pp-embed]` | Overall viewer wrapper, CSS variables |
| Inner container | `[data-pp-container]` | Inner container element |
| Layout | `[data-pp-layout]` | Grid layout container |
| Portal header | `[data-pp-header]` | Header bar with logo and CTAs |
| Header CTA (desktop) | `[data-pp-cta-desktop]` | Desktop call-to-action button |
| Header CTA (mobile) | `[data-pp-cta-mobile]` | Mobile call-to-action button |
| Filters wrapper | `[data-pp-filters-wrapper]` | Filter bar background/styling |
| Filters | `[data-pp-filters]` | Filter controls section |
| Glass filters | `[data-pp-glass-filters]` | Glass-style filter variant |
| Unit grid | `[data-pp-unit-grid]` | Grid of unit cards |
| Unit list | `[data-pp-unit-list]` | Table view of units |
| Unit cards | `[class*="unitTile"]` | Individual unit listings |
| Card body | `[class*="unitTileBody"]` | Card content area |
| Card price | `[class*="unitTilePrice"]` | Price display |
| Status badges | `[class*="badge"]` | Available/Sold/Reserved labels |
| Dropdowns | `[class*="dropdownToggle"]` | Filter dropdown buttons |
| Dropdown menus | `[class*="dropdownMenu"]` | Filter dropdown options |
| Action buttons | `[class*="unitCardAction"]` | CTA buttons |
| Modals | `[data-pp-modal]` | Popup windows |
| Canvas area | `[data-pp-canvas]` | Floor plan display area |
| Unit view | `[data-pp-unit-view]` | Unit view container |
| Amenity view | `[data-pp-amenity-view]` | Amenity view container |
| Commerce view | `[data-pp-commerce-view]` | Commerce view container |
| Gallery | `[class*="embla"]` | Image carousel |
| Shortlist button | `[class*="shortlistAction"]` | Favorite/save button |
***
## CSS custom properties (variables)
The default theme is built on CSS custom properties. Overriding them is the safest way to restyle the viewer: a few lines change everything consistently, and they keep working when the design is updated.
These variables live in *your* stylesheet, not in the viewer itself. Setting `--pp-brand-primary` on its own does nothing until a rule reads it — which is exactly what the snippets do. Add **Brand colours** first, then any other snippet follows it.
```css theme={null}
[data-pp-embed] {
/* Brand — every snippet derives from --pp-brand-primary */
--pp-brand-primary: #5b4cdb;
/* Solid brand colour with a subtle sheen: buttons, chips, filter bar.
Swap it for a gradient if you want a two-tone look. */
--pp-brand-surface: linear-gradient(
135deg,
rgba(255, 255, 255, 0.12) 0%,
rgba(0, 0, 0, 0.12) 100%
),
var(--pp-brand-primary);
/* Pale wash of the brand colour: hover and selected states */
--pp-brand-tint: linear-gradient(
0deg,
rgba(255, 255, 255, 0.9) 0%,
rgba(255, 255, 255, 0.9) 100%
),
var(--pp-brand-primary);
/* Optional accents — nothing uses them unless you do */
--pp-brand-secondary: #7c3aed;
--pp-brand-accent: #8b5cf6;
--pp-brand-light: #ede9fe;
/* Status Colors */
--pp-success: #059669;
--pp-success-bg: #d1fae5;
--pp-danger: #dc2626;
--pp-danger-bg: #fee2e2;
--pp-warning: #d97706;
--pp-warning-bg: #fef3c7;
/* Neutral Palette */
--pp-white: #ffffff;
--pp-gray-50: #f9fafb;
--pp-gray-100: #f3f4f6;
--pp-gray-200: #e5e7eb;
--pp-gray-500: #6b7280;
--pp-gray-700: #374151;
--pp-gray-900: #111827;
/* Shadows */
--pp-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.04);
--pp-shadow-md: 0 4px 8px -2px rgba(0, 0, 0, 0.08), 0 2px 4px -2px rgba(0, 0, 0, 0.04);
--pp-shadow-lg: 0 12px 24px -4px rgba(0, 0, 0, 0.1), 0 4px 8px -2px rgba(0, 0, 0, 0.05);
/* Border Radius */
--pp-radius-sm: 8px;
--pp-radius-md: 12px;
--pp-radius-lg: 16px;
--pp-radius-xl: 20px;
--pp-radius-full: 9999px;
}
```
***
## Example: styling status badges
```css theme={null}
/* Available badge - green gradient */
[data-pp-embed] [class*="badge"][data-style="available"] {
background: linear-gradient(135deg, #10b981 0%, #059669 100%) !important;
color: #ffffff !important;
font-weight: 600 !important;
padding: 6px 14px !important;
border-radius: 9999px !important;
}
/* Sold badge - red gradient */
[data-pp-embed] [class*="badge"][data-style="sold"] {
background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%) !important;
color: #ffffff !important;
font-weight: 600 !important;
padding: 6px 14px !important;
border-radius: 9999px !important;
}
/* Reserved/On Hold badge - gray gradient */
[data-pp-embed] [class*="badge"][data-style="reserved"],
[data-pp-embed] [class*="badge"][data-style="onhold"] {
background: linear-gradient(135deg, #6b7280 0%, #4b5563 100%) !important;
color: #ffffff !important;
font-weight: 600 !important;
padding: 6px 14px !important;
border-radius: 9999px !important;
}
```
***
## Troubleshooting
### It looks right in the editor but not on my site
1. **Missing URL parameter:** make sure `?customCss=true` is in your embed URL
2. **Not published:** the status above the editor must read *Published*, not *Unsaved changes* — click **Save & publish**
3. **Cache:** reload with a hard refresh, or test in a private window
### Some elements aren't styling correctly
You're probably using selectors that don't exist in the viewer:
* ❌ Don't use: `[data-pp-button]`, `[data-pp-unit-tile]`, `.unitTile`
* ✅ Do use: `[class*="button"]`, `[class*="unitTile"]`
Inspect the element in the live preview to see the exact class, then target it with a `[class*="…"]` wildcard.
### My rule is ignored
Add `!important`. CSS Modules generate high-specificity selectors, so most overrides need it.
### I changed a `--pp-*` variable and nothing happened
Variables only do something when a rule reads them. They're defined by your stylesheet, not by the viewer — so `--pp-brand-primary` on its own changes nothing. Add the **Brand colours** snippet plus the snippet for the section you want to restyle.
### My viewer stopped getting design updates
That happens when the published stylesheet is a full copy of the default theme: it pins every component to an old version. Trim it down to the rules you actually changed.
### How do I go back to the default theme?
Click **Remove** in the CSS editor, or drop the `?customCss=true` parameter from your embed URL. Removing doesn't delete your stylesheet — you can paste it back later.
# Choice of Finishes
Source: https://viewerdocs.planpoint.io/custom-finishes
Let buyers pick between different finish packages (kitchen, bathroom, and more) directly in the plan viewer
The **Choice of Finishes** feature lets you create finish packages (for example "California", "Provence", "Kansai") made up of cover photos and thumbnails for different rooms, and apply them to your units. Visitors can then switch between the available finish options directly from the unit page in the viewer.
Go to your project's **Settings** module, under the **Customization** tab, and enable the **Choice of finishes** checkbox.
This checkbox only controls whether the feature is visible to visitors. You still need to create at least one finish set and apply it to a unit for the button to appear.
Go to your project's content page, open the **Media** tab, then the **Custom finishes** sub-tab.
Click **Add new** to create a finish set:
* Give it a name (this is what you'll pick from when applying it to units, e.g. "California").
* For each room (Kitchen, Bathroom, General, etc.), upload a cover photo and a thumbnail for every finish option you want to offer.
Cover photos must be a PNG or JPG under 1.5 MB. If your source files are larger, resize/compress them before uploading.
From the same **Custom finishes** tab, select one or more units and apply the finish set you created, the same way you would apply any other asset from the Media Gallery.
If a unit already has a finish set applied and you're re-applying one (for example, after editing it), turn on **Replace** before applying. Otherwise the new tabs are added on top of the existing ones instead of replacing them, which can duplicate options for that room.
## What visitors see
Once a unit has at least one finish option configured and the feature is enabled for the project, visitors see a **Choice of finishes** button on that unit's page. Clicking it opens a room picker and a swatch/thumbnail selector so they can preview each finish option's cover photo before closing the panel.
# Form
Source: https://viewerdocs.planpoint.io/documentation/general/advanced-features/forms
The Form module allows you to create fully customizable forms to collect information from users interested in a specific unit. Form can be integrated directly into your project flow, supporting advanced customization, logic rules, previews, and multi-language translations.
This module is commonly used for:
* Lead capture
* Unit inquiries
* Reservation requests
* Contact and information collection
### Video Guide for Visual Learners
### Enabling the Form
To activate a form for your viewer:
1. In your dashboard, go to Sales & Marketing. From there, you will find the Form module.
2. Toggle Enable form to ON.
Once enabled, the form becomes available in the project flow and can be customized.
## Form Configuration
To customize your form, click Edit to open the Form builder. The builder is divided into four main sections:
* Designer
* Preview
* Logic
* Translations
### Designer
The Designer tab is where you build and configure the structure of your form.
### Form Title and Description
* Form title: Defines the main heading of the form. Example: Request info about unit unitName Dynamic variables like unitName are supported.
* Title visibility: You can choose whether the title and description are visible to end users.
### Form Language
* Select the default language for the form. Available default languages are English, Spanish, French, and German.
### Display Settings
* Form display mode
* Editable: Users can fill in and submit the form.
* Read-only: Form is visible but cannot be edited.
* Form width mode
* Auto: Adjust automatically to layout.
* Static: Fixed width.
* Responsive: Adapts to different screen sizes.
### Fields and Questions
You can add and configure multiple field types, including:
* Single-line input
* Long text
* Radio button groups
* Checkboxes
* Dropdowns
* Multi-select dropdowns
* Yes / No questions
Each field supports:
* Required / optional settings
* Custom labels
* Validation rules
**Example fields:**
### Logo and Header
You can upload a logo to display in the form header, helping mantain brand consistency.
### Navigation and Pages
* Organize the form into multiple pages
* Control navigation between pages
* Define the overall flow of the form
### Validation
Set validation rules to ensure users provide correct and complete information (e.g. required fields, email format).
### Thank you page
After submission, users are shown a confirmation screen. You can customize:
* Thank you message
* HTML markup
* Button text
## Preview
The Preview tab allows you to see exactly how the form will appear to end users before publishing.
* View the full layout
* Test field behaviour
* Confirm images, text, and button placement
This is especially useful when testing different screen sizes and layouts.
## Logic
The logic tab lets you define conditional rules that control the form flow.
### Logic Rules
You can create rules based on user input to:
* Show or hide specific questions
* Control navigation between pages
* Customize the user journey dynamically
To create a rule:
1. Go to Logic
2. Click Add New Rule
3. Define the condition and resulting action
If no rules are created, the form follows a linear flow by default.
## Translations
The Translations tab aloows you to manage multi-language versions of the form.
### Supported Translations
You can translate:
* Form title
* Button text
* Than you page content
* Questions labels
Each language is managed side by side for easy comparison and editing.
### Language Management
* Add or remove languages
* Enable only selected languages
* Keep English as default fallback
This makes Forms ideal for international or multi-region projects.
## Form Image
You can upload a Form Image that will override the main project image and be displayed alongside the form in preview and live views.
## Email Settings
Forms support email language configuration, allowing notification or automated messages to match the selected form language.
## Custom Reservation Flow
For advanced use cases, you can define a Custom Reservation Flow, including a custom confirmation message after submission.
If no custom message is set, the default confirmation behavior is applied.
Best Practices:
* Keep forms short to improve conversion rates
* Use required fileds only when neccessary
* Always preview before enabling the form
* Use translations to improve accessibility
* Leverage logic rules for personalized flows
# PostMessage Tracking
Source: https://viewerdocs.planpoint.io/documentation/general/advanced-features/post-message
## Overview
When Planpoint is embedded via iframe, the parent page cannot directly access what happens inside. **PostMessage Tracking** solves this by broadcasting events from the iframe to your page, allowing you to capture and forward them to any analytics tool.
***
## Setup
### 1. Enable in Dashboard
1. Go to **Sales & Marketing → Event Tracking**
2. Toggle **PostMessage Analytics** on
3. Select the events you want to track
4. Click **Select All** for comprehensive tracking
### 2. Copy Embed Code
Go to **Settings → Embed Code** and click "Copy". The generated code automatically includes the analytics listener script when PostMessage Analytics is enabled.
### 3. Uncomment Your Analytics Platform
The embed code includes commented-out lines for common platforms. Uncomment the one you use:
```javascript theme={null}
// Send to Google Analytics 4 (uncomment if using gtag)
// if (typeof gtag !== 'undefined') gtag('event', event.data.event, event.data.data);
// Send to GTM dataLayer (uncomment if using GTM)
// if (typeof dataLayer !== 'undefined') dataLayer.push({ event: event.data.event, ...event.data.data });
```
* **Using GA4 with gtag.js?** → Uncomment the `gtag` line
* **Using Google Tag Manager?** → Uncomment the `dataLayer` line
* **Using something else?** → Add your own handler (see examples below)
***
## Available Events
| Event | Description |
| - | - |
| `project-viewed` | User views a project |
| `floor-viewed` | User selects a floor |
| `unit-viewed` | User views a unit detail |
| `commerce-viewed` | User views a commercial space |
| `favorite-added` | User adds item to favorites |
| `favorite-removed` | User removes item from favorites |
| `filters-applied` | User applies search filters |
| `contact-form-submitted` | User submits contact form |
| `share-initiated` | User shares via email |
| `download-initiated` | User downloads floorplan/brochure |
| `gallery-opened` | User opens image gallery |
| `3d-model-viewed` | User opens 3D virtual tour |
| `portal-signup` | User signs up for portal |
| `portal-signin` | User signs in to portal |
| `payment-completed` | User completes a payment |
***
## Integration Examples
### Google Analytics 4 (gtag.js)
```javascript theme={null}
window.addEventListener('message', function(event) {
if (event.data.type !== 'planpoint-event') return;
gtag('event', event.data.event, event.data.data);
});
```
### Google Tag Manager
```javascript theme={null}
window.addEventListener('message', function(event) {
if (event.data.type !== 'planpoint-event') return;
dataLayer.push({
event: event.data.event,
...event.data.data
});
});
```
### Custom Handler
```javascript theme={null}
window.addEventListener('message', function(event) {
if (event.data.type !== 'planpoint-event') return;
console.log('Event:', event.data.event);
console.log('Data:', event.data.data);
// Send to your analytics platform
myAnalytics.track(event.data.event, event.data.data);
});
```
***
## Event Data Structure
All events follow this format:
```javascript theme={null}
{
type: 'planpoint-event',
event: 'unit-viewed', // Event name
data: { // Event-specific data
projectId: '...',
projectName: '...',
unitId: '...',
unitName: '...',
// Additional fields vary by event
}
}
```
### Sample Event Payloads
**Unit Viewed:**
```javascript theme={null}
{
projectId: "abc123",
projectName: "Sunrise Towers",
unitId: "unit456",
unitName: "Unit 302",
floorId: "floor789",
floorName: "3rd Floor"
}
```
**Contact Form Submitted:**
```javascript theme={null}
{
projectId: "abc123",
projectName: "Sunrise Towers",
unitId: "unit456",
formType: "contact"
}
```
**Favorite Added:**
```javascript theme={null}
{
projectId: "abc123",
projectName: "Sunrise Towers",
unitId: "unit456",
unitName: "Unit 302"
}
```
***
## Best Practices
1. **Select only needed events** — Reduces noise in your analytics
2. **Test in browser console first** — Events log to console by default
3. **Use GTM for flexibility** — Easier to modify tracking without code changes
4. **Set up GA4 custom dimensions** — Map `projectName`, `unitName` for better reporting
***
## Troubleshooting
### Events not firing?
* Verify PostMessage Analytics is **enabled** in dashboard
* Check that specific events are **selected**
* Regenerate and update your embed code after changing settings
### Events firing but not in GA4?
* Confirm `gtag` is loaded before the listener
* Check GA4 DebugView for incoming events
* Verify your GA4 measurement ID is correct
***
## Migration from GTM Code Injection
If you were using the legacy **GTM Code Injection** feature:
| Legacy (GTM Injection) | New (PostMessage Analytics) |
| - | - |
| Injects GTM into Planpoint page | Broadcasts events to parent page |
| Works for direct page visits | Works for embedded iframes |
| Limited to GTM | Works with any analytics tool |
For embedded usage, **PostMessage Analytics is recommended**.
# SEO indexing
Source: https://viewerdocs.planpoint.io/documentation/general/advanced-features/untitled-page
Turn your Planpoint Viewer into search engine-indexable pages so clients can find your units directly from search result pages (Google, Bing, and AI).
## How It Works, In Short
* Your real estate project's website is hosted on its own domain (e.g. `astoria.com`).
* Planpoint Viewer is embedded on a page like `astoria.com/floorplans`. That embedded viewer is **not** crawlable by Google because it's an iframe.
* To make the content of Planpoint Viewer searchable, add a **CNAME subdomain** (e.g. `floorplans.astoria.com`) and connect it in Style & Embed settings.
* On that subdomain we serve the units as **dedicated, server-rendered SEO pages** — not the embedded Viewer. The content lives in the raw HTML, so Google can read and index it. Each page still links into the interactive viewer.
* The **sitemap.xml and robots.txt** documents are generated automatically and stay up to date on every publish — nothing manual.
* **Titles and descriptions** are automatic and descriptive, e.g. the landing page reads `Astoria — Floor Plans & Availability`, unit pages read `Unit 202 — 2 Bedroom Floor Plan at Astoria`, with auto descriptions summarizing available units, layouts and pricing.
***
When you connect a **custom domain** to your project (e.g. `viewer.yourproject.com`), Planpoint automatically serves a set of public, search-engine-friendly pages for it. The domain exposes your units as real, crawlable web pages — so they can be indexed by Google and show up when buyers search.
The pages are fully server-rendered (the content is in the HTML, not loaded later by JavaScript), which is what makes them indexable.
***
## Before You Start
You need a **custom domain connected to your project**. If you haven't set one up yet, please go to [Style & Embed](https://viewerdocs.planpoint.io/preview-embed).
This applies only to **custom domains**. Your Planpoint dashboard and the default `*.planpoint` links are unaffected — they keep working exactly as before.
***
## What Gets Published
On your custom domain, these pages are generated automatically:
| URL | Page |
| - | - |
| `/` | Landing page listing all available units |
| `/unit/` | Individual unit page (beds, baths, area, floor…) |
| `/` (e.g. `/2-bedrooms`) | Filtered list for a unit type |
| `/sitemap.xml` | Sitemap of all the above, for search engines |
| `/robots.txt` | Crawl rules + link to the sitemap |
Each page carries a proper title, heading, and unit details so Google can understand and rank it.
***
## Step-by-Step
### Step 1 — Confirm your pages are live
Open your project's custom domain in a browser and check:
* The **root** (`viewer.yourproject.com`) shows your units
* Clicking a unit opens a page like `viewer.yourproject.com/unit/301`
* A filter URL like `viewer.yourproject.com/2-bedrooms` shows a filtered list
* `viewer.yourproject.com/sitemap.xml` lists your URLs
* `viewer.yourproject.com/robots.txt` loads
Right-click any page → **View Source**. If you can see the unit text in the raw HTML, the page is indexable. That's exactly what Googlebot reads.
### Step 2 — Add your domain to Google Search Console
Go to [Google Search Console](https://search.google.com/search-console) and add a new **URL prefix** property using your full domain (e.g. `https://viewer.yourproject.com/`).
A **URL-prefix** property covers just that subdomain. It does **not** cover your root marketing site (`yourproject.com`) — that's a separate property.
### Step 3 — Verify ownership
Choose the **HTML file** verification method (Google's recommended option):
* Download the verification file Google gives you (e.g. `google.html`).
* Send it to your Planpoint contact — we host it on your domain for you.
* Once it's live, click **Verify** in Search Console.
Planpoint serves this file automatically for connected domains — you don't upload anything yourself. Just share the file (or its name) with us and we'll confirm when it's ready to verify.
### Step 4 — Submit your sitemap
In Search Console, open **Sitemaps** and submit:
```text theme={null}
sitemap.xml
```
Google will read it and discover all your unit and filter pages. A **Success** status means it was accepted.

### Step 5 — Request indexing (optional, speeds things up)
Use **URL Inspection** at the top of Search Console, paste a page URL (e.g. a unit page), and click **Request Indexing**. Do this for your homepage and a few key units to jump the crawl queue instead of waiting.
***
## How to Check If You're Indexed
* **In Google:** search `site:viewer.yourproject.com`. It lists every page Google has already indexed for the domain. New pages appear here over time as they're crawled.
* **In Search Console:** the **Pages** report shows how many URLs are indexed, and **Performance** shows impressions and clicks once pages start ranking.
Indexing is not instant. New pages typically take **days to a few weeks** to appear in Google, even after submitting the sitemap. An empty `site:` result early on is normal — it means Google hasn't crawled yet, not that anything is wrong.
***
## FAQ
**Does this change my dashboard or embed?** No. Only public pages on your connected custom domain are affected. Your dashboard, embeds, and Planpoint links are unchanged.
**Will unavailable/sold units show up?** Only units surfaced on your public pages are included in the sitemap.
**Can I index my main website (`yourproject.com`) too?** That's a separate site and a separate Search Console property. This feature covers the Planpoint viewer domain only.
# Terminology
Source: https://viewerdocs.planpoint.io/documentation/general/editing-and-management/terminology
The Terminology feature allows you to customize the wording used throughout your project so it aligns with your business, market, or customer preferences. By adjusting key terms, you can ensure the interface language matches how your customers naturally refer to units, listings, and project details.
This is especially useful for adapting Planpoint to different industries, regions, or branding requirements without changing any underlying functionality.
Terminology updates are applied across the project wherever those terms appear, creating a more consistent and familiar experience for your users.
### How to Access Terminology Settings
1. Open your project and go to **Settings**.
2. Navigate to **Style & Embed**.
3. Click **Customize Style**.
4. Within the Style editor, open the **Terminology** tab.
From there, simply click on the term you want to edit and enter the wording of your choice. Changes are applied automatically and reflected everywhere that term appears in the project.
### Editable Terminology
The following terms can be customized on a per-project basis. Updating a term will change how it appears throughout the project interface.
| Default Term | Description | Example Customizations |
| :- | :- | :- |
| **1. Project** | The overall development or listing | Building, Property, Community |
| **2. Floor** | A level within the project | Level, Story |
| **3. Unit** | An individual space or listing | Apartment, Suite, Office |
| **4. Area** | Size measurement for a unit | Sq Ft, Sq M, Size |
| **5. Price** | Cost associated with a unit | Rent, Lease Rate, Starting At |
| **6. Change model** | Action to switch unit variants | Switch Layout, Change Plan |
| **7. Available** | Unit is currently available | Open, For Sale |
| **8. Reserved** | Unit is temporarily held | On Hold |
| **9. Future** | Unit not yet released | Coming Soon |
| **10. Unavailable** | Unit cannot be selected | Not Available |
| **11. Sold / Leased** | Unit has been finalized | Sold, Leased |
# Themes
Source: https://viewerdocs.planpoint.io/documentation/general/editing-and-management/themes
Themes control the visual style and layout of your Planpoint project viewer. Each theme is prebuilt and ready to use, allowing you to present your project in a professional and consistent way without custom design work.
Themes define how your listings, units, floorplans, and project details are displayed to users across desktop and mobile devices.
## What are themes?
A theme is a predesigned visual layout that determines:
* Overall page structure and layout
* Typography, spacing, and visual hierarchy
* How units and listings are displayed
* Interaction patterns and UI presentation
* The overall look and feel of your project
All themes are responsive and optimized for modern browsers and devices.
## **How to Access and Apply Themes**
Follow these steps to access themes in your Planpoint dashboard:
1. From your dashboard, click Style & Embed at the top of the project. If you are already inside a project, navigate to Settings → Style & Embed.
2. Click on Customize Style.
3. In the Style editor, navigate to the Themes section and select the theme that best fits your needs. The theme will be applied immediately, and you can change it at any time.
You can also use your own CSS. To get started, download the default theme CSS, make your edits, and then upload it.
# Change information
Source: https://viewerdocs.planpoint.io/edit-info
Here you can find how to modify/update your projects.
There are many things you can modify in your projects. Below, you will find instructions on how to make these changes.
Go to settings, and under **project details**, you can modify the main image, name, website URL and internal URLs of the project.
As easy as it looks in the following video. Just select your desired modifications based on the project phase.
After updating the main render, you will need to modify the exterior drawing. Simply navigate to the **content** module, click on the **exterior** tab, and *redraw* the corresponding floors.
Navigate to the **Floors** tab and select **Floorplan** to change the actual floor plate. Then, click on **Draw Floorplan** for each unit and sketch the corresponding polygon.
In the **Units** tab, you can update your unit list either *manually* (one by one) or *automatically* by re-uploading an updated version of the CSV file.
To make any updates, you can download the current unit list
# Enterprise Map & Points of Interest
Source: https://viewerdocs.planpoint.io/enterprise-map-embed
How to show Points of Interest on your Enterprise map and control the embed with URL parameters (project=, grid=false, pois=true, and more).
## Overview
Your **Enterprise** embed shows every project and group on a single map. You can also scope that same map down to **one project** (or a small cluster of nearby projects) — for example to drop a "neighbourhood" map on that project's own page — and layer **Points of Interest** (nearby amenities, transit, shops) on top.
Both of these are controlled by a handful of parameters added to the end of the embed's URL. This article covers what each one does, plus how to manage Points of Interest from your dashboard.
These parameters apply to the **Enterprise map embed** specifically. For deep-linking to a unit or collection on any embed (project, group, or enterprise), see [Deep Linking to specific units](/link-units).
***
## Points of Interest (POIs)
Points of Interest let you pin nearby places — restaurants, transit stops, schools, parks — next to your project pins on the Enterprise map. Each POI shows a custom icon on the map and opens a card with its title, category, description, and photo when clicked.
### Managing POIs in the dashboard
1. Open your **Enterprise** in the dashboard and go to **Settings**.
2. Click the **POIs** tab.
3. Under **Categories**, add a category for each type of place you want to show (e.g. "Restaurant", "Grocery Store", "Metro Station") and upload an icon for it. Categories let every POI of the same type share one icon.
4. Under **POIs**, click **+ Add POI** to create one manually — give it a title, pick a category, add a description, and search for its address (Planpoint locates it on the map for you). Or click **Import** to upload a CSV or Excel file of places in bulk; rows with an address are located automatically, and categories are matched to the ones you've already created.
5. Titles and descriptions can each have translations for every language your embed supports — useful if your POI list was written in one language but your embed serves visitors in several.
### Showing POIs on the embed
POIs are **off by default** on every Enterprise embed — turn them on per embed with:
```text theme={null}
https://yourwebsite.com/your-page?pois=true
```
Add `poiDirections=true` to also draw a walking/driving route with travel time from a project to its nearest POIs when that project is hovered or selected:
```text theme={null}
https://yourwebsite.com/your-page?pois=true&poiDirections=true
```
POIs are styled with the same theme and Custom CSS as the rest of your embed. See [Custom CSS](/custom-css) if you want to restyle the pins or cards beyond the built-in themes.
***
## Scoping the map to specific projects
By default, the Enterprise map shows all of your projects and groups. Use `project=` to scope it down to one project, or a short list of nearby ones:
```text theme={null}
https://yourwebsite.com/your-page?project=Riverside%20Tower
```
To show a small cluster of neighbouring projects on the same scoped map (their pins appear for context, but only the first project's units are listed), separate names with a comma:
```text theme={null}
https://yourwebsite.com/your-page?project=Riverside%20Tower,Riverside%20Annex
```
`project=` matches your project or group's name (case-insensitive). When it's set, the map automatically centers and zooms on that project, and Points of Interest (if enabled) are limited to the area immediately around it — see `poiRadius` below.
***
## Parameter Reference
| Param | What it does | Default |
| - | - | - |
| `project` | Scopes the map to one project/group by name, or a comma-separated list of names | Off (shows everything) |
| `pois` | Shows Points of Interest (`true` or `1`) | Off |
| `poiDirections` | Draws a route + travel time from the active project to its nearest POIs (`true` or `1`); only takes effect alongside `pois=true` | Off |
| `poiRadius` | How far (in km) around a `project=`-scoped project to keep POIs visible | `3` |
| `grid` | Hides the project/unit list next to the map, so the map fills the full width (`false` or `0`) | Shown |
| `zoom` | Overrides the map's initial zoom level | Project's saved zoom |
| `center` | Overrides the map's initial center point, as `longitude,latitude` | Project's saved center |
For `center`, always use `longitude,latitude` in that order — not `lat`/`lng`. Those two parameter names are reserved for the searchbox's location filter.
***
## Full-width, map-only embed
Hide the side list entirely so the map fills the embed on its own — handy for a compact "find us nearby" widget on a project page:
```text theme={null}
https://yourwebsite.com/your-page?project=Riverside%20Tower&pois=true&grid=false
```
***
## Custom map framing
If you want an embed to open already zoomed to a particular area rather than your project's saved default, combine `zoom` and `center`:
```text theme={null}
https://yourwebsite.com/your-page?zoom=14¢er=-73.5674,45.5019
```
***
## Quick Examples
| Goal | Add to your page URL |
| - | - |
| Show POIs on the full Enterprise map | `?pois=true` |
| Show POIs with travel times | `?pois=true&poiDirections=true` |
| Scope the map to one project | `?project=Riverside%20Tower` |
| Scope the map to a cluster of nearby projects | `?project=Riverside%20Tower,Riverside%20Annex` |
| Scoped map, full-width, with POIs | `?project=Riverside%20Tower&pois=true&grid=false` |
| Widen the POI search radius to 5 km | `?project=Riverside%20Tower&pois=true&poiRadius=5` |
| Open the map at a custom zoom and location | `?zoom=14¢er=-73.5674,45.5019` |
All of these can be combined in the same URL, for example:
```text theme={null}
https://yourwebsite.com/your-page?project=Riverside%20Tower&pois=true&poiDirections=true&grid=false&poiRadius=4
```
# Enterprise
Source: https://viewerdocs.planpoint.io/enterprise-new
This new feature allows you to showcase all your projects and availabilities in a single map interface. Here is how you can build it.
In Planpoint Enterprise, you can integrate projects from a single account or many different accounts (by invitation)
***
## Video Guide for Visual Learners
***
In your Planpoint dashboard, click the hamburger menu icon and then select **Enterprises**.
To create you enterprise project, click on **new enterprise**. Assign a name for the enterprise and click on **save and create**.


Once you create your project or projects, you can observe them displayed in your enterprise dashboard. Then click on **Settings** to begin editing your enterprise project.

Here, you can customize your enterprise project. You will be able to add your Enterprise image, edit the project's name, assign the embed options and prices, set the availabilities, layouts, and colors you want to use.

To finalize the project settings, you need to organize everything related to geolocation. Here you can select the map style, the target marker, the map point color and add directions if you wish.
To choose the map to be displayed on the enterprise dashboard, you must set the desired view you want using the map on the right side. Then click on **use this view**. You can also use the icons on the upper right corner of the map to adjust your map view.
You can choose to turn the initial zoom-in and dynamic centering on or off for your enterprise project
The Searchbox tab allows Enterprise administrators to configure how the Planpoint search experience behaves and which filters are available to end users.
This section controls visibility, behavior, and layout of the embedded searchbox used across Enterprise environments.
### Searchbox Settings
The Settings panel on the left defines the core behavior of the searchbox:
* Enable Searchbox: Turns the Enterprise seaarchbox on or off entirely.
* Show Locations Search: Enables location-based searching (e.g. cities, areas, neighborhoods) within the searchbox.
* Result URLs: Allows you to select the language used for result links.
* Searchbox URL: Opens the hosted searchbox in a new browser tab. Useful for testing or sharing.
* Searchbox Embed Code: Generates an embeddable snippet that can be copied and placed into external websites or applications.
* Enable Custom Styling: When enabled, allows advanced styling and branding customization for the search box using either the default theme CSS or a custom CSS file.
### Filters Configuration
The filters panel on the right controls which filters appear in the searchbox and how they are displayed.
Key rules:
* A maximum of **10 filters** can be enabled
* A minimum of **2 filters** is required
* Only the **first 4 enabled filters** are displayed by default in the searchbox UI
* Filters can be reordered via drag-and-drop
* Each filter can be individually enabled or disabled
Go to the **entities** tab to add any project or group project you want.
You can also add external projects by searching for them by their name. Simply go to the **External** tab, type the name of the project, choose the project and send a request. After the request is accepted by the project's owner, you will be able to add it to your enterprise.

You can also manage the members of your team who can administer or edit your enterprise
# Exterior
Source: https://viewerdocs.planpoint.io/exterior
Following the completion of the settings module, proceed to the exterior module to start building your Planpoint.
### Exterior
Your project currently indicates there are no floors added, which is expected at this stage. The next step involves initiating the addition of floors to your project. Simply click on **add floor.**

To draw the first floor, click on **draw** or **redraw** (depending on the case). The **edit** button allows you to change the floor name. And the **reset** button allows you to delete the drawn path and start again.

After clicking on **draw**, a new window will pop up, allowing you to draw the exterior floor of the corresponding level.

* You can make minor adjustments by clicking on **Redraw** and then using the magnetic snap feature.
* You can add points to existing polygons by clicking **Add Points**.
* You can navigate around the canvas using the 🖐️ tool. You can also use the Undo and Redo arrow buttons to reverse or restore your changes.
* The **Focus on this Shape** feature hides all polygons except the one you are currently working on. This is especially useful when your renders contain many details or when you’re using a large number of points to create your polygons.
* You can zoom in or zoom out of the image using the **+ -** buttons.
* If you wish to completely redraw the floor, click on **Reset**.
* You can also rename the floor how you want by clicking on **Edit** and editing the name field.
The Keyboard Shortcuts (❓) feature is a helpful reference for learning how to use the polygon drawing tool effectively.
If you have a second image in a night-time version, you can add it and enable the **Day & Night** feature. This adds a button to the plan viewer, allowing users to switch between the day and night images of the project’s exterior.
You can also customize the **360° icon**.
If you want end users to be able to zoom in on the project’s main image, you can enable the **Zoom** tool here.

## Exterior hover colors
Exterior shapes use the project's **Hover** color by default, even when unit availabilities are displayed elsewhere in the Viewer.
To color exterior shapes by availability, go to **Settings → Customization → Availabilities**, enable **Availabilities**, then turn on **Use availability colors on exterior**. The status colors are configured under **Settings → Style & Embed → Customize Style → Color Scheme**.
For projects without a floor step, each exterior shape uses that space or unit's status. For projects with floors, a floor can contain mixed inventory, so Planpoint uses the first status that applies in this order: **Available**, **Reserved**, **Future**, **Unavailable**, then **Sold/Leased**.
This option changes the color shown when an exterior shape is highlighted. It does not make all exterior shapes permanently visible.
## AI Exterior Detection
AI Exterior Detection reads the active building image and traces the visible floors in perspective. For projects without a floor step, it can trace commercial spaces instead. Nothing is saved until you review and apply the results.
### Before you start
For the strongest results, use an image that:
* Shows one building clearly.
* Has an unobstructed view of the facade.
* Makes rows of windows, balconies, entrances or storefront divisions easy to follow.
* Includes the complete visible building rather than a tightly cropped section.
Your account also needs enough AI credits for the selected mode. **Faster** costs one credit and **Best quality** costs three credits per building image.
The image currently selected in **Exterior** is the one Planpoint analyzes. Select the correct image first when the project has alternative exterior covers.
### Detect floors or spaces
Go to **Content → Exterior** and select the building image you want to process. Click **Detect floors**. On projects without a floor step, the action is **Detect spaces**.
Select **Best quality** for complex facades, setbacks and angled building views. Select **Faster** for a quicker, value-optimized pass on clear, front-facing images.
The setup screen also shows your AI credit balance and the cost of the detection.
Click **Start detection**. Planpoint reads the building shot, identifies the visible floors or spaces, traces each region in perspective and prepares matches against the records in your project.
In the full-screen review, inspect the proposed outlines and assign each region to an existing floor or space, create a new record, or skip it.
Resolve any duplicate assignments before applying the results.
Apply the reviewed results to save them. Use **Redraw** beside an individual floor or space when its outline needs a manual adjustment.
### What the detector looks for
For residential projects, Planpoint follows rows of windows and balconies to identify complete storey bands, including visible wings and setbacks. It traces the perspective visible in the image rather than forcing horizontal rectangles.
For commercial projects without a floor step, Planpoint uses entrances, window groups, columns, facade changes and signage to separate occupiable spaces.
### AI credits
**Faster** detection costs one AI credit per building image. **Best quality** costs three credits. The setup screen shows the current balance, selected mode cost, and a **Top up** link. Failed detections and results with no usable regions are refunded automatically.
### AI detection troubleshooting
AI Exterior Detection may need to be enabled for your account. Confirm that the project has an exterior image, then contact Planpoint support if the action is still unavailable.
Try **Best quality** with a clearer or more front-facing image. During review, keep the useful regions and skip duplicates, then draw or redraw the remaining floor manually.
Close the review, select the intended exterior cover and start a new detection. The selected cover in the Exterior module determines which image is analyzed.
Change that region's assignment during review. Nothing changes in the project until you apply the results.
If Day & Night is turned on, you will be able to add an extra view of the project, but you will lose the ability to create a 360° project
# Floors
Source: https://viewerdocs.planpoint.io/floors
In the **Floors** module, selecting the **floorplan** option will grant you access to the corresponding floor plate for each floor:

You can also update the floor plan here:

Selecting **draw floorplan** option will enable you to draw the polygon for the corresponding unit in the floor plan:

After drawing the polygons for a floor, and if other floors share the same floor plate, you can clone the drawings. This will help speed up the process by duplicating the drawn polygons.

After choosing the floor you wish to copy from, it will serve as the reference floor, and its drawings will be cloned. You may choose as many floors as needed. Enabling the **Clone Floorplan** option will copy both the drawings and the floor plans from the selected floor.

Clicking on the **delete** button will remove the entire floor along with its units.
## Magic Wand - Automatically outline units with the help of AI
Magic Wand reads a floorplan image, traces the visible unit boundaries and helps match those outlines to the units already in your project. Nothing is saved until you review and apply the results.
### Before you start
Make sure that:
* The floor has a clear JPG or PNG floorplan.
* Unit boundaries and numbers are readable at the uploaded resolution.
* The units have already been imported or added when you want Planpoint to match outlines to existing records.
* Your account has enough AI credits for the selected mode. **Faster** costs one credit and **Best quality** costs three credits per floorplan.
AI Unit Detection works best on high-contrast architectural plans. Faint scans, overlapping annotations and low-resolution images may need more manual adjustment.
### Detect the units
Go to **Content → Floors**. Find the floorplan you want to process and click **Detect units**.
Select **Best quality** for complex or crowded floorplans. Select **Faster** for a quicker, value-optimized pass on clear and simple plans.
Turn **Include balconies, terraces and gardens** off when you only want the enclosed interior boundary of each unit.
Confirm the credit balance and click **Start detection**. Planpoint uploads the floorplan for analysis, finds the units, cleans up the outlines and prepares matches against your project data.
You can follow each stage in the progress window. Processing a complex floorplan can take several minutes.
Planpoint opens a full-screen review after detection. Check each outline and choose whether it should:
* Update an existing unit.
* Create a new unit.
* Be skipped.
Printed unit numbers are used to suggest matches where possible. Resolve any duplicate assignments before applying the results.
Apply the reviewed results to save them. You can then use **Redraw** on individual units to adjust any outline that needs a manual correction.
### AI credits
**Faster** detection costs one AI credit per floorplan. **Best quality** costs three credits. The setup screen shows the current balance, selected mode cost, and a **Top up** link. Failed detections and results with no usable regions are refunded automatically.
### AI detection troubleshooting
Confirm that the floor has a floorplan image and that AI detection is enabled for your account. Contact Planpoint support if the action is still unavailable.
Try **Best quality** with the clearest available source image. After applying the useful results, redraw any missing or inaccurate outline manually.
Use the assignment control for that region to select the correct existing unit, create a new one or skip it. Nothing changes in the project until you apply the review.
Run detection with **Include balconies, terraces and gardens** turned off when you only need enclosed interior outlines.
# Homes & Land
Source: https://viewerdocs.planpoint.io/homes-land
The **Homes & Land** option lets you choose between one of three models:
1. A regular image (i.e. money-shot rendering or a bird's-eye view)
2. An interactive SVG
3. Custom polygons directly on our native map
### Regular image
You can map your homes and plots of land to any type of image. In a **Homes & Land project**, you don't draw polygons on top of floors - *there's no concept of floors* - but directly on the home itself or the land itself.

Here's a **[live demo](https://www.planpoint.io/types/single-family).**

Here's a **[live demo](https://app.planpoint.io/Mariners-2/Mariners-2).**
You can use our traditional polygon drawing feature to make these homes or plots of land selectable and linkable to the relevant content.
### Interactive SVG
The interactive SVG model is mostly used for maps that have been created in vector editing software. This model allows pre-existing vector shapes to be selectable inside Planpoint. It also allows other elements to be placed on top of the shapes without affecting the hover color.
Here's a [live demo](https://app.planpoint.io/Mariners3/Mariners).

To use the interactive SVG model, you need to follow a few important requirements when exporting your file.
* All elements you want to be selectable must be grouped together under one group.
* This group must have a unique ID.
* Each element under this group must have it's own unique ID.

If you want to inspect an example file, you can **[download our SVG template here](https://svgshare.com/i/14Pw.svg)**.
### Custom polygons
This third model lets you draw polygons directly on our native map interface.

### Now that we've covered how the Homes & Land feature works, let's show you how to set it up.
Begin by creating a new project, and select **Homes & Land** as the project type.
This type of project is set up similarly to a regular project, but there are some differences when it comes to the project's geolocation and exterior drawings. If you encounter any issues while setting up your project, please refer to our [settings page](https://viewerdocs.planpoint.io/settings) for assistance.
To organize the project's geolocation, please enter the address and coordinates (latitude and longitude). Once this is complete, proceed to add the perimeter.
Begin by zooming in on the map located on the right side of the geolocation. You can use the **Zoom In** button in the bottom right corner, or scroll your mouse over the map until you reach the desired view.
Next, click on the polygon tool to draw your perimeter. Once you have finished, double-click to confirm the new perimeter.
After setting up the geolocation, you need to select the lot layouts. You can choose from individual lots, vector tiles, or a custom map.
Assuming that the units have already been added to the project, and you've selected a custom map for the lot layouts, please proceed to the units module and click on the **world map** icon.
Once you're there, simply draw your polygons on the custom map tab.
# Deep Linking to specific units
Source: https://viewerdocs.planpoint.io/link-units
## What Is This?
By default, your Planpoint embed opens at the top-level view when a visitor lands on your page. Deep-linking lets you share a URL that skips straight to a specific **unit** — or to a whole **collection** (a curated group of units, such as “The City Studios”). It's useful for email campaigns, ads, or any page where you want to highlight a particular listing or collection.
***
## Before You Start
This guide assumes you already have a Planpoint embed on your website. If you haven't set that up yet, follow the [How to Embed](https://viewerdocs.planpoint.io/preview-embed#how-to-embed) Planpoint on your website guide first, then come back here.
Looking for Enterprise **map** parameters like `project=`, `pois=true`, or `grid=false` instead? See [Enterprise Map & Points of Interest](/enterprise-map-embed).
***
## Step-by-Step
### Step 1 — Find your unit's details
In your Planpoint dashboard, open the project that contains the unit you want to link to and note down:
* **The unit name** — the number or label shown on the unit card (e.g. `202`, `Unit A`)
* **The collection name** *(optional)* — the collection you want to open (e.g. `The City Studios`), exactly as named in your dashboard. Use this to land on a whole collection instead of a single unit
* **The collection link slug** *(optional)* — only needed for [pretty-path links](#pretty-path-links-using-your-page-url). Set it on the collection's **Edit** screen (e.g. `city-studios`)
* **The floor name** *(optional)* — the floor that unit is on (e.g. `Floor 2`). Only needed if the same unit name appears on more than one floor
* **The project name** *(group and enterprise embeds only)* — the full project name as entered in your dashboard (e.g. `Riverside Tower`). Only needed if multiple projects in your group or enterprise share unit names
### Step 2 — Go to the page where your embed lives
Open the page on your website that contains the Planpoint embed. Copy its full URL from the browser address bar.
Example:
```text theme={null}
https://yourwebsite.com/apartments
```
### Step 3 — Add the parameters
Append `?u=` followed by the unit name to the end of your URL:
```text theme={null}
https://yourwebsite.com/apartments?u=202
```
If you also want to specify the floor:
```text theme={null}
https://yourwebsite.com/apartments?f=Floor%202&u=202
```
If you have a group or enterprise embed and want to pin to a specific project:
```text theme={null}
https://yourwebsite.com/apartments?p=Riverside%20Tower&f=Floor%202&u=202
```
To open a whole **collection** instead of a single unit, use `?c=` followed by the collection name:
```text theme={null}
https://yourwebsite.com/apartments?c=The%20City%20Studios
```
> **Shortcut:** In your dashboard, open the project's **Collections** tab and click **Copy link** next to any collection. This copies a ready-made deep-link for that collection — no need to build the URL by hand.
### Step 4 — Test the link
Paste the URL into a new browser tab. The embed should open directly on the unit you specified. If it opens on the main view instead, double-check that the unit name, floor name, and project name match exactly what is in your dashboard.
### Step 5 — Use the link
You can now use this URL anywhere — in an email, an ad, a button on another page, or a QR code.
***
## Parameter Reference
| Param | What it does | Required? |
| - | - | - |
| `u` | The unit name to open | Yes — unless you're linking to a collection with `c` |
| `c` | The collection to open | Yes — unless you're linking to a unit with `u` |
| `f` | Narrows the search to a specific floor | Optional |
| `p` | Narrows the search to a specific project | Optional — only needed for group/enterprise embeds when unit names repeat across projects |
***
## Usage by Embed Type
### Project Embed
`f` and `p` are both optional. `?u=202` alone is enough:
```text theme={null}
https://yourwebsite.com/your-page?u=202
```
If the same unit number exists on multiple floors, add `f` to be precise:
```text theme={null}
https://yourwebsite.com/your-page?f=Floor%202&u=202
```
### Group Embed
Works the same way. Add `p` only if multiple projects share the same unit names:
```text theme={null}
https://yourwebsite.com/your-page?p=Riverside%20Tower&f=Floor%202&u=202
```
If the project has the **Skip Floor Step** setting enabled (used for commercial spaces with no floors), use `u` alone — there is no floor to specify:
```text theme={null}
https://yourwebsite.com/your-page?u=Shop%20A
```
### Enterprise Embed
Same as group, but searches across all projects and groups within the enterprise:
```text theme={null}
https://yourwebsite.com/your-page?p=Riverside%20Tower&f=Floor%202&u=202
```
### Linking to a Collection
Collections work with project, group, and enterprise embeds. Use `c` on its own to open straight on a collection:
```text theme={null}
https://yourwebsite.com/your-page?c=The%20City%20Studios
```
In a group or enterprise embed, Planpoint automatically opens the project that owns the collection — you don't need to add `p`.
### Pretty-Path Links (using your page URL)
If your collections live behind tidy URLs like:
```text theme={null}
https://yourwebsite.com/pricelist/city-studios
```
Planpoint can open the matching collection automatically — no `?c=` needed. It reads the **last segment of the page path** (`city-studios` above) and opens the collection whose **link slug** matches it.
Set the slug in your dashboard: open the project's **Collections** tab, click **Edit** on a collection, and set the **Link slug** field (e.g. `city-studios`). It defaults to a slug based on the collection name, so most collections work out of the box — only change it if you want it to match a specific path on your site.
This works on any platform (Webflow, WordPress, Squarespace, etc.) with no extra setup — just add the embed to the page. If a path segment doesn't match any collection, nothing changes and the embed opens normally. A `?c=` in the URL always takes priority over the path.
***
## Matching Rules
* **Unit name (`u`)** — must match exactly, including capitalisation (e.g. `202`, `Unit A`)
* **Floor name (`f`)** — must match exactly, including capitalisation (e.g. `Floor 2`, `Level 3`)
* **Project name (`p`)** — case-insensitive exact match (`p=riverside tower` matches "Riverside Tower")
* **Collection name (`c`)** — case-insensitive exact match (`c=the city studios` matches "The City Studios")
* When `p` is omitted in a group or enterprise embed, the first unit with a matching name is opened
***
## URL Encoding
Spaces and special characters must be percent-encoded in URLs:
| Character | Encoded form |
| - | - |
| Space | `%20` |
| `&` | `%26` |
| `#` | `%23` |
So "Floor 2" becomes `Floor%202` and "Riverside Tower" becomes `Riverside%20Tower`.
Most website builders (Webflow, WordPress, Squarespace) handle this automatically when you paste a URL into a link field.
***
## Quick Examples
| Goal | Add to your page URL |
| - | - |
| Open unit 202 | `?u=202` |
| Open the "The City Studios" collection | `?c=The%20City%20Studios` |
| Open a collection from a pretty path | `yourwebsite.com/pricelist/city-studios` (set the collection's **Link slug** to `city-studios`) |
| Open unit 202 on Floor 2 | `?f=Floor%202&u=202` |
| Open unit 202 in project "Riverside Tower" (group/enterprise) | `?p=Riverside%20Tower&u=202` |
| Open unit 202 on Floor 2 in "Riverside Tower" (group/enterprise) | `?p=Riverside%20Tower&f=Floor%202&u=202` |
| Open commercial space "Shop A" (project with Skip Floor Step enabled) | `?u=Shop%20A` |
***
## Locked or Portal-Protected Viewers
If your viewer uses a Lock Screen or portal login, deep-links still work. The visitor is asked to log in or register first, and is then taken straight to the linked unit or collection — the link is never skipped, so your lead capture stays intact.
# Lock Screen
Source: https://viewerdocs.planpoint.io/lock-screen
The lock screen feature encourage visitors to share their information to gain access to your Planpoint before accessing the project plans. This approach ensures that your sales team can reach out to individuals showing interest in your project.
* Start by enabling the lock screen
* After enabling this feature, within the settings, activate the lock screen feature and specify the parameters you wish to gather from your leads, such as name, email, phone number. Alternatively, configure custom fields for the form according to your preferences.
* You can also enable the priority list feature that allows the customer to organize the list of preferred units of the project
# Media Gallery
Source: https://viewerdocs.planpoint.io/media-gallery
The **Media Gallery** allows you to upload many assets (such as images and plans) and apply them to many units at once.
Looking to let visitors pick between finish packages (kitchen, bathroom, etc.)? That lives in the **Custom finishes** sub-tab, see the [Choice of Finishes](/custom-finishes) guide.
### Video guide on how to use the Media Gallery
# Members
Source: https://viewerdocs.planpoint.io/members
Invite Admins or Editors to a specific projet or to the full account.
To access the Members module, click on Members on top of the project you wish to add it to in your dashboard. Alternatively, you can search for it within the Sales & Marketing module.

Click on the Invite members button to open up the menu. The table below will list all current members of a specific project.

Choose a permission level and simply enter the user's email address. **Administrators** have all rights except deleting the current project - this is a right only the main initial owner of a Planpoint account has. **Editors** can only edit the information contained inside the unit module. This is particularly useful for sales admin.

The member that you invited will receive an email from [support@planpoint.io](mailto:support@planpoint.io) asking them to accept the invitation by clicking on a hyperlink. They will be required to setup their account by creating a password to login. If invited to multiple projects with the same email, they will be able to see multiple projects in the dashboard and manage them from it.

For users with multiple Planpoints (projects), you can easily grant access to all of your projects at once for admins or editors. Simply navigate to the **Settings** in the top right corner of the dashboard and select the **Members** module to grant and manage permissions.

# Group project
Source: https://viewerdocs.planpoint.io/multi-phase
This article describes how to create a **multi-phase** or **multi-building** project, otherwise called a Group project.
**Prerequisite** You should have all your content already prepared. For more details about the content, please read the [checklist](/checklist).
### Video Guide for Visual Learners
## Troubleshooting
Here's how to solve some common problems when setting up your group project.
Please ensure that you have already created the group project and each individual phase of the project. Once everything is set up, simply click the box that appears when you hover your mouse over each individual project on the dashboard. Select all the phases you wish to add to the group project, and proceed to add them.
Please make sure that at the end of the URL in the preview link, you add: **?customColors=a** This ensures that the system recognizes and applies the color preferences you’ve set for the group project. If this parameter is not added, the default color will be displayed instead of your custom colors.
If you encounter an unknown error, please contact us at [support@planpoint.io](mailto:support@planpoint.io)
# Payments
Source: https://viewerdocs.planpoint.io/payments
Easily set up and accept payments for deposits and reservations in over 135 currencies and 40+ payment methods
Setting up your payments is straightforward, and best of all, you can customize various aspects of the payment process, as outlined below.
### How to Set Up Your Payments
**1. Select Your Project**\
Navigate to the project you wish to set up payments for and click on **Payments**.
**2. Access the Payments Module**\
After clicking on **Payments**, you will be redirected to the Payments module.
**3. Configure Payment Settings**\
In the Payments module, you can customize the following settings:
You will find two main sections in this module: the Planpoint section, where you can set up and customize your payments, and the Customers section, where you can view the history of all payments received.
The **Amount to be Charged** allows you to specify the charge amount. You can set a uniform amount for all units or customize the amount per unit. Additionally, you can select from over 135 supported currencies.
The **Button Information** section allows you to customize the text displayed on the payment button in the plan viewer. Additionally, you can upload an SVG file to use as an icon.
The **Statement Descriptor** explains the charges or payments that appear on your customers' bank statements.
The **Success Payment** allows you to provide a title and description to communicate the details of the reserved unit to your clients.
Once the user clicks the Payment button, the unit status will switch to **On Hold**. This status is temporary and unique to this process. It will remain On Hold for X minutes or until the user completes the payment, at which point the status will update to Reserved or Purchased.
Please note that you can enable or disable the payment options in the Settings module, under Style and Embed.
## Buy Now / Secure Above Asking
Buy Now can be enabled for individual units rather than the entire project. Go to **Settings > Style & Embed**, switch on **Buy Now / Secure Above Asking**, then use **Units with Buy Now enabled** to choose which units can use the payment flow.
* Selected units show the launch price, Buy Now price, and Buy Now action.
* Unselected units remain visible in the viewer but cannot use either Buy Now or the regular payment action while Buy Now is active.
* A unit with its own payment option disabled remains unavailable for payment even when selected.
When enabling Buy Now on a new project, select at least one unit before making the flow available to buyers. Existing Buy Now configurations created before the unit selector continue to apply to all units until an explicit selection is saved.
The **Additional amount** increases the displayed purchase price for Buy Now. It does not change the reservation fee configured in the Payments module.
## Custom Reservation Flow (CRF)
The **Custom Reservation Flow** is a guided, 3-step flow you can share with visitors instead of (or alongside) the regular plan viewer: they pick their favourite unit(s), book a time through Calendly, then optionally pay a refundable deposit to confirm.
This section only appears once your project has a Calendly connection (**Username** and **API Key**) set up under Settings, in the Connections section.
Set the deposit amount and currency that will be charged at the end of the booking flow, through the payment provider already connected to your account (Stripe or PayPal, configured in your Account Settings under Payments). Set the amount to **0** to skip the payment step entirely and only require the Calendly booking.
Copy the **Flow URL** link to share directly with visitors, or add `?crf=1` to your project's regular viewer URL to open it in the Custom Reservation Flow.
All deposits collected through the Custom Reservation Flow are recorded and listed under the **Transactions** tab of the Payments module.
# Style & Embed
Source: https://viewerdocs.planpoint.io/preview-embed
In this module, you can preview your project, edit hosting options and customize the style of your Planpoint Viewer.
### How to customize the style
If you want deeper style customization capabilities, check out our [Custom CSS article](https://viewerdocs.planpoint.io/custom-css). You will need a developer for this.
### How to embed
Planpoint can be embedded into any kind of website, from custom HTML/CSS/JS to platforms like Webflow, SquareSpace, Wix or WordPress. A Planpoint embed code is simply a few lines of HTML and JavaScript.

Paste the code where you want your Planpoint Viewer to appear. The Planpoint Viewer will obey the width of the parent element in which it's placed in. The height will be decided by the content inside the viewer. For example, if the building image's proportions are more vertical than horizontal, Planpoint Viewer will occupy more height on your page. You can stylize the parent element however you see fit, for example by adding padding or giving it a fixed width.
> A Responsive Inline Channel will horizontally fill the width of its parent element and grow vertically based on the content of the channel.

### Video Guide on how to embed
### Step-by-step guide
To access the **Style & Embed** module, locate the project you wish to access in your Planpoint dashboard and click on **the Style & Embed** button.

In the **Embed & Hosting** card, you'll find:
* **Project path** - the part of the URL that identifies this project (what used to be called the "namespace"). Changing it breaks any embed code already pasted on your site.
* **Language** - the language your embedded Viewer displays in. To support multiple languages on your site, generate and paste a separate embed code for each one.
* **Custom Domain** *(optional)* - serve your Viewer (and crawlable per-unit pages, for SEO) on your own subdomain instead of planpoint.io.
* **Embed Code** - click **Click to copy** to grab the current HTML/JS snippet for the language selected above.
* **Planpoint URL** - opens the live Viewer in a new tab, handy for testing before you paste the code anywhere.
Theme and color changes are no longer baked into the embed code - the Viewer always pulls your latest style live, so you never need to re-copy/re-paste the code after a style change. Only the **Project path** and **Language** affect the code itself.
Test your plan viewer with **Planpoint URL** and make changes accordingly - reload the tab after each change to see it take effect.
Further down, the **Style** card lets you fine-tune how the Viewer looks and behaves:
| Setting | What it does |
| - | - |
| Default view | Show units as a **List** or a **Grid** (2, 3 or 4 per row) |
| Grid image | In grid view, show the unit layout, the first gallery image, or a custom cover image per unit |
| Skeleton loading | Shows a loading placeholder while the Viewer loads |
| Mobile load behavior | Infinite scroll vs a "View more" button on mobile lists/grids |
| Default currency / Dynamic currency converter | Set the currency symbol shown, and optionally let visitors convert prices to their own currency live |
| Area Unit | ft² or m² |
| Show floor overview | Shows how many units are available on a floor on hover |
| Branding | Toggle the Planpoint logo/branding on the embed |
| Polygon outline | Adds a white outline to floor and unit polygons |
| Highlight animation | Animates the floors on first load, hinting that they're interactive |
Click **Customize Style** to pick a theme, set a custom color scheme (see the [color guide](/colors)), and edit your project's terminology.
# Go
Source: https://viewerdocs.planpoint.io/sdk-documentation/go
# planpoint-sdk-go
Official Go SDK for the [Planpoint](https://app.planpoint.io) API.
## Installation
```bash theme={null}
go get github.com/planpoint-io/planpoint-sdk-go
```
> **Note:** Responses use `JSON200` or `JSON201` depending on the endpoint. `login`, `getFloors`, and `getLeads` return `JSON200`. All other endpoints return `JSON201`.
## Quick Start
```go theme={null}
package main
import (
"context"
"fmt"
"net/http"
openapi_types "github.com/oapi-codegen/runtime/types"
planpoint "github.com/planpoint-io/planpoint-sdk-go"
)
func main() {
ctx := context.Background()
// 1. Authenticate
unauthClient, _ := planpoint.NewClientWithResponses("https://app.planpoint.io")
pass := "yourpassword"
loginResp, _ := unauthClient.LoginWithResponse(ctx, planpoint.LoginJSONRequestBody{
Username: openapi_types.Email("you@example.com"),
Password: &pass,
})
token := loginResp.JSON200.AccessToken
// 2. Create an authenticated client
client, _ := planpoint.NewClientWithResponses("https://app.planpoint.io",
planpoint.WithRequestEditorFn(func(ctx context.Context, req *http.Request) error {
req.Header.Set("Authorization", "Bearer "+token)
return nil
}),
)
// 3. Fetch your projects
projectsResp, _ := client.GetMyProjectsWithResponse(ctx)
fmt.Println(projectsResp.JSON201)
}
```
## API Reference
### Authentication
#### `LoginWithResponse(ctx, body)`
Authenticate and receive a JWT token.
| Field | Type | Required | Description |
| - | - | - | - |
| `body.Username` | `openapi_types.Email` | Yes | User email |
| `body.Password` | `*string` | No | User password |
| `body.Impersonate` | `*bool` | No | Impersonate another user |
**Returns:** `*LoginResponse` — `{ JSON200: *AuthResponse{ AccessToken, Message } }`
***
### Projects
#### `GetMyProjectsWithResponse(ctx)`
List all projects belonging to the authenticated user. Requires auth.
**Returns:** `*GetMyProjectsResponse` — `{ JSON201: *[]ProjectSummary }`
`ProjectSummary`: `{ Id, Name, Namespace?, HostName?, Status?, Paused?, CreatedAt? }`
***
#### `FindProjectWithResponse(ctx, body)`
Find a public project by namespace and hostname. No auth required.
| Field | Type | Required | Description |
| - | - | - | - |
| `body.Namespace` | `string` | Yes | Project namespace |
| `body.HostName` | `string` | Yes | Allowed hostname |
**Returns:** `*FindProjectResponse` — `{ JSON201: *Project }`
***
#### `GetProjectWithResponse(ctx, id)`
Get a project by ID. Requires auth.
| Param | Type | Required | Description |
| - | - | - | - |
| `id` | `string` | Yes | Project ObjectId |
**Returns:** `*GetProjectResponse` — `{ JSON201: *Project }`
***
#### `UpdateProjectWithResponse(ctx, id, body)`
Update project settings. Requires auth.
| Param | Type | Required | Description |
| - | - | - | - |
| `id` | `string` | Yes | Project ObjectId |
**Returns:** `*UpdateProjectResponse` — `{ JSON201: *Project }`
***
### Groups
#### `GetGroupsWithResponse(ctx)`
List all groups for the authenticated user. Requires auth.
**Returns:** `*GetGroupsResponse` — `{ JSON201: *GroupsListResponse{ Records, Count } }`
***
#### `GetGroupWithResponse(ctx, id)`
Get a group by ID. Requires auth.
| Param | Type | Required | Description |
| - | - | - | - |
| `id` | `string` | Yes | Group ObjectId |
**Returns:** `*GetGroupResponse` — `{ JSON201: *Group }`
***
#### `CreateGroupWithResponse(ctx, body)`
Create a new group. Requires auth.
**Returns:** `*CreateGroupResponse` — `{ JSON201: *Group }`
***
#### `UpdateGroupWithResponse(ctx, id, body)`
Update a group. Requires auth.
**Returns:** `*UpdateGroupResponse` — `{ JSON201: *Group }`
***
### Floors
#### `GetFloorsWithResponse(ctx, params)`
List all floors for a project. Requires auth.
| Param | Type | Required | Description |
| - | - | - | - |
| `params.Pid` | `string` | Yes | Project ObjectId |
**Returns:** `*GetFloorsResponse` — `{ JSON200: *[]FloorFull }`
`FloorFull`: `{ Id, Name?, Project, Level?, Position?, Path?, Image? }`
***
#### `GetFloorWithResponse(ctx, id)`
Get a floor by ID. Requires auth.
**Returns:** `*GetFloorResponse` — `{ JSON201: *FloorFull }`
***
#### `CreateFloorWithResponse(ctx, body)`
Create a new floor. Requires auth.
**Returns:** `*CreateFloorResponse` — `{ JSON201: *FloorFull }`
***
#### `UpdateFloorWithResponse(ctx, id, body)`
Update a floor. Requires auth.
**Returns:** `*UpdateFloorResponse` — `{ JSON201: *FloorFull }`
***
### Units
#### `GetUnitsWithResponse(ctx, params)`
List all units for a project. Requires auth.
| Param | Type | Required | Description |
| - | - | - | - |
| `params.Pid` | `string` | Yes | Project ObjectId |
**Returns:** `*GetUnitsResponse` — `{ JSON201: *UnitsListResponse{ Records, Count } }`
`UnitFull`: `{ Id, Floor, Name?, UnitNumber?, Status?, Price?, Bed?, Bath?, Sqft?, Model? }`
`Status` values: `Available` | `OnHold` | `Sold` | `Leased` | `Unavailable`
***
#### `GetUnitWithResponse(ctx, id)`
Get a unit by ID. Requires auth.
**Returns:** `*GetUnitResponse` — `{ JSON201: *UnitFull }`
***
#### `CreateUnitWithResponse(ctx, body)`
Create a new unit. Requires auth.
**Returns:** `*CreateUnitResponse` — `{ JSON201: *UnitFull }`
***
#### `UpdateUnitWithResponse(ctx, id, body)`
Update a unit. Requires auth.
**Returns:** `*UpdateUnitResponse` — `{ JSON201: *UnitFull }`
***
#### `DeleteUnitWithResponse(ctx, id)`
Delete a unit. Requires auth.
**Returns:** `*DeleteUnitResponse`
***
#### `BatchUpdateUnitsWithResponse(ctx, body)`
Update multiple units at once. Requires auth.
**Returns:** `*BatchUpdateUnitsResponse` — `{ JSON201: *[]UnitFull }`
***
### Leads
#### `GetLeadsWithResponse(ctx, params)`
List all leads for a project. Requires auth.
| Param | Type | Required | Description |
| - | - | - | - |
| `params.Pid` | `string` | Yes | Project ObjectId |
**Returns:** `*GetLeadsResponse` — `{ JSON200: *[]Lead }`
`Lead`: `{ Id?, Name?, Email?, Phone?, Message?, Unit?, CreatedAt? }`
***
## Links
* **[Install: go get github.com/planpoint-io/planpoint-sdk-go](https://github.com/planpoint-io/planpoint-sdk-go)**
* [Planpoint App](https://app.planpoint.io)
* [TypeScript SDK on npm](https://www.npmjs.com/package/@planpoint/sdk)
* [Python SDK on PyPI](https://pypi.org/project/planpoint-sdk)
* [PHP SDK on GitHub](https://github.com/planpoint-io/planpoint-sdk-php)
* [Java SDK on GitHub](https://github.com/planpoint-io/planpoint-sdk-java)
# Introduction to Planpoint SDK
Source: https://viewerdocs.planpoint.io/sdk-documentation/introduction
Integrate real estate project data into your application with the official Planpoint SDK.
## Overview
The Planpoint SDK gives developers programmatic access to the Planpoint platform — the same data that powers the interactive floor plan viewer on your website.
Use it to build custom dashboards, automate unit management, sync availability with your CRM, or embed project data into any application.
## What You Can Do
Log in with your Planpoint credentials and receive a JWT token to make authenticated requests.
List your projects, retrieve full project details including floors, units, and display settings.
Create, update, delete, and batch-update units. Control status, pricing, bedrooms, and more.
Create and update floor plans, set display order, and attach SVG paths or images.
Organize multiple projects under groups. Control team access with owner, admin, and editor roles.
Retrieve leads submitted through your project's contact forms, including contact details and unit interest.
## Core Concepts
### Authentication
All requests (except `findProject`) require a Bearer token. Obtain one by calling `login` with your Planpoint credentials. The token is a JWT and should be passed in the `Authorization` header of every subsequent request.
### Projects
A **Project** is the top-level entity. It contains floors, units, branding settings, and display configuration. Projects are identified by an `_id` (ObjectId) and a `namespace` (URL-friendly slug).
### Floors & Units
**Floors** are ordered levels within a project. Each floor contains **Units** — the individual listings with attributes like status, price, bedrooms, bathrooms, and square footage.
Unit status can be one of: `Available`, `OnHold`, `Sold`, `Leased`, or `Unavailable`.
### Groups
**Groups** allow you to organize multiple projects under a single entity (e.g. a development company). Groups support role-based access: `owner`, `admin`, and `editor`.
### Leads
**Leads** are contact form submissions captured through the Planpoint embed. Each lead includes name, email, phone, message, and the unit of interest.
## Available SDKs
Install via npm. Works in Node.js and browser environments.
```bash theme={null}
npm install @planpoint/sdk
```
Install via pip. Works with Python 3.8+.
```bash theme={null}
pip install planpoint-sdk
```
Install via `go get`. Works with Go 1.22+.
```bash theme={null}
go get github.com/planpoint-io/planpoint-sdk-go
```
Install via Composer. Works with PHP 8.1+.
```bash theme={null}
composer require planpoint/planpoint
```
Install via Maven or Gradle using JitPack. Works with Java 17+.
## Base URL
All API requests are made to:
```
https://app.planpoint.io
```
## Authentication Flow
```mermaid theme={null}
sequenceDiagram
participant App
participant Planpoint API
App->>Planpoint API: POST /api/users/login
Planpoint API-->>App: { access_token }
App->>Planpoint API: GET /api/projects/mine (Bearer token)
Planpoint API-->>App: ProjectSummary[]
```
# JavaScript
Source: https://viewerdocs.planpoint.io/sdk-documentation/java-script
# @planpoint/sdk
Official TypeScript SDK for the [Planpoint](https://app.planpoint.io) API.
## Installation
```bash theme={null}
npm install @planpoint/sdk
```
## Quick Start
```ts theme={null}
import { login, getMyProjects, createClient } from "@planpoint/sdk";
import { createClient } from "@hey-api/client-fetch";
// 1. Authenticate
const { data } = await login({
body: { username: "you@example.com", password: "yourpassword" },
});
// 2. Create an authenticated client
const client = createClient({
baseUrl: "https://app.planpoint.io",
headers: { Authorization: `Bearer ${data.access_token}` },
});
// 3. Fetch your projects
const { data: projects } = await getMyProjects({ client });
console.log(projects); // ProjectSummary[]
```
## API Reference
### Authentication
#### `login(options)`
Authenticate and receive a JWT token.
| Param | Type | Required | Description |
| - | - | - | - |
| `body.username` | `string` | Yes | User email |
| `body.password` | `string` | No | User password |
| `body.impersonate` | `boolean` | No | Impersonate another user |
**Returns:** `LoginResponse` — `{ message: string, access_token: string }`
***
### Projects
#### `getMyProjects(options)`
List all projects belonging to the authenticated user. Requires auth.
**Returns:** `ProjectSummary[]` — `{ _id, name, namespace?, hostName?, status?, paused?, createdAt? }`
***
#### `findProject(options)`
Find a public project by namespace and hostname. No auth required.
| Param | Type | Required | Description |
| - | - | - | - |
| `body.namespace` | `string` | Yes | Project namespace |
| `body.hostName` | `string` | Yes | Allowed hostname |
**Returns:** `Project` — full project with floors, units, settings
***
#### `getProject(options)`
Get a project by ID. Requires auth.
| Param | Type | Required | Description |
| - | - | - | - |
| `path.id` | `string` | Yes | Project ObjectId |
**Returns:** `Project`
***
#### `updateProject(options)`
Update project settings. Requires auth.
| Param | Type | Required | Description |
| - | - | - | - |
| `path.id` | `string` | Yes | Project ObjectId |
| `body` | `Record` | Yes | Fields to update |
**Returns:** `Project`
***
### Groups
#### `getGroups(options)`
List all groups for the authenticated user.
**Returns:** `GroupsListResponse` — `{ records: Group[], count: number }`
***
#### `getGroup(options)`
Get a group by ID.
| Param | Type | Required | Description |
| - | - | - | - |
| `path.id` | `string` | Yes | Group ObjectId |
**Returns:** `Group` — `{ _id, name, namespace?, hostName?, type?, projects?, isOwner?, isAdmin?, isEditor? }`
***
#### `createGroup(options)`
Create a new group.
| Param | Type | Required | Description |
| - | - | - | - |
| `body.name` | `string` | Yes | Group name |
| `body.namespace` | `string` | No | Namespace |
| `body.hostName` | `string` | No | Hostname |
| `body.type` | `string` | No | Group type |
| `body.propertyType` | `string` | No | Property type |
**Returns:** `Group`
***
#### `updateGroup(options)`
Update a group.
| Param | Type | Required | Description |
| - | - | - | - |
| `path.id` | `string` | Yes | Group ObjectId |
| `body` | `Record` | Yes | Fields to update |
**Returns:** `Group`
***
### Floors
#### `getFloors(options)`
List all floors for a project.
| Param | Type | Required | Description |
| - | - | - | - |
| `query.pid` | `string` | Yes | Project ObjectId |
**Returns:** `FloorFull[]` — `{ _id, name?, project, level?, position?, path?, image? }`
***
#### `getFloor(options)`
Get a floor by ID.
| Param | Type | Required | Description |
| - | - | - | - |
| `path.id` | `string` | Yes | Floor ObjectId |
**Returns:** `FloorFull`
***
#### `createFloor(options)`
Create a new floor.
| Param | Type | Required | Description |
| - | - | - | - |
| `body.project._id` | `string` | Yes | Project ObjectId |
| `body.name` | `string` | Yes | Floor name |
| `body.position` | `number` | No | Display order |
| `body.path` | `string` | No | SVG/image path |
| `body.alternativePaths` | `string[]` | No | Additional paths |
**Returns:** `FloorFull`
***
#### `updateFloor(options)`
Update a floor.
| Param | Type | Required | Description |
| - | - | - | - |
| `path.id` | `string` | Yes | Floor ObjectId |
| `body` | `Record` | Yes | Fields to update |
**Returns:** `FloorFull`
***
### Units
#### `getUnits(options)`
List all units for a project.
| Param | Type | Required | Description |
| - | - | - | - |
| `query.pid` | `string` | Yes | Project ObjectId |
**Returns:** `UnitsListResponse` — `{ records: UnitFull[], count: number }`
`UnitFull`: `{ _id, floor, name?, unitNumber?, status?, price?, bed?, bath?, sqft?, model?, orientation?, parking? }`
`status` values: `Available` | `OnHold` | `Sold` | `Leased` | `Unavailable`
***
#### `getUnit(options)`
Get a unit by ID.
| Param | Type | Required | Description |
| - | - | - | - |
| `path.id` | `string` | Yes | Unit ObjectId |
**Returns:** `UnitFull`
***
#### `createUnit(options)`
Create a new unit.
| Param | Type | Required | Description |
| - | - | - | - |
| `body.floor._id` | `string` | Yes | Floor ObjectId |
**Returns:** `UnitFull`
***
#### `updateUnit(options)`
Update a unit.
| Param | Type | Required | Description |
| - | - | - | - |
| `path.id` | `string` | Yes | Unit ObjectId |
| `body` | `Record` | Yes | Fields to update |
**Returns:** `UnitFull`
***
#### `deleteUnit(options)`
Delete a unit.
| Param | Type | Required | Description |
| - | - | - | - |
| `path.id` | `string` | Yes | Unit ObjectId |
**Returns:** `{ message: string }`
***
#### `batchUpdateUnits(options)`
Update multiple units at once.
| Param | Type | Required | Description |
| - | - | - | - |
| `body.ids` | `string[]` | Yes | Unit ObjectIds to update |
| `body.patchData` | `Record` | Yes | Fields to apply to all |
**Returns:** `UnitFull[]`
***
### Leads
#### `getLeads(options)`
List all leads for a project.
| Param | Type | Required | Description |
| - | - | - | - |
| `query.pid` | `string` | Yes | Project ObjectId |
**Returns:** `Lead[]` — `{ _id?, name?, email?, phone?, message?, unit?, createdAt? }`
***
## TypeScript Support
All methods are fully typed. Import types directly:
```ts theme={null}
import type {
Project,
ProjectSummary,
Group,
GroupsListResponse,
FloorFull,
UnitFull,
UnitsListResponse,
Lead,
LoginResponse,
} from "@planpoint/sdk";
```
## Links
* [**Install on npm: npm install @planpoint/sdk**](https://www.npmjs.com/package/@planpoint/sdk)
* [Planpoint App](https://app.planpoint.io)
* [Python SDK on PyPI](https://pypi.org/project/planpoint-sdk)
* [Go SDK on GitHub](https://github.com/planpoint-io/planpoint-sdk-go)
* [PHP SDK on GitHub](https://github.com/planpoint-io/planpoint-sdk-php)
* [Java SDK on GitHub](https://github.com/planpoint-io/planpoint-sdk-java)
# PHP
Source: https://viewerdocs.planpoint.io/sdk-documentation/php
# planpoint-sdk-php
Official PHP SDK for the [Planpoint](https://app.planpoint.io) API.
## Requirements
* PHP 8.1+
* Composer
## Installation
Create a `composer.json` in your project:
```json theme={null}
{
"require": { "planpoint/planpoint": "dev-main" },
"repositories": [
{
"type": "vcs",
"url": "https://github.com/planpoint-io/planpoint-sdk-php"
}
],
"minimum-stability": "dev"
}
```
Then install:
```bash theme={null}
composer install
```
> **SSL Note:** If you get a cURL SSL certificate error on Windows, download the CA bundle and add to your `php.ini`:
>
> ```ini theme={null}
> curl.cainfo=C:\path\to\cacert.pem
> openssl.cafile=C:\path\to\cacert.pem
> ```
>
> Download `cacert.pem` from [curl.se/ca/cacert.pem](https://curl.se/ca/cacert.pem).
## Quick Start
```php theme={null}
authentication->login(
new \Planpoint\Authentication\Requests\LoginBody([
'username' => 'you@example.com',
'password' => 'yourpassword',
])
);
$token = $loginResp->accessToken;
// 2. Create an authenticated client
$client = new PlanpointClient($token);
// 3. Fetch your projects
$projects = $client->projects->getMyProjects();
foreach ($projects as $project) {
echo $project->name . "\n";
}
```
## API Reference
### Authentication
#### `$client->authentication->login(LoginBody $request)`
Authenticate and receive a JWT token.
| Field | Type | Required | Description |
| - | - | - | - |
| `username` | `string` | Yes | User email |
| `password` | `string` | No | User password |
| `impersonate` | `bool` | No | Impersonate another user |
**Returns:** `LoginResponse` — `->accessToken: string`
***
### Projects
#### `$client->projects->getMyProjects()`
List all projects belonging to the authenticated user. Requires auth.
**Returns:** `ProjectSummary[]` — `->name`, `->namespace`, `->hostName`, `->status`, `->paused`, `->createdAt`
***
#### `$client->projects->findProject(FindProjectRequest $request)`
Find a public project by namespace and hostname. No auth required.
| Field | Type | Required | Description |
| - | - | - | - |
| `namespace` | `string` | Yes | Project namespace |
| `hostName` | `string` | Yes | Allowed hostname |
**Returns:** `Project` — full project with floors, units, settings
***
#### `$client->projects->getProject(string $id)`
Get a project by ID. Requires auth.
| Param | Type | Required | Description |
| - | - | - | - |
| `$id` | `string` | Yes | Project ObjectId |
**Returns:** `Project`
***
#### `$client->projects->updateProject(string $id, UpdateProjectRequest $request)`
Update project settings. Requires auth.
**Returns:** `Project`
***
### Groups
#### `$client->groups->getGroups()`
List all groups for the authenticated user. Requires auth.
**Returns:** `GroupsListResponse` — `->records: Group[]`, `->count: int`
***
#### `$client->groups->getGroup(string $id)`
Get a group by ID. Requires auth.
**Returns:** `Group` — `->name`, `->namespace`, `->hostName`, `->type`, `->projects`, `->isOwner`, `->isAdmin`, `->isEditor`
***
#### `$client->groups->createGroup(CreateGroupRequest $request)`
Create a new group. Requires auth.
| Field | Type | Required | Description |
| - | - | - | - |
| `name` | `string` | Yes | Group name |
| `namespace` | `string` | No | Namespace |
| `hostName` | `string` | No | Hostname |
| `type` | `string` | No | Group type |
| `propertyType` | `string` | No | Property type |
**Returns:** `Group`
***
#### `$client->groups->updateGroup(string $id, UpdateGroupRequest $request)`
Update a group. Requires auth.
**Returns:** `Group`
***
### Floors
#### `$client->floors->getFloors(GetFloorsRequest $request)`
List all floors for a project. Requires auth.
| Field | Type | Required | Description |
| - | - | - | - |
| `pid` | `string` | Yes | Project ObjectId |
**Returns:** `FloorFull[]` — `->name`, `->project`, `->level`, `->position`, `->path`, `->image`
***
#### `$client->floors->getFloor(string $id)`
Get a floor by ID. Requires auth.
**Returns:** `FloorFull`
***
#### `$client->floors->createFloor(CreateFloorRequest $request)`
Create a new floor. Requires auth.
| Field | Type | Required | Description |
| - | - | - | - |
| `project` | `array` | Yes | `['_id' => '']` |
| `name` | `string` | Yes | Floor name |
| `position` | `int` | No | Display order |
| `path` | `string` | No | SVG/image path |
| `alternativePaths` | `string[]` | No | Additional paths |
**Returns:** `FloorFull`
***
#### `$client->floors->updateFloor(string $id, UpdateFloorRequest $request)`
Update a floor. Requires auth.
**Returns:** `FloorFull`
***
### Units
#### `$client->units->getUnits(GetUnitsRequest $request)`
List all units for a project. Requires auth.
| Field | Type | Required | Description |
| - | - | - | - |
| `pid` | `string` | Yes | Project ObjectId |
**Returns:** `UnitsListResponse` — `->records: UnitFull[]`, `->count: int`
`UnitFull` fields: `->floor`, `->name`, `->unitNumber`, `->status`, `->price`, `->bed`, `->bath`, `->sqft`, `->model`, `->orientation`, `->parking`
`status` values: `Available` | `OnHold` | `Sold` | `Leased` | `Unavailable`
***
#### `$client->units->getUnit(string $id)`
Get a unit by ID. Requires auth.
**Returns:** `UnitFull`
***
#### `$client->units->createUnit(CreateUnitRequest $request)`
Create a new unit. Requires auth.
| Field | Type | Required | Description |
| - | - | - | - |
| `floor` | `array` | Yes | `['_id' => '']` |
**Returns:** `UnitFull`
***
#### `$client->units->updateUnit(string $id, UpdateUnitRequest $request)`
Update a unit. Requires auth.
**Returns:** `UnitFull`
***
#### `$client->units->deleteUnit(string $id)`
Delete a unit. Requires auth.
**Returns:** `array` — `['message' => string]`
***
#### `$client->units->batchUpdateUnits(BatchUpdateUnitsRequest $request)`
Update multiple units at once. Requires auth.
| Field | Type | Required | Description |
| - | - | - | - |
| `ids` | `string[]` | Yes | Unit ObjectIds to update |
| `patchData` | `array` | Yes | Fields to apply to all |
**Returns:** `UnitFull[]`
***
### Leads
#### `$client->leads->getLeads(GetLeadsRequest $request)`
List all leads for a project. Requires auth.
| Field | Type | Required | Description |
| - | - | - | - |
| `pid` | `string` | Yes | Project ObjectId |
**Returns:** `Lead[]` — `->name`, `->email`, `->phone`, `->message`, `->unit`, `->createdAt`
***
## Links
* **[Install via GitHub (Composer)](https://github.com/planpoint-io/planpoint-sdk-php)**
* [Planpoint App](https://app.planpoint.io)
* [TypeScript SDK on npm](https://www.npmjs.com/package/@planpoint/sdk)
* [Python SDK on PyPI](https://pypi.org/project/planpoint-sdk)
* [Go SDK on GitHub](https://github.com/planpoint-io/planpoint-sdk-go)
* [Java SDK on GitHub](https://github.com/planpoint-io/planpoint-sdk-java)
# Python
Source: https://viewerdocs.planpoint.io/sdk-documentation/untitled-page
# planpoint-sdk
Official Python SDK for the [Planpoint](https://app.planpoint.io) API.
## Installation
```bash theme={null}
pip install planpoint-sdk
```
## Quick Start
```python theme={null}
import planpoint
# 1. Authenticate
auth_client = planpoint.PlanpointApi(token=None)
login_response = auth_client.authentication.login(
username="you@example.com",
password="yourpassword"
)
token = login_response.token
# 2. Create an authenticated client
client = planpoint.PlanpointApi(token=token)
# 3. Fetch your projects
projects = client.projects.get_my_projects()
for p in projects:
print(p.name, p.namespace)
```
## API Reference
### Authentication
#### `client.authentication.login(**kwargs)`
Authenticate and receive a JWT token.
| Param | Type | Required | Description |
| - | - | - | - |
| `username` | `str` | Yes | User email |
| `password` | `str` | No | User password |
| `impersonate` | `bool` | No | Impersonate another user |
**Returns:** `LoginResponse` — `.token: str`
***
### Projects
#### `client.projects.get_my_projects()`
List all projects belonging to the authenticated user. Requires auth.
**Returns:** `list[ProjectSummary]` — `.name`, `.namespace`, `.host_name`, `.status`, `.paused`, `.created_at`
***
#### `client.projects.find_project(**kwargs)`
Find a public project by namespace and hostname. No auth required.
| Param | Type | Required | Description |
| - | - | - | - |
| `namespace` | `str` | Yes | Project namespace |
| `host_name` | `str` | Yes | Allowed hostname |
**Returns:** `Project` — full project with floors, units, settings
***
#### `client.projects.get_project(**kwargs)`
Get a project by ID. Requires auth.
| Param | Type | Required | Description |
| - | - | - | - |
| `id` | `str` | Yes | Project ObjectId |
**Returns:** `Project`
***
#### `client.projects.update_project(**kwargs)`
Update project settings. Requires auth.
| Param | Type | Required | Description |
| - | - | - | - |
| `id` | `str` | Yes | Project ObjectId |
| `request` | `dict` | Yes | Fields to update |
**Returns:** `Project`
***
### Groups
#### `client.groups.get_groups()`
List all groups for the authenticated user.
**Returns:** `GroupsListResponse` — `.records: list[Group]`, `.count: int`
***
#### `client.groups.get_group(**kwargs)`
Get a group by ID.
| Param | Type | Required | Description |
| - | - | - | - |
| `id` | `str` | Yes | Group ObjectId |
**Returns:** `Group` — `.name`, `.namespace`, `.host_name`, `.type`, `.projects`, `.is_owner`, `.is_admin`, `.is_editor`
***
#### `client.groups.create_group(**kwargs)`
Create a new group.
| Param | Type | Required | Description |
| - | - | - | - |
| `name` | `str` | Yes | Group name |
| `namespace` | `str` | No | Namespace |
| `host_name` | `str` | No | Hostname |
| `type` | `str` | No | Group type |
| `property_type` | `str` | No | Property type |
**Returns:** `Group`
***
#### `client.groups.update_group(**kwargs)`
Update a group.
| Param | Type | Required | Description |
| - | - | - | - |
| `id` | `str` | Yes | Group ObjectId |
| `request` | `dict` | Yes | Fields to update |
**Returns:** `Group`
***
### Floors
#### `client.floors.get_floors(**kwargs)`
List all floors for a project.
| Param | Type | Required | Description |
| - | - | - | - |
| `pid` | `str` | Yes | Project ObjectId |
**Returns:** `list[FloorFull]` — `.name`, `.project`, `.level`, `.position`, `.path`, `.image`
***
#### `client.floors.get_floor(**kwargs)`
Get a floor by ID.
| Param | Type | Required | Description |
| - | - | - | - |
| `id` | `str` | Yes | Floor ObjectId |
**Returns:** `FloorFull`
***
#### `client.floors.create_floor(**kwargs)`
Create a new floor.
| Param | Type | Required | Description |
| - | - | - | - |
| `project` | `dict` | Yes | `{"_id": ""}` |
| `name` | `str` | Yes | Floor name |
| `position` | `int` | No | Display order |
| `path` | `str` | No | SVG/image path |
| `alternative_paths` | `list[str]` | No | Additional paths |
**Returns:** `FloorFull`
***
#### `client.floors.update_floor(**kwargs)`
Update a floor.
| Param | Type | Required | Description |
| - | - | - | - |
| `id` | `str` | Yes | Floor ObjectId |
| `request` | `dict` | Yes | Fields to update |
**Returns:** `FloorFull`
***
### Units
#### `client.units.get_units(**kwargs)`
List all units for a project.
| Param | Type | Required | Description |
| - | - | - | - |
| `pid` | `str` | Yes | Project ObjectId |
**Returns:** `UnitsListResponse` — `.records: list[UnitFull]`, `.count: int`
`UnitFull` fields: `.floor`, `.name`, `.unit_number`, `.status`, `.price`, `.bed`, `.bath`, `.sqft`, `.model`, `.orientation`, `.parking`
`status` values: `Available` | `OnHold` | `Sold` | `Leased` | `Unavailable`
***
#### `client.units.get_unit(**kwargs)`
Get a unit by ID.
| Param | Type | Required | Description |
| - | - | - | - |
| `id` | `str` | Yes | Unit ObjectId |
**Returns:** `UnitFull`
***
#### `client.units.create_unit(**kwargs)`
Create a new unit.
| Param | Type | Required | Description |
| - | - | - | - |
| `floor` | `dict` | Yes | `{"_id": ""}` |
**Returns:** `UnitFull`
***
#### `client.units.update_unit(**kwargs)`
Update a unit.
| Param | Type | Required | Description |
| - | - | - | - |
| `id` | `str` | Yes | Unit ObjectId |
| `request` | `dict` | Yes | Fields to update |
**Returns:** `UnitFull`
***
#### `client.units.delete_unit(**kwargs)`
Delete a unit.
| Param | Type | Required | Description |
| - | - | - | - |
| `id` | `str` | Yes | Unit ObjectId |
**Returns:** `dict` — `{ "message": str }`
***
#### `client.units.batch_update_units(**kwargs)`
Update multiple units at once.
| Param | Type | Required | Description |
| - | - | - | - |
| `ids` | `list[str]` | Yes | Unit ObjectIds to update |
| `patch_data` | `dict` | Yes | Fields to apply to all |
**Returns:** `list[UnitFull]`
***
### Leads
#### `client.leads.get_leads(**kwargs)`
List all leads for a project.
| Param | Type | Required | Description |
| - | - | - | - |
| `pid` | `str` | Yes | Project ObjectId |
**Returns:** `list[Lead]` — `.name`, `.email`, `.phone`, `.message`, `.unit`, `.created_at`
***
## Links
* [**Install on PyPI: pip install planpoint-sdk**](https://pypi.org/project/planpoint-sdk)
* [Planpoint App](https://app.planpoint.io)
* [TypeScript SDK on npm](https://www.npmjs.com/package/@planpoint/sdk)
* [Go SDK on GitHub](https://github.com/planpoint-io/planpoint-sdk-go)
* [PHP SDK on GitHub](https://github.com/planpoint-io/planpoint-sdk-php)
* [Java SDK on GitHub](https://github.com/planpoint-io/planpoint-sdk-java)
# Settings
Source: https://viewerdocs.planpoint.io/settings
This article describes how to create a plan viewer with Planpoint starting with the first module: the general settings.
**Prerequisite** You should have all your content already prepared. For more details about the content, please read the [checklist](/checklist).
Click on the + New project button on the upper left side of the dashboard.

Assign a project name, address, choose the project type (sales, rental, land, commercial), and select whether you want to skip the floor or not. This allows you to jump directly from the project render to the unit you choose to view. This feature is typically used for small projects.

You can also copy settings from other projects. This allows you to set up projects faster when they have similar or identical configurations. If you have a promo code, you can enter it here as well.

Choose the specific plan for this specific project. Plans are based on the number of **units per project.** Larger real estate projects require a larger monthly plan.

The project is now created but empty. In your dahsboard, click on **details.**

This will redirect you to the **settings** module, where you will find the following tabs:

Under **details** you can do the following:
* Define a cover image. This is the image that will appear in the card preview of the project in the dashboard and will also be your main building image. Please choose a high-resolution image, but no bigger than 1 MB. You can also choose a secondary project image, which you can use if you want to change the project’s main image.
* Edit the project's name.
* Turn the Skip Floor Step feature on or off.
* If you wish, you can add the website URL of your project, which will redirect you to the project's website.
* You can also add an internal URL for the project. This is intended for your marketing and sales teams.

Pause or delete the project's subscription.

After finishing with the project details, move on to the **customization** tab. Here you can do the following:
* Select the property type (Condominium, rental, townhouse, house, land, retail, office, commercial, industrial).
* Turn on/off prices. When turned on, the plan viewer will show each unit's price.
* Turn on/off availabilities. When turned on, the plan viewer will specify whether each unit is available or not.
* You can choose which units to display based on their status. You can display all units, all units except sold units, or only available units.
* Turn on/off the unit information freely. This includes inclusions, parking, orientation, bathrooms, descriptions, finishes and more.
* Turn on/off the [Choice of Finishes](/custom-finishes) feature, letting visitors pick between different finish packages for a unit.
* You can choose which filters to display in the plan viewer and drag them into your preferred order.

* The Unit Display Fields section lets you choose which elements of a unit you want to display in the project. For example, if your project doesn’t have an orientation feature, you can hide it. Similarly, if the project doesn’t have a media gallery, you can hide that field as well.
* The Engagement Features section lets you manage the interactive tools available in your Planpoint Viewer. You can quickly enable or disable features such as favorites, sharing, featured units, custom forms, custom buttons, sponsors, and Walk Score. For Custom Buttons, you can create multiple calls to action, choose where they appear, add an icon, localize them by language, and define what happens when users click them.

* Finishing this section, we can see everything related to enterprise. Here you can add the project to the enterprise you have already created. Learn more about the [enterprise feature](https://viewerdocs.planpoint.io/enterprise).

Keep in mind that you can always preview your work in progress by navigating to the settings module, under the **Style & Embed** tab
## Troubleshooting
Here's how to solve some common problems when setting up a project.
Please remember to add a credit card to your profile before initiating a project.
Yes, you can change a monthly plan for a project only if it's a **rental** one. Rental projects are based in vacant units.
For any connections, please contact us via support @ planpoint.io.
# Spotlight Mode
Source: https://viewerdocs.planpoint.io/spotlight
Place interactive pins on your exterior image and let visitors explore selected properties on desktop and mobile.
Spotlight presents your exterior images with clickable pins connected to your inventory. It is an alternative entry point to the viewer: visitors can explore properties directly from the image instead of starting with the usual floor selection.
On desktop, the image appears beside the inventory. On mobile, visitors can tap a pin, swipe through property cards, and open a dedicated filter sheet.
## Before You Start
* Add a main [exterior image](/exterior) to your project. Add alternative exterior views there when you want a 360-style sequence.
* Create the [units](/units) or spaces you want to link to pins, including their names, images, and availability.
* Check the project's filter and visibility settings. Spotlight uses the same inventory data as the regular viewer.
Spotlight uses the main and alternative exterior covers automatically. There
is no separate Spotlight image upload. If you replace or reorder an exterior,
review that view's pin positions because the image composition may have
changed.
## Set Up Spotlight
Open your project in the dashboard, go to **Sales & Marketing**, then select **Spotlight > General**.
The configuration includes **Pinpoints editing**, **Pinpoints color**, **Spotlight URL**, and **Embed code**.
Beside **Pinpoints editing**, click **Add** or **Edit** to open the full-screen editor.
Click an empty location on the image to create a pin. The target picker opens so you can choose the unit or space that the pin represents.
When the project has multiple exterior covers, use the numbered exterior selector at the top of the editor before placing pins. Each pin belongs to the exterior on which it was created. Existing pins created before multi-exterior support remain on exterior **1**.
Select the correct target in the picker. Click an existing pin to change its target, or use **Delete pinpoint** in the picker to remove it.
For a standard project, pins link to units. Projects that skip the floor step use spaces. Group and enterprise configurations offer their corresponding project or group target pickers.
Drag a pin to reposition it without reopening the target picker. A focused pin can also be nudged with the arrow keys; hold **Shift** for a larger adjustment.
Use **Pin color** and **Pin size** inside the editor to adjust the dots. Changes appear immediately. The size applies to all pins and supports a radius of **6-24 px**, with **10 px** as the default.
Click **Save** to persist the pin positions, targets, deletions, color, and size together. Then close the editor. You can also use **Pinpoints color** in the General configuration for a quick color change without opening the editor.
Closing the editor is not a substitute for clicking Save. Save your changes before leaving the editor or reloading the dashboard.
## Share or Embed Spotlight
Use **Spotlight URL > Open in new tab** to preview the configured experience. Share that URL to send visitors directly to Spotlight.
The Spotlight URL must include the `spotlight=true` query parameter. If you build the URL in code, append the parameter to the regular viewer URL.
When multiple exterior covers are available, use the **360°** control at the top of the image. On desktop, click its left half for the previous exterior or its right half for the next exterior. A regular tap advances to the next exterior.
To place it on your website, click **Embed code > Click to copy** and insert the generated code into your website's HTML or embed block. Give the embed enough vertical space for both the exterior and the inventory on mobile.
The generated Spotlight link includes `spotlight=true`. Keep this parameter
when sharing the link. The regular viewer URL remains available; configuring
pins does not replace its default opening view.
See [Style & Embed](/preview-embed) for general embedding settings.
## What Visitors See
### Desktop
Visitors see the exterior beside the inventory cards. Hovering over a unit pin reveals its preview, and clicking it opens that unit's details. When multiple exteriors are available, the **360°** control cycles through them and shows the pins configured for each view. Inventory filters remain available alongside the image.
### Mobile
The exterior sits above a horizontally scrollable inventory. Tap a unit pin to bring its matching card into view, swipe the cards to explore, and tap a card to open the property's details. For projects with multiple exteriors, tap the **360°** control to move through the views.
The inventory header shows the matching result count. **Filters** opens a bottom sheet with the project's enabled filters and an active-filter count on the button. Choose options or adjust ranges, then use the checkmark or close button to return to the cards. **Clear all** resets the selections.
The sheet keeps its close and reset controls available while the filter content scrolls. Motion is reduced when the visitor's device requests reduced motion.
## Review Before Publishing
* Open the generated Spotlight URL on desktop and mobile.
* Confirm each pin points to the intended property and opens or selects the correct item.
* Check pin positions on every configured exterior view.
* Verify that names, images, availability, and enabled filters are correct.
* Test the actual website embed, including short phone screens, not just the standalone viewer.
## Troubleshooting
Add a main exterior image first. The Pinpoints editing row is only available when the entity has a main cover.
Open the editor, click that pin, choose the correct target, and click Save. Reload the Spotlight URL to verify the change.
Check whether an exterior image was replaced, recomposed, or reordered. Pin locations are stored for a specific exterior and relative to that image, so a different composition may require repositioning them.
Open the pin editor and select that exterior's number before adding its pins. Pins are configured independently for each exterior; pins created before this feature remain on exterior 1.
Clear the active filters, verify the pin's target, and review the project's availability and visibility settings. Linking a pin does not override the normal visibility rules.
Copy the Spotlight URL from Sales & Marketing > Spotlight > General again and ensure the spotlight=true parameter has not been removed by your website or link tool.
# Superframe & Touchscreen TVs
Source: https://viewerdocs.planpoint.io/superframe
A specialized app designed to enhance your sales presentations on touchscreen TVs or tablets.
The process for creating the superframe is simple and straightforward. Please follow the next steps.
**Download** the Superframe app for Windows, macOS and iPadOS [on our website](https://www.planpoint.io/new-releases/superframe).
***
## Video Guide for Visual Learners
***
The Superframe section can be found in the Sales & Marketing module.

You can update the project logo displayed in the Superframe by simply browsing and uploading a file from your device. Additionally, you can customize the color scheme and text color to match your branding.

Here, you can divide the interior of the project into different rooms of the unit, allowing you to display each section separately. Please note that you can fully customize your project to suit your needs.

After adding a new gallery set, you'll need to upload the main render for the room by clicking the cloud storage icon and selecting the file from your computer.

The edit button allows the user to add a title for the room, include a 3D tour link (if available), and upload the image gallery for this area.

You can also delete the gallery set by simply clicking the trash can icon.
In this section, you can add content related to the common areas of the project. It follows the same format as the previous section (interior).
Simply add your choice of finishes to the project and edit the gallery set as demonstrated in the previous steps.

To add a video of the project or a map showing its location, simply insert the respective links. You can add multiple videos if needed.
The aspect ratio for televisions is 16:9 and Planpoint Superframe will make your images fit the screen entirely.
Since most images and renders don't follow this 16:9 ratio, your images might not appear in full.
We recommend adjusting your images before importing. Here's an example of a render that was adjusted to 16:9 ratio by adding blur on both sides:
Visits made on a Superframe screen are recorded separately from your public embed. In [Analytics](/analytics), use the **Per Channel** filter to compare **Web** and **Superframe** engagement.
# Unit variants
Source: https://viewerdocs.planpoint.io/unit-variants
The **Unit variants** feature is extremely useful for home development projects where many types of models of the same house can be sold on the same plot of land. It displays the various variants inside a neat menu for quick and easy access.
### Here's a video guide:
# Units
Source: https://viewerdocs.planpoint.io/units
Need to draw unit boundaries on a floorplan? See [AI Unit Detection](/floors#ai-unit-detection) to detect, match and review the outlines before saving them.
The unit tab now contains all the floors previously created in the exterior module. You can import a CSV file containing all your units for quicker upload.
Download the [Excel template here](https://app.planpoint.io/assets/template.xlsx). The download button, located next to the upload button, allows you to download a CSV file of the current unit list. This feature is particularly useful if you need to make bulk updates to the unit list and re-upload it to update the project.
Please view the following video to understand how to prepare your Excel file before import:
You can also add units manually, one-by-one. Click on **Add unit** on the corresponding floor and repeat for each unit.
Once the units are imported, you will see the unit menu. It contains several other features that you can access through the icons on the right.
1. The **first** icon is for uploading a cover image for this specific unit. It will only be visible in the plan viewer when using grid mode.
2. The **second** icon is for uploading different finishes for this unit.
3. The **third** icon is for uploading an image gallery for this specific unit. For example, you could show interior renderings or exterior drone views.
4. The **fourth** icon allows you to add a URL for your custom button. This URL will redirect users to the selected website when the custom button is clicked. For example, you can add a "Book a Tour" button. The URL can be added to individual units or applied to multiple units as needed.
5. The **fifth** icon is for embedding a 3D virtual visit. You can simply copy-paste code from [Kuula](https://kuula.co/) or other virtual visit providers.
6. The **sixth** icon is for uploading the PDF version of the unit's plan layout. This PDF will be downloadable by the end-user.
7. The **seventh** icon is for uploading a JPG or PNG version of the unit's plan layout. This image will be shown in the plan viewer but is not downloadable.
8. The **eighth** icon allows you to define the perimeters of the lots in a [Homes & Land project](https://viewerdocs.planpoint.io/homes-land)
9. The **ninth** icon lets you edit the unit number, the model number, the type of unit, the area, the number of bedrooms, the price, availability, the occupancy dates, inclusions, description, number of bathrooms, the number of parking spaces and orientation.
10. The **tenth** icon is used to delete this specific unit.
\*The number in parentheses next to the floor number represents the total number of units on that floor.
With all your units in the system, you can click on the edit icon (ninth from the left), allowing you to modify the unit's basic information.

* The **Name** is your internal referral number. It can be numerical or alphanumerical.
* The **Model** number is the unit's model layout. A particular model can reappear on the same floor or on different floors. In such instance, simply writing the model number in this field will automatically fill up the area, number of bedrooms, price and availability fields.
* You assign a **Type** if the unit is either a parking or an amenity.
* The **Area** is the square footage or square meter of this particular plan. You decide wether to show net or gross area.
* The **Bedrooms** field is a simple dropdown choice.
* The **Price** number is the unit's price. For sales, you would enter the full list price (before or after tax is your choice). For rentals, you would enter the monthly rent amount.
* The **Availability** field is a simple dropdown choice between Available, Unavailable, Sold and Reserved. The unavailable units will not be shown in the plan viewer and the sold units cannot be clicked on in the plan viewer.
* The **Occupancy date** can be be selected on a calendar to show when the unit will be available.
* The **Inclusions** can be added in a comma separated list.
* The **Description** of the unit must be added as a text.
* For **Bathrooms**, just type the number of bathrooms the unit has.
* For **Parking Spaces**, just type the number of parking spaces the unit has.
\*The **Orientation** indicates the direction the unit will face. For example, you can specify "Mountain View" or simply "South."
If you do not observe the changes made to your units, please refresh the page.
## Troubleshooting
Here's how to solve some common problems when uploading units to the project.
It is crucial to meticulously follow each step outlined in the import video. If the problem persists, please contact us.
Yes, you have the option to upload an updated version of the CSV file, and it will overwrite the existing content. You can perform this action as many times as needed.
# Java
Source: https://viewerdocs.planpoint.io/untitled-page
# planpoint-sdk-java
Official Java SDK for the [Planpoint](https://app.planpoint.io) API.
## Requirements
* Java 17+
* Maven or Gradle
> **Windows Note:** Make sure `JAVA_HOME` is set before running Maven:
>
> ```powershell theme={null}
> $env:JAVA_HOME = "C:\Program Files\Microsoft\jdk-17.0.18.8-hotspot"
> $env:Path += ";$env:JAVA_HOME\bin"
> ```
## Installation
The SDK is served via [JitPack](https://jitpack.io) — no auth or registry setup required.
### Maven
```xml theme={null}
jitpack.iohttps://jitpack.iocom.github.planpoint-ioplanpoint-sdk-javamain-SNAPSHOTorg.codehaus.mojoexec-maven-plugin3.1.0com.yourpackage.Main
```
### Gradle
```groovy theme={null}
repositories {
maven { url 'https://jitpack.io' }
}
dependencies {
implementation 'com.github.planpoint-io:planpoint-sdk-java:main-SNAPSHOT'
}
```
## Quick Start
```java theme={null}
import io.planpoint.ApiClient;
import io.planpoint.api.AuthenticationApi;
import io.planpoint.api.ProjectsApi;
import io.planpoint.model.LoginBody;
import io.planpoint.model.AuthResponse;
import io.planpoint.model.ProjectSummary;
import java.util.List;
public class Main {
static ApiClient makeClient(String token) {
ApiClient client = new ApiClient();
client.setScheme("https");
client.setHost("app.planpoint.io");
client.setPort(-1);
if (!token.isEmpty()) {
client.setRequestInterceptor(req -> req.header("Authorization", "Bearer " + token));
}
return client;
}
public static void main(String[] args) throws Exception {
// 1. Authenticate
LoginBody loginBody = new LoginBody();
loginBody.setUsername("you@example.com");
loginBody.setPassword("yourpassword");
AuthResponse auth = new AuthenticationApi(makeClient("")).login(loginBody);
String token = auth.getAccessToken();
// 2. Fetch your projects using authenticated client
List projects = new ProjectsApi(makeClient(token)).getMyProjects();
for (ProjectSummary p : projects) {
System.out.println(p.getName());
}
}
}
```
## API Reference
### Authentication
#### `new AuthenticationApi(client).login(LoginBody body)`
Authenticate and receive a JWT token.
| Field | Type | Required | Description |
| - | - | - | - |
| `username` | `String` | Yes | User email |
| `password` | `String` | No | User password |
| `impersonate` | `Boolean` | No | Impersonate another user |
**Returns:** `AuthResponse` — `.getAccessToken(): String`
***
### Projects
#### `new ProjectsApi(client).getMyProjects()`
List all projects belonging to the authenticated user. Requires auth.
**Returns:** `List` — `.getName()`, `.getNamespace()`, `.getHostName()`, `.getStatus()`, `.getPaused()`, `.getCreatedAt()`
***
#### `new ProjectsApi(client).findProject(FindProjectBody body)`
Find a public project by namespace and hostname. No auth required.
| Field | Type | Required | Description |
| - | - | - | - |
| `namespace` | `String` | Yes | Project namespace |
| `hostName` | `String` | Yes | Allowed hostname |
**Returns:** `Project`
***
#### `new ProjectsApi(client).getProject(String id)`
Get a project by ID. Requires auth.
**Returns:** `Project`
***
#### `new ProjectsApi(client).updateProject(String id, Object body)`
Update project settings. Requires auth.
**Returns:** `Project`
***
### Groups
#### `new GroupsApi(client).getGroups()`
List all groups for the authenticated user. Requires auth.
**Returns:** `GroupsListResponse` — `.getRecords(): List`, `.getCount(): Integer`
***
#### `new GroupsApi(client).getGroup(String id)`
Get a group by ID. Requires auth.
**Returns:** `Group` — `.getName()`, `.getNamespace()`, `.getHostName()`, `.getType()`
***
#### `new GroupsApi(client).createGroup(CreateGroupBody body)`
Create a new group. Requires auth.
**Returns:** `Group`
***
#### `new GroupsApi(client).updateGroup(String id, Object body)`
Update a group. Requires auth.
**Returns:** `Group`
***
### Floors
#### `new FloorsApi(client).getFloors(String pid)`
List all floors for a project. Requires auth.
| Param | Type | Required | Description |
| - | - | - | - |
| `pid` | `String` | Yes | Project ObjectId |
**Returns:** `List` — `.getName()`, `.getProject()`, `.getLevel()`, `.getPosition()`, `.getPath()`
***
#### `new FloorsApi(client).getFloor(String id)`
Get a floor by ID. Requires auth.
**Returns:** `FloorFull`
***
#### `new FloorsApi(client).createFloor(CreateFloorBody body)`
Create a new floor. Requires auth.
**Returns:** `FloorFull`
***
#### `new FloorsApi(client).updateFloor(String id, Object body)`
Update a floor. Requires auth.
**Returns:** `FloorFull`
***
### Units
#### `new UnitsApi(client).getUnits(String pid)`
List all units for a project. Requires auth.
| Param | Type | Required | Description |
| - | - | - | - |
| `pid` | `String` | Yes | Project ObjectId |
**Returns:** `UnitsListResponse` — `.getRecords(): List`, `.getCount(): Integer`
`UnitFull` fields: `.getFloor()`, `.getName()`, `.getUnitNumber()`, `.getStatus()`, `.getPrice()`, `.getBed()`, `.getBath()`, `.getSqft()`, `.getModel()`
`status` values: `Available` | `OnHold` | `Sold` | `Leased` | `Unavailable`
***
#### `new UnitsApi(client).getUnit(String id)`
Get a unit by ID. Requires auth.
**Returns:** `UnitFull`
***
#### `new UnitsApi(client).createUnit(CreateUnitBody body)`
Create a new unit. Requires auth.
**Returns:** `UnitFull`
***
#### `new UnitsApi(client).updateUnit(String id, Object body)`
Update a unit. Requires auth.
**Returns:** `UnitFull`
***
#### `new UnitsApi(client).deleteUnit(String id)`
Delete a unit. Requires auth.
***
#### `new UnitsApi(client).batchUpdateUnits(BatchUpdateUnitsBody body)`
Update multiple units at once. Requires auth.
| Field | Type | Required | Description |
| - | - | - | - |
| `ids` | `List` | Yes | Unit ObjectIds to update |
| `patchData` | `Object` | Yes | Fields to apply to all |
**Returns:** `List`
***
### Leads
#### `new LeadsApi(client).getLeads(String pid)`
List all leads for a project. Requires auth.
| Param | Type | Required | Description |
| - | - | - | - |
| `pid` | `String` | Yes | Project ObjectId |
**Returns:** `List` — `.getName()`, `.getEmail()`, `.getPhone()`, `.getMessage()`, `.getUnit()`, `.getCreatedAt()`
***
## Links
* **[Install via JitPack (Maven/Gradle)](https://jitpack.io/#planpoint-io/planpoint-sdk-java)**
* [Java SDK on GitHub](https://github.com/planpoint-io/planpoint-sdk-java)
* [Planpoint App](https://app.planpoint.io)
* [TypeScript SDK on npm](https://www.npmjs.com/package/@planpoint/sdk)
* [Python SDK on PyPI](https://pypi.org/project/planpoint-sdk)
* [Go SDK on GitHub](https://github.com/planpoint-io/planpoint-sdk-go)
* [PHP SDK on GitHub](https://github.com/planpoint-io/planpoint-sdk-php)
# Welcome
Source: https://viewerdocs.planpoint.io/welcome
In this documentation site, you will find all the necessary knowledge to create and edit a plan viewer, as well as developer docs for our API and our SDK kit.
## Getting Started
What are you looking for today?
Start building an awesome Planpoint in under 2 hours.
Our many API endpoints can connect both our applications.
Easy to understand SDK for a quick turnaround.
## Advanced features
There's a lot of advanced features to learn, from Enterprise to Immersive 3D. Let's dig in!
Display all your projects on a global map interface.
Create a 360° outlook of your project’s environment.
Showcase your project's amenities and available parking spaces.
Allocate limited access to specific floors and units for stakeholders.
# Zapier Integration with Planpoint
Source: https://viewerdocs.planpoint.io/zapier
Learn how to connect Planpoint with over 6,000 apps using Zapier.
You can find our Zapier app here: [https://zapier.com/apps/planpoint/integrations](https://zapier.com/apps/planpoint/integrations) 
## Zapier Integration with Planpoint
The **Planpoint Zapier app** enables seamless connectivity between your Planpoint account and over **6,000 applications**, facilitating direct data exchange for:
* **Leads**
* **Unit status**
* **Unit availability**
* **Unit prices**
* **And more...**
## Key Benefits
### Lead Management
* **Automatically route new leads** from Planpoint to your preferred **CRM or marketing tools**.
* Ensure **timely follow-ups** and enhance conversion rates.
### Real-Time Updates
* **Sync unit statuses, availability, and pricing** across platforms.
* Maintain **consistent and accurate** information across all your systems.
### Enhanced Analytics
* Integrate with analytics platforms to gain deeper **insights into customer behavior** and sales performance.
* Leverage **data-driven decision-making** for better business strategies.
## Getting Started
To begin utilizing the Zapier integration, follow these steps:
1. **Request an Invitation**: Contact our support team at [**support@planpoint.io**](mailto:support@planpoint.io).
2. **Receive Setup Instructions**: Our team will send you an invitation and guide you through the setup process.
3. **Connect Your Apps**: Use Zapier to link Planpoint with your preferred tools and automate workflows.
## Support
If you need assistance with the Zapier integration, our support team is ready to help:
* **Email**: [support@planpoint.io](mailto:support@planpoint.io)
By leveraging the **Zapier integration**, you can enhance your **Planpoint experience**, streamline workflows, and maintain up-to-date information across all your platforms. Automate your processes and **maximize efficiency today**!