Skip to main content
RapidDev - Software Development Agency
v0-integrationsNext.js API Route

How to Integrate Propertybase with V0

To integrate Propertybase with V0 by Vercel, use Propertybase's Salesforce-based REST API to fetch real estate listings, contacts, and transactions via a Next.js API route. Store your Salesforce Connected App credentials as Vercel environment variables, authenticate using OAuth2 client credentials, and build real estate dashboards and agent portals with V0-generated UI components.

What you'll learn

  • How to create a Salesforce Connected App in Propertybase to obtain OAuth2 API credentials
  • How to implement the Salesforce OAuth2 client credentials flow in a Next.js API route
  • How to query Propertybase listings, contacts, and transactions using SOQL via the Salesforce REST API
  • How to build a V0-generated real estate agent dashboard that displays live Propertybase data
  • How to cache Salesforce access tokens efficiently in serverless functions to avoid repeated auth calls
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate15 min read60 minutesOtherApril 2026RapidDev Engineering Team
TL;DR

To integrate Propertybase with V0 by Vercel, use Propertybase's Salesforce-based REST API to fetch real estate listings, contacts, and transactions via a Next.js API route. Store your Salesforce Connected App credentials as Vercel environment variables, authenticate using OAuth2 client credentials, and build real estate dashboards and agent portals with V0-generated UI components.

Build Real Estate Agent Dashboards with Propertybase and V0

Propertybase is a specialized real estate CRM built entirely on the Salesforce platform — it adds real estate-specific objects (Listings, Properties, Transactions, Showings) on top of Salesforce's standard CRM objects (Contacts, Leads, Opportunities, Accounts). This architecture means Propertybase integration follows Salesforce's API patterns: you authenticate via OAuth2, then use SOQL (Salesforce Object Query Language) to query any object in your org, including both Propertybase custom objects and standard Salesforce objects. The Salesforce REST API returns standard JSON responses that are straightforward to consume in Next.js API routes.

For real estate brokerages using Propertybase, building custom agent dashboards with V0 can significantly improve daily workflows. The default Propertybase interface is powerful but complex — a custom V0-built dashboard can surface exactly the metrics each agent needs: their active listings with days on market, pending transactions with upcoming milestones, leads requiring follow-up by priority score, and scheduled showings for the week. These custom views can be deployed to Vercel as internal tools accessible from any browser, complementing the full Propertybase platform for day-to-day status checking.

The Salesforce API connection uses OAuth2 with either the Username-Password flow (simpler, suitable for server-to-server integrations) or the Connected App JWT Bearer flow (more secure, doesn't require storing a user password). For V0-built Next.js apps on Vercel, the Username-Password flow is the most practical starting point — you create a Connected App in Salesforce, store the consumer key, consumer secret, username, and password+security token in Vercel environment variables, and your API routes exchange these for access tokens as needed. Access tokens expire after a configurable period (default 2 hours), so implement a lightweight caching mechanism to avoid re-authenticating on every API request.

Integration method

Next.js API Route

Propertybase is built on the Salesforce platform, meaning it uses Salesforce's REST API and SOQL query language. Integration with V0-generated Next.js apps requires creating a Salesforce Connected App in your Propertybase org to obtain OAuth2 credentials, then using those credentials in Next.js API routes to query Propertybase objects (Listings, Contacts, Transactions, Properties). The Salesforce API returns JSON and is called server-side from Vercel API routes with credentials stored as environment variables. V0 generates the real estate dashboards, agent portals, and listing displays that consume this data.

Prerequisites

  • Propertybase admin access with permission to create Connected Apps in Salesforce — go to Setup → Apps → App Manager in your Propertybase org
  • A Salesforce Connected App with the 'api' OAuth scope enabled — note the Consumer Key (client_id) and Consumer Secret (client_secret) after creation
  • Your Propertybase username and password plus a Salesforce Security Token (generated via your user profile → Reset My Security Token if you don't have one)
  • Your Salesforce instance URL — the base URL of your Propertybase org, formatted like https://yourcompany.my.salesforce.com
  • A V0 account at v0.dev with a Next.js project exported to GitHub and connected to Vercel

Step-by-step guide

1

Generate the Real Estate Dashboard UI with V0

Open V0 at v0.dev and describe the specific real estate dashboard components you need. Real estate UIs have domain-specific design patterns: property cards with hero images, price formatting ($1,250,000 not 1250000), status badges with industry-standard colors (active = green, pending = yellow, sold = gray), and timeline views for transactions. Be specific about the Propertybase objects you want to display — Listings (MLS properties for sale), Properties (the physical address records), Contacts (buyers and sellers), and Transactions (deals in progress). V0 generates components that look professional with shadcn/ui Card, Badge, and Table components. For a listing search page, describe the filter sidebar options, card layout, and pagination behavior. For a transaction pipeline, describe the Kanban column names (matching Propertybase's stage picklist values in your org), card information density, and whether you want drag-and-drop. For an agent dashboard, describe the metrics that matter most for daily workflow. V0 works best with real estate UIs when you specify American vs. metric units, currency formatting, date formats (closing date in MM/DD/YYYY), and whether photos are shown. After generating, push to GitHub via V0's Git panel and check the Vercel preview to confirm the layout renders correctly on both desktop and mobile.

V0 Prompt

Build a real estate listing grid component with a filter sidebar on the left and a property card grid on the right. Filters include: Status (Active/Pending/Sold checkboxes), Price range (min/max number inputs formatted with $ and commas), Bedrooms (1+ through 5+ radio buttons), Bathrooms (1+ through 4+ radio buttons), and Property type (Single Family, Condo, Townhome, Multi-Family checkboxes). Each property card shows a large photo placeholder (gray gradient), address as bold title, city and state, price in large text formatted with commas, and a row of icons showing bed count, bath count, and square footage. Add an Active/Pending/Sold badge in the top-right corner of each card. Cards link to /listings/:mlsNumber. Show a results count above the grid. Data fetches from /api/propertybase/listings with filter query params.

Paste this in V0 chat

Pro tip: Ask V0 to include a price-per-square-foot calculation in listing cards — it's a key metric agents use to compare properties and makes the dashboard immediately useful to real estate professionals.

Expected result: A real estate listing grid renders in V0's preview with filter sidebar, property cards with mock data, and a responsive layout that works on both desktop and tablet. Status badges and price formatting match real estate industry conventions.

2

Create the Salesforce Authentication Helper

Create a reusable authentication module that handles the Salesforce OAuth2 Username-Password flow and caches the access token to avoid re-authenticating on every API request. The Salesforce OAuth2 token endpoint is https://login.salesforce.com/services/oauth2/token (or https://test.salesforce.com for sandbox orgs). The Username-Password flow sends a POST request with grant_type=password, client_id, client_secret, username, and password (password concatenated with the security token). The response includes an access_token and instance_url. Salesforce access tokens are valid for 2 hours by default, though this is configurable in your org. Since Next.js serverless functions are stateless, you can't cache the token in memory across requests. A simple approach is to re-request the token on each function invocation (adding ~100-200ms) or cache it in an external store like Upstash Redis. For internal dashboards with moderate traffic, re-requesting is simpler and sufficient. Store the instance_url from the token response — it's the base URL for all subsequent API calls and may differ from what you configured, especially in orgs that have been migrated.

lib/propertybase.ts
1// lib/propertybase.ts
2interface SalesforceToken {
3 access_token: string;
4 instance_url: string;
5 token_type: string;
6}
7
8let cachedToken: SalesforceToken | null = null;
9let tokenExpiry: number = 0;
10
11export async function getSalesforceToken(): Promise<SalesforceToken> {
12 // Return cached token if still valid (with 5 min buffer)
13 if (cachedToken && Date.now() < tokenExpiry - 300_000) {
14 return cachedToken;
15 }
16
17 const params = new URLSearchParams({
18 grant_type: 'password',
19 client_id: process.env.SALESFORCE_CLIENT_ID!,
20 client_secret: process.env.SALESFORCE_CLIENT_SECRET!,
21 username: process.env.SALESFORCE_USERNAME!,
22 // Password + security token concatenated (no space)
23 password: process.env.SALESFORCE_PASSWORD! + process.env.SALESFORCE_SECURITY_TOKEN!,
24 });
25
26 const response = await fetch(
27 'https://login.salesforce.com/services/oauth2/token',
28 {
29 method: 'POST',
30 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
31 body: params.toString(),
32 }
33 );
34
35 if (!response.ok) {
36 const error = await response.text();
37 throw new Error(`Salesforce auth failed: ${error}`);
38 }
39
40 const token = await response.json() as SalesforceToken;
41 cachedToken = token;
42 tokenExpiry = Date.now() + 2 * 60 * 60 * 1000; // 2 hours
43
44 return token;
45}
46
47export async function querySalesforce<T = unknown>(
48 soql: string
49): Promise<T[]> {
50 const { access_token, instance_url } = await getSalesforceToken();
51
52 const encodedQuery = encodeURIComponent(soql);
53 const response = await fetch(
54 `${instance_url}/services/data/v59.0/query?q=${encodedQuery}`,
55 {
56 headers: {
57 Authorization: `Bearer ${access_token}`,
58 'Content-Type': 'application/json',
59 },
60 }
61 );
62
63 if (!response.ok) {
64 const error = await response.text();
65 throw new Error(`Salesforce query failed: ${error}`);
66 }
67
68 const data = await response.json();
69 return data.records as T[];
70}

Pro tip: Concatenate the Salesforce security token directly to the password with no space (e.g., 'myPassword' + 'tokenABC123' = 'myPasswordtokenABC123'). Forgetting the security token is the most common auth failure — Salesforce requires it unless your org has trusted IP ranges configured.

Expected result: Calling getSalesforceToken() returns a valid Salesforce access token and instance URL. Calling querySalesforce() with a SOQL query returns an array of records from your Propertybase org.

3

Create the Propertybase Data API Routes

Create the Next.js API routes that use the Salesforce helper to query Propertybase objects and return formatted data to your V0-generated dashboard. Propertybase adds custom objects to Salesforce — the exact API names depend on your org's configuration, but common objects include pb__Listing__c (listings), pb__Transaction__c (transactions), and standard Contact records for buyers and sellers. Use SOQL queries with SELECT statements to fetch the fields your dashboard needs. SOQL syntax is SQL-like: SELECT Id, Name, pb__List_Price__c, pb__Status__c, pb__Days_On_Market__c, pb__City__c, pb__State__c FROM pb__Listing__c WHERE pb__Status__c = 'Active' ORDER BY CreatedDate DESC LIMIT 50. Custom Salesforce fields end with __c (double underscore c) and you can find the API names for your org's fields in Setup → Object Manager → your object → Fields & Relationships. For the listings route, implement pagination using SOQL's LIMIT and OFFSET clauses and pass filter parameters from the query string. Return data in a shape that maps directly to your V0-generated component's props interface — transform Salesforce-style field names (pb__List_Price__c) into clean camelCase names (listPrice) in the API route to keep the frontend components clean.

app/api/propertybase/listings/route.ts
1// app/api/propertybase/listings/route.ts
2import { NextRequest, NextResponse } from 'next/server';
3import { querySalesforce } from '@/lib/propertybase';
4
5interface SFListing {
6 Id: string;
7 Name: string;
8 pb__List_Price__c: number;
9 pb__Status__c: string;
10 pb__Days_On_Market__c: number;
11 pb__City__c: string;
12 pb__State__c: string;
13 pb__Bedrooms__c: number;
14 pb__Bathrooms__c: number;
15 pb__Living_Area__c: number;
16 pb__Property_Type__c: string;
17 pb__MLS_Number__c: string;
18}
19
20export async function GET(request: NextRequest) {
21 const { searchParams } = new URL(request.url);
22 const status = searchParams.get('status') || 'Active';
23 const minPrice = searchParams.get('minPrice');
24 const maxPrice = searchParams.get('maxPrice');
25 const limit = Math.min(parseInt(searchParams.get('limit') || '50', 10), 100);
26
27 let whereClause = `pb__Status__c = '${status.replace(/'/g, "''")}' `;
28
29 if (minPrice) {
30 whereClause += `AND pb__List_Price__c >= ${parseFloat(minPrice)} `;
31 }
32 if (maxPrice) {
33 whereClause += `AND pb__List_Price__c <= ${parseFloat(maxPrice)} `;
34 }
35
36 const soql = `
37 SELECT Id, Name, pb__List_Price__c, pb__Status__c,
38 pb__Days_On_Market__c, pb__City__c, pb__State__c,
39 pb__Bedrooms__c, pb__Bathrooms__c, pb__Living_Area__c,
40 pb__Property_Type__c, pb__MLS_Number__c
41 FROM pb__Listing__c
42 WHERE ${whereClause}
43 ORDER BY pb__Days_On_Market__c DESC
44 LIMIT ${limit}
45 `;
46
47 try {
48 const records = await querySalesforce<SFListing>(soql);
49
50 const listings = records.map(r => ({
51 id: r.Id,
52 address: r.Name,
53 listPrice: r.pb__List_Price__c,
54 status: r.pb__Status__c,
55 daysOnMarket: r.pb__Days_On_Market__c || 0,
56 city: r.pb__City__c,
57 state: r.pb__State__c,
58 bedrooms: r.pb__Bedrooms__c,
59 bathrooms: r.pb__Bathrooms__c,
60 squareFeet: r.pb__Living_Area__c,
61 propertyType: r.pb__Property_Type__c,
62 mlsNumber: r.pb__MLS_Number__c,
63 }));
64
65 return NextResponse.json({ listings, count: listings.length });
66 } catch (error) {
67 const message = error instanceof Error ? error.message : 'Query failed';
68 console.error('Propertybase listings error:', message);
69 return NextResponse.json({ error: message }, { status: 500 });
70 }
71}

Pro tip: The Propertybase field API names (pb__List_Price__c, etc.) are org-specific — verify the exact field names in your Salesforce Setup → Object Manager → pb__Listing__c → Fields & Relationships before querying. Different Propertybase installations may have customized field names.

Expected result: GET /api/propertybase/listings returns an array of formatted listing objects from your Propertybase org. The V0-generated listing grid populates with real MLS listing data including addresses, prices, and property details.

4

Configure Environment Variables and Deploy

Open the Vercel Dashboard, navigate to your project, and go to Settings → Environment Variables. Add five variables for the Salesforce connection: SALESFORCE_CLIENT_ID with your Connected App's Consumer Key, SALESFORCE_CLIENT_SECRET with the Consumer Secret, SALESFORCE_USERNAME with the Salesforce user email that will make API calls, SALESFORCE_PASSWORD with that user's Salesforce password, and SALESFORCE_SECURITY_TOKEN with the user's security token (found or reset via user profile → Settings → Reset My Security Token in Salesforce). None of these should have the NEXT_PUBLIC_ prefix — all Propertybase API calls happen server-side. For a sandbox org, you'll also need to change the OAuth token URL from login.salesforce.com to test.salesforce.com in the lib/propertybase.ts helper. After saving all variables and redeploying, test the connection by calling /api/propertybase/listings from your browser. A successful response returns listing data; a failure returns a descriptive error message from Salesforce. Common issues at this stage are incorrect security token (the token changes when you reset your password), API access not enabled for the user's profile, or the Connected App not having the 'api' OAuth scope. For RapidDev teams building real estate brokerage tools, ensure your Propertybase admin has reviewed data access and enabled appropriate API permissions for the integration user.

Pro tip: Create a dedicated Salesforce API user with a read-only profile for the integration rather than using an admin's credentials. This limits what data is accessible via the API and prevents accidental data modifications from the Next.js integration.

Expected result: All five Salesforce environment variables are set in Vercel. The deployed API route successfully authenticates with Salesforce and returns Propertybase listing data. The V0-generated dashboard is live and displaying real property data.

Common use cases

Agent Activity Dashboard

A real estate agent opens a custom dashboard showing their active listings sorted by days on market, pending transactions with the next milestone due, and a lead follow-up list sorted by score. The V0-generated dashboard queries Propertybase via API routes and presents data in a compact, scannable format that's faster to check than navigating Propertybase's full UI.

V0 Prompt

Build a real estate agent dashboard with three columns: Active Listings (showing address, list price, days on market as a colored badge — green under 14 days, yellow 14-30, red over 30, and status), Pending Transactions (showing property address, client name, close date countdown, and next milestone), and Lead Follow-Up (showing lead name, source, last contact date, score badge, and a Call/Email action button). Data fetches from /api/propertybase/agent-summary. Include a refresh button and last-updated timestamp at the top.

Copy this prompt to try it in V0

Listing Search and Detail Portal

A broker-facing search portal for browsing active MLS listings in the Propertybase system. The V0-generated interface shows a filterable grid of property cards with key details, and clicking a card opens a detail view with full listing information, showing history, and related contact records.

V0 Prompt

Create a property listing search page with a filter sidebar (price range sliders, bedroom/bathroom selectors, property type checkboxes, status multiselect for Active/Pending/Sold). The main area shows a responsive grid of listing cards with hero photo, address, list price, bedrooms, bathrooms, square footage, and days on market badge. Clicking a card navigates to /listings/:id showing full details. The search calls GET /api/propertybase/listings with filter params. Include a map view toggle that shows a placeholder map with listing pins.

Copy this prompt to try it in V0

Transaction Pipeline Manager

A visual transaction pipeline showing all deals in progress organized by stage (Under Contract, Inspection, Appraisal, Clear to Close, Closed). Each transaction card shows property address, buyer/seller names, agent, and close date. Dragging between columns would trigger Propertybase stage updates via the API.

V0 Prompt

Build a transaction Kanban board with five columns representing transaction stages. Each card shows property address, primary client name, agent initials avatar, close date, and transaction value. Add a total value sum at the bottom of each column. Include a 'New Transaction' button that opens a form posting to /api/propertybase/transactions. Add a search bar that filters cards client-side by address or client name. The board fetches from /api/propertybase/transactions?stage=all and shows loading skeletons while fetching.

Copy this prompt to try it in V0

Troubleshooting

Salesforce returns 'INVALID_LOGIN: Invalid username, password, security token; or user locked out'

Cause: The password and security token are not concatenated correctly, the credentials are wrong, or the user has been locked out after too many failed attempts. The security token changes whenever the user resets their password.

Solution: Verify the exact value in SALESFORCE_SECURITY_TOKEN — it should be a 25-character alphanumeric string from the 'Reset My Security Token' email. Confirm the password and token are concatenated with no space in the URL params (password field = 'actual_password' + 'security_token'). If the account is locked, unlock it in Salesforce Setup → Users. If you recently reset your password, regenerate the security token.

SOQL query returns 'INVALID_FIELD: No such column pb__List_Price__c on entity pb__Listing__c'

Cause: The field API name used in the SOQL query doesn't match the actual field name in this Propertybase org. Propertybase field names can differ between installations based on customization and version.

Solution: In Salesforce Setup → Object Manager → Propertybase Listing (or pb__Listing__c) → Fields & Relationships, check the exact API Name column for each field you want to query. API names end with __c for custom fields. Use the Salesforce Developer Console (Setup → Developer Console → Query Editor) to run test SOQL queries and see actual field names.

typescript
1// Use Salesforce's describe endpoint to discover available fields:
2// GET {instance_url}/services/data/v59.0/sobjects/pb__Listing__c/describe

API route works locally but returns authentication errors on Vercel

Cause: Environment variables are set in .env.local locally but not configured in Vercel Dashboard, or were added after the last deployment.

Solution: Verify all five Salesforce variables are present in Vercel Dashboard → Settings → Environment Variables for the Production environment. After adding or changing variables, trigger a redeployment from the Deployments tab. Note that NEXT_PUBLIC_ variables are inlined at build time — but since Salesforce credentials don't use NEXT_PUBLIC_, they're read at runtime and available immediately after the function starts.

Best practices

  • Create a dedicated Salesforce API user with a read-only profile for the V0 integration — this prevents accidental data modifications and limits data exposure if the credentials are compromised
  • Use SOQL LIMIT clauses on all queries and implement pagination in your API routes — Salesforce queries without limits can timeout and returning thousands of records wastes bandwidth and slows dashboard load times
  • Cache Salesforce access tokens in a module-level variable with an expiry check — re-authenticating on every request adds unnecessary latency and consumes API limits
  • Escape user-provided filter values in SOQL queries to prevent SOQL injection: replace single quotes with doubled single quotes (str.replace(/'/g, "''"))
  • Use the Salesforce API version URL path (v59.0) explicitly rather than relying on defaults — newer API versions may return different field formats or support new query features
  • Handle Salesforce rate limits gracefully — Salesforce enforces API call limits per 24-hour period based on your org edition; implement exponential backoff on 429 responses and add the current request count to your dashboard's admin view

Alternatives

Frequently asked questions

Does Propertybase have its own API separate from Salesforce?

No — Propertybase is built entirely on the Salesforce platform and uses Salesforce's standard REST API and SOQL query language. There is no separate Propertybase API. All Propertybase data is stored as custom Salesforce objects with the pb__ namespace prefix, and you access them using the same Salesforce REST API patterns as standard Salesforce objects.

How do I find the correct SOQL field names for Propertybase objects?

Use the Salesforce Developer Console (Setup → Developer Console → Query Editor) to run DESCRIBE queries: SELECT FIELDS(ALL) FROM pb__Listing__c LIMIT 1. This returns all available fields. Alternatively, use the Salesforce Object Manager in Setup to browse objects and see field API names. The Propertybase documentation at propertybase.com/developers also lists standard field names, though customizations in your org may differ.

Can the V0 dashboard create or update listings in Propertybase?

Yes — Salesforce's REST API supports POST (create), PATCH (update), and DELETE operations on any object your API user has write permissions for. In your Next.js API routes, use POST requests to {instance_url}/services/data/v59.0/sobjects/pb__Listing__c/ with a JSON body to create a new listing record. However, most V0-built integrations start with read-only dashboards since write operations require careful consideration of data validation and business rules.

How many API calls does Salesforce allow per day for Propertybase?

Salesforce API call limits depend on your org edition and number of licenses. Enterprise Edition orgs get 1,000 API calls per Salesforce license per 24 hours, with a minimum of 1,000,000 calls. Professional Edition orgs get 1,000 calls per license. Check your current API usage in Setup → System Overview → API Usage. For internal dashboards, this limit is rarely reached. Cache responses and implement pagination to minimize call count.

What's the difference between Propertybase Salesforce Edition and Propertybase GO?

Propertybase offers two products: the Salesforce Edition (built on Salesforce, uses Salesforce API as described in this guide) and Propertybase GO (a standalone non-Salesforce version). If your organization uses Propertybase GO, the API documentation is different — check your Propertybase GO account's developer settings for the appropriate API credentials and endpoints.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.