Propertybase is a real estate CRM built on Salesforce, so integrating it with Bolt.new means using Salesforce's REST API with OAuth 2.0. Set up a Connected App in your Salesforce/Propertybase org, obtain access tokens via the OAuth flow through a Next.js API route, then query real estate objects like listings and contacts. All API calls go through server-side routes — never expose client credentials in your Bolt frontend.
Connecting Bolt.new to Propertybase via the Salesforce REST API
Propertybase is not a standalone API — it is a managed package installed on top of a Salesforce org. This means everything you can do with Propertybase's data is done through Salesforce's REST API, using Salesforce's authentication (OAuth 2.0), Salesforce's query language (SOQL), and Salesforce's object model (standard Salesforce objects plus Propertybase custom objects). If you have used Salesforce APIs before, Propertybase integration will feel familiar. If you have not, the learning curve is steeper than a typical REST API, but the pattern is well-documented.
The integration approach in Bolt follows the standard server-side proxy pattern. Bolt generates a React frontend and a set of Next.js API routes. The API routes handle OAuth token acquisition using the Salesforce Username-Password flow (suitable for server-to-server, not user-facing login) and proxy data requests to Salesforce's REST endpoints. The frontend only calls your own API routes — it never touches Salesforce directly, which keeps your Connected App credentials private and server-only.
During development in Bolt's WebContainer, outbound HTTPS calls to Salesforce's servers (login.salesforce.com and your org's API endpoint) work perfectly — WebContainers support outbound HTTP/HTTPS. What does not work is incoming connections: if you want Salesforce to push real-time updates to your app via Outbound Messages or Platform Events webhooks, you need a deployed URL. For development, poll the Salesforce API or use Bolt's proxy pattern to simulate real-time updates. After deploying to Netlify or Vercel, register your webhook endpoints with Salesforce Workflow Rules or Process Builder.
Integration method
Propertybase runs on Salesforce, so its API is the Salesforce REST API accessed through a Connected App with OAuth 2.0. Bolt generates the frontend and Next.js API routes that proxy Salesforce REST calls — keeping credentials server-side and handling the OAuth token exchange. During Bolt development, outbound HTTPS calls to Salesforce's servers work fine in the WebContainer. Incoming webhooks from Salesforce (for real-time updates) require a deployed URL and cannot be tested in the Bolt preview.
Prerequisites
- An active Propertybase subscription with a Salesforce org (Propertybase is installed as a managed package on Salesforce)
- Salesforce System Administrator access to create a Connected App in the org
- Your Salesforce username, password, and security token (found in Salesforce Settings → Personal Information → Reset My Security Token)
- A Bolt.new project using Next.js for server-side API routes
- Basic understanding of SOQL (Salesforce Object Query Language) for querying Propertybase objects
Step-by-step guide
Create a Salesforce Connected App for API Access
Create a Salesforce Connected App for API Access
To authenticate with the Salesforce REST API (and therefore Propertybase), you need a Connected App — a configuration in your Salesforce org that represents your external application and grants it API access. Connected Apps provide the client_id and client_secret used in OAuth flows. To create a Connected App: log into your Salesforce org (or Propertybase portal, which takes you to Salesforce). Navigate to Setup (gear icon top-right) → search 'App Manager' → click 'New Connected App' in the top-right. Fill in: Connected App Name (e.g., 'Bolt Property Portal'), API Name (auto-fills), Contact Email (your email). Under 'API (Enable OAuth Settings)', check 'Enable OAuth Settings'. For Callback URL, enter http://localhost:3000/api/auth/callback (you will update this after deployment). Under 'Selected OAuth Scopes', add: 'Access and manage your data (api)', 'Perform requests on your behalf at any time (refresh_token, offline_access)', and 'Full access (full)'. Save the Connected App. Salesforce takes 2-10 minutes to propagate the new Connected App. After propagation, click 'Manage Consumer Details' to retrieve your Consumer Key (this is your client_id) and Consumer Secret (this is your client_secret). Store these in your Bolt .env file — they grant full API access and must never appear in frontend code. For the server-to-server Username-Password OAuth flow used in this integration, you do not need to configure the callback URL to match exactly during development. The flow sends credentials directly to Salesforce's token endpoint and receives an access token without a browser redirect. However, for production apps where users log in with their own Salesforce accounts, you would implement the Web Server OAuth flow with proper redirect handling.
Create a .env file with these Salesforce/Propertybase credentials as placeholders: SALESFORCE_CLIENT_ID=your_consumer_key_here, SALESFORCE_CLIENT_SECRET=your_consumer_secret_here, SALESFORCE_USERNAME=your_salesforce_email, SALESFORCE_PASSWORD=your_salesforce_password, SALESFORCE_SECURITY_TOKEN=your_security_token, SALESFORCE_INSTANCE_URL=https://yourorg.salesforce.com. Create a lib/salesforce.ts file that exports a getSalesforceToken function using the Username-Password OAuth flow — POST to https://login.salesforce.com/services/oauth2/token with grant_type=password. Cache the token and instance_url in memory and refresh when expired.
Paste this in Bolt.new chat
1# .env2SALESFORCE_CLIENT_ID=your_consumer_key_from_connected_app3SALESFORCE_CLIENT_SECRET=your_consumer_secret_from_connected_app4SALESFORCE_USERNAME=admin@yourorg.com5SALESFORCE_PASSWORD=yourpassword6SALESFORCE_SECURITY_TOKEN=yourSecurityToken1237# Security token is appended to password during OAuth flow8# Get it from: Salesforce → Settings → Personal Information → Reset My Security TokenPro tip: The Salesforce security token is appended directly to the password in the OAuth request — your effective password is 'YourPassword' + 'SecurityToken'. If your Salesforce org uses an IP allowlist that includes your server's IP, you may not need the security token. On Netlify/Vercel, IPs are dynamic, so always include the security token.
Expected result: A Connected App exists in your Salesforce org with a Consumer Key and Consumer Secret. Your .env file has all five Salesforce credentials. The getSalesforceToken function is scaffolded and ready for the next step.
Build the Salesforce Authentication Utility
Build the Salesforce Authentication Utility
The Salesforce Username-Password OAuth 2.0 flow is the simplest path for server-to-server authentication. Your server posts credentials to Salesforce's token endpoint and receives an access_token and instance_url. The access_token is a short-lived JWT (typically valid for 1-2 hours, configurable in Salesforce), and the instance_url is your org's API base URL (e.g., https://yourcompany.my.salesforce.com). For a Next.js API route application, token caching is important. Without caching, every API request would make a token fetch call before the actual Salesforce API call — doubling your latency and consuming Salesforce API limits faster. Since Next.js serverless functions can run in multiple concurrent instances, a simple module-level variable is not perfect for distributed caching, but it works well enough for most applications. For high-traffic apps, cache tokens in Redis or a database. The combined password+security_token value is sent as the password parameter. Salesforce validates the credentials, checks the Connected App's OAuth scopes, and returns an access token. The token is used as a Bearer token in all subsequent API calls via the Authorization header. If your org is in a sandbox (for testing), use https://test.salesforce.com/services/oauth2/token as the login URL instead of https://login.salesforce.com. Important: during development in Bolt's WebContainer, this OAuth call goes outbound to Salesforce's servers over HTTPS — this works perfectly in WebContainers. You can test the authentication flow directly in the Bolt preview. Only incoming webhooks from Salesforce require a deployed URL.
Build the complete Salesforce authentication utility in lib/salesforce.ts. Implement a getSalesforceToken function that POSTs to https://login.salesforce.com/services/oauth2/token with grant_type=password, client_id, client_secret, username, and password+security_token concatenated. Cache the token and its expiry (2 hours) in a module-level variable. Export a salesforceRequest helper that automatically calls getSalesforceToken and makes authenticated SOQL queries via the Salesforce REST API. Add TypeScript interfaces for the token response and query result.
Paste this in Bolt.new chat
1// lib/salesforce.ts2interface SalesforceToken {3 access_token: string;4 instance_url: string;5 expires_at: number;6}78interface SalesforceQueryResult<T> {9 totalSize: number;10 done: boolean;11 records: T[];12}1314let tokenCache: SalesforceToken | null = null;1516export async function getSalesforceToken(): Promise<SalesforceToken> {17 if (tokenCache && Date.now() < tokenCache.expires_at) {18 return tokenCache;19 }2021 const params = new URLSearchParams({22 grant_type: 'password',23 client_id: process.env.SALESFORCE_CLIENT_ID!,24 client_secret: process.env.SALESFORCE_CLIENT_SECRET!,25 username: process.env.SALESFORCE_USERNAME!,26 // Password + security token concatenated with no separator27 password: process.env.SALESFORCE_PASSWORD! + process.env.SALESFORCE_SECURITY_TOKEN!,28 });2930 const res = await fetch('https://login.salesforce.com/services/oauth2/token', {31 method: 'POST',32 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },33 body: params.toString(),34 });3536 if (!res.ok) {37 const err = await res.text();38 throw new Error(`Salesforce OAuth failed: ${err}`);39 }4041 const data = await res.json();42 tokenCache = {43 access_token: data.access_token,44 instance_url: data.instance_url,45 expires_at: Date.now() + 1.5 * 60 * 60 * 1000, // 1.5 hours46 };47 return tokenCache;48}4950export async function soqlQuery<T>(51 query: string52): Promise<SalesforceQueryResult<T>> {53 const { access_token, instance_url } = await getSalesforceToken();54 const encoded = encodeURIComponent(query);55 const res = await fetch(56 `${instance_url}/services/data/v58.0/query?q=${encoded}`,57 { headers: { Authorization: `Bearer ${access_token}` } }58 );59 if (!res.ok) {60 const err = await res.text();61 throw new Error(`SOQL query failed: ${err}`);62 }63 return res.json();64}6566export async function salesforceUpdate(67 objectType: string,68 recordId: string,69 fields: Record<string, unknown>70): Promise<void> {71 const { access_token, instance_url } = await getSalesforceToken();72 const res = await fetch(73 `${instance_url}/services/data/v58.0/sobjects/${objectType}/${recordId}`,74 {75 method: 'PATCH',76 headers: {77 Authorization: `Bearer ${access_token}`,78 'Content-Type': 'application/json',79 },80 body: JSON.stringify(fields),81 }82 );83 if (!res.ok) {84 const err = await res.text();85 throw new Error(`Salesforce update failed: ${err}`);86 }87}Pro tip: Salesforce API versions (v58.0, v59.0, etc.) are backward compatible. Check your org's maximum version at /services/data/ — this endpoint returns all available versions. Using a recent version ensures access to newer fields on Propertybase objects.
Expected result: The Salesforce authentication utility is complete. Calling getSalesforceToken() returns a valid access_token and instance_url from Salesforce. The soqlQuery helper can run SOQL queries. Test by making a call in a simple API route — you should see your org's data in the Bolt preview.
Query Propertybase Objects with SOQL
Query Propertybase Objects with SOQL
Propertybase installs custom objects on top of Salesforce's standard objects. The exact object names depend on your Propertybase version and any customizations your team has made. Standard Salesforce objects (Contact, Lead, Account, Opportunity) are always available. Propertybase-specific objects typically have a namespace prefix (e.g., pb__ or propertybase__) and include objects like Property__c (listings), Transaction__c (deals), and Commission__c. To discover your org's Propertybase objects and their fields, use Salesforce's Schema API. In a browser, while logged into Salesforce, visit: YOUR_INSTANCE_URL/services/data/v58.0/sobjects/ — this lists all available objects. For a specific object's fields, visit /services/data/v58.0/sobjects/Property__c/describe/. This describe call returns every field name, type, label, and whether it is required or read-only. Use this to build accurate SOQL queries. SOQL (Salesforce Object Query Language) looks like SQL but has important differences: no SELECT *, no JOINs (use relationship queries instead), and WHERE clauses require exact field API names (not labels). A basic property query: SELECT Id, Name, pb__Price__c, pb__Bedrooms__c, pb__City__c, pb__Status__c FROM pb__Property__c WHERE pb__Status__c = 'Active' ORDER BY CreatedDate DESC LIMIT 50. Relationship queries traverse foreign keys: SELECT Id, Name, pb__Property__r.Name, pb__Agent__r.FirstName FROM pb__Transaction__c WHERE IsClosed = false. Create a separate Next.js API route for each resource type. Do not expose raw SOQL via a query parameter — that is a SOQL injection vulnerability. Build parameterized server-side queries where only safe values (validated from a known set) are interpolated into the SOQL string.
Create Next.js API routes for Propertybase data. Build app/api/properties/route.ts (GET: SOQL query on Property__c with optional query params minPrice, maxPrice, bedrooms, city — validate and sanitize all params before interpolating into SOQL), app/api/contacts/route.ts (GET: list contacts with pagination, POST: create new contact), app/api/leads/route.ts (GET: list open leads with status filter). Import soqlQuery and salesforceUpdate from lib/salesforce.ts. Each route should return typed JSON responses. Add a GET /api/salesforce/objects route that returns the list of available SObjects for debugging.
Paste this in Bolt.new chat
1// app/api/properties/route.ts2import { NextResponse } from 'next/server';3import { soqlQuery } from '@/lib/salesforce';45interface Property {6 Id: string;7 Name: string;8 pb__Price__c: number;9 pb__Bedrooms__c: number;10 pb__City__c: string;11 pb__Status__c: string;12 pb__PhotoUrl__c?: string;13}1415export async function GET(request: Request) {16 try {17 const { searchParams } = new URL(request.url);18 const conditions: string[] = ["pb__Status__c = 'Active'"];1920 const minPrice = Number(searchParams.get('minPrice'));21 const maxPrice = Number(searchParams.get('maxPrice'));22 const bedrooms = Number(searchParams.get('bedrooms'));23 const city = searchParams.get('city')?.replace(/[^a-zA-Z\s]/g, '');2425 if (minPrice > 0) conditions.push(`pb__Price__c >= ${minPrice}`);26 if (maxPrice > 0) conditions.push(`pb__Price__c <= ${maxPrice}`);27 if (bedrooms > 0) conditions.push(`pb__Bedrooms__c = ${bedrooms}`);28 if (city) conditions.push(`pb__City__c = '${city}'`);2930 const where = conditions.join(' AND ');31 const soql = `SELECT Id, Name, pb__Price__c, pb__Bedrooms__c, pb__City__c, pb__Status__c, pb__PhotoUrl__c FROM pb__Property__c WHERE ${where} ORDER BY CreatedDate DESC LIMIT 100`;3233 const result = await soqlQuery<Property>(soql);34 return NextResponse.json(result.records);35 } catch (error: unknown) {36 const e = error as { message: string };37 return NextResponse.json({ error: e.message }, { status: 500 });38 }39}Pro tip: If your Propertybase objects have a different namespace prefix than pb__, open Salesforce Setup → Object Manager and look at the API Name column. The prefix before __ is your namespace. Ask your Salesforce admin if unsure — they will know immediately.
Expected result: GET /api/properties returns an array of property records from your Propertybase org. The Bolt preview shows live data from your Salesforce instance. Filters for price, bedrooms, and city work correctly.
Build the Property Listing Frontend in Bolt
Build the Property Listing Frontend in Bolt
With the API routes returning Propertybase data, prompt Bolt to build the React frontend components. The frontend should fetch from your own API routes (not directly from Salesforce), so the architecture remains: React component → your API route → Salesforce REST API → Propertybase data. The property listing UI typically includes: a search form with filters (price range slider, bedroom selector, city dropdown or text input), a results grid showing property cards, a detail view or modal for individual properties, and pagination or infinite scroll for large result sets. Use Bolt to scaffold all of these components and wire them to your API endpoints. For the agent dashboard portion — listing contacts, leads, and transactions — consider using a table layout with sortable columns, status badges (color-coded by Propertybase status values), and inline editing for quick updates. Inline edits should call your PATCH API routes that use salesforceUpdate(). State management for this type of data portal is straightforward: use React's useState and useEffect for data fetching, or a library like SWR or TanStack Query for automatic caching and revalidation. Bolt can scaffold either approach on request. For the Kanban pipeline view, prompt Bolt to build columns from the distinct StageName values returned by your SOQL query — these should match your org's opportunity stages exactly.
Build a property listing portal UI connected to my /api/properties endpoint. Create: (1) A SearchFilters component with price range inputs (min/max), bedroom count selector (any, 1, 2, 3, 4, 5+), and city text input. (2) A PropertyCard component displaying photo, name, price (formatted as USD), bedrooms, city, and status badge. (3) A PropertyGrid component that fetches /api/properties with filter params and renders a responsive grid of PropertyCards. (4) A PropertyModal component that shows full property details when a card is clicked. Use SWR for data fetching with loading skeleton and error states. Style with Tailwind CSS.
Paste this in Bolt.new chat
Pro tip: Propertybase photo URLs may be internal Salesforce Content URLs that require authentication to view. If property photos do not render in the browser, set up a GET /api/properties/[id]/photo API route that fetches the image with the Bearer token and streams it back — this proxies the authenticated image through your server.
Expected result: The property search portal renders live data from Propertybase in the Bolt preview. Filters update the displayed listings in real time. Clicking a property card opens the detail modal with full information.
Deploy and Configure Salesforce Outbound Webhooks
Deploy and Configure Salesforce Outbound Webhooks
Deploy your Bolt project to Netlify or Vercel to get a stable public URL. Salesforce Outbound Messages and Platform Events — Propertybase's mechanisms for pushing real-time updates when records change — require a publicly accessible HTTPS endpoint. During Bolt WebContainer development, incoming connections are impossible since the WebContainer has no public network address. This is a fundamental limitation of the browser-based runtime: Salesforce cannot call back to a localhost URL inside your browser tab. To deploy to Netlify: in your Bolt project, open Settings → Applications → Netlify → Publish. After the first deploy, go to Netlify Dashboard → Site Settings → Environment Variables and add all five Salesforce credentials (SALESFORCE_CLIENT_ID, SALESFORCE_CLIENT_SECRET, SALESFORCE_USERNAME, SALESFORCE_PASSWORD, SALESFORCE_SECURITY_TOKEN). Trigger a redeploy. For Salesforce Outbound Messages: in Salesforce Setup, go to Workflow Rules (or Process Builder). Create a rule that fires when a Property__c status changes. Add an Outbound Message action pointing to https://your-netlify-domain.netlify.app/api/webhooks/salesforce. Create a POST handler at that route that parses the SOAP XML Salesforce sends, processes the update, and returns a standard acknowledgment response. For simpler event handling, use Salesforce Change Data Capture (CDC) via Platform Events — this is available on Developer Edition and Enterprise+ orgs. CDC pushes events to a Pub/Sub API endpoint. However, for most Propertybase integrations, polling the SOQL API every 30-60 seconds is sufficient and avoids the webhook complexity entirely.
Prepare my Propertybase integration for deployment. Create a netlify.toml with build command 'npm run build', publish directory '.next', Node.js version 20, and @netlify/plugin-nextjs. Create a POST /api/webhooks/salesforce route that receives Salesforce Outbound Message SOAP XML, parses the key fields using a simple XML parser, and revalidates the relevant Next.js cache tags. Add an API health check at GET /api/health that tests the Salesforce OAuth connection and returns connection status.
Paste this in Bolt.new chat
1# netlify.toml2[build]3 command = "npm run build"4 publish = ".next"56[build.environment]7 NODE_VERSION = "20"89[[plugins]]10 package = "@netlify/plugin-nextjs"Pro tip: Salesforce Outbound Messages send SOAP XML (not JSON). The simplest parser for this in Node.js is a regex or string match for the fields you care about, or a lightweight XML parser like fast-xml-parser. Avoid heavy SOAP libraries — they add significant bundle size without providing much value for simple message parsing.
Expected result: The app is deployed to Netlify with all Salesforce credentials set as environment variables. The Salesforce API connection works in production. Outbound Message webhooks can be registered with the Netlify URL for real-time property and contact updates.
Common use cases
Property Listing Search Portal
Build a public-facing property search interface that reads listing data from Propertybase in real time. The frontend renders search filters (price range, bedrooms, location) and calls a Next.js API route that queries Propertybase via SOQL. Results display as a responsive card grid with property photos, pricing, and agent contact details.
Build a property listing search portal connected to Propertybase via the Salesforce REST API. Create a Next.js API route at app/api/properties/route.ts that authenticates with Salesforce using the Username-Password OAuth flow (reading SALESFORCE_USERNAME, SALESFORCE_PASSWORD, SALESFORCE_SECURITY_TOKEN, SALESFORCE_CLIENT_ID, SALESFORCE_CLIENT_SECRET from env). The route should accept query params (minPrice, maxPrice, bedrooms, city) and run a SOQL query on the Property__c object returning Name, Price__c, Bedrooms__c, City__c, Status__c, PhotoUrl__c fields. Build a React frontend with a search form and property card grid that calls this API.
Copy this prompt to try it in Bolt.new
Agent Dashboard for Lead and Contact Management
Create an internal agent dashboard that surfaces Propertybase contacts and leads in a clean interface. Agents can view their assigned leads, filter by status, and update contact information — all operations proxied through Next.js API routes to Salesforce. The dashboard pulls from standard Salesforce Contact and Lead objects that Propertybase extends.
Build an agent dashboard connected to Propertybase. Create API routes: GET /api/contacts (SOQL: SELECT Id, FirstName, LastName, Email, Phone, LeadSource, Status__c FROM Contact WHERE OwnerId = ':userId' ORDER BY CreatedDate DESC LIMIT 50), GET /api/leads (similar query on Lead object), PATCH /api/contacts/[id] (update contact fields via Salesforce PATCH). All routes authenticate via the Salesforce Username-Password OAuth flow. Build a tabbed dashboard UI with contacts list, leads pipeline board, and a contact detail modal with an edit form.
Copy this prompt to try it in Bolt.new
Transaction Tracker with Deal Pipeline
Build a deal pipeline view that pulls Propertybase transaction and opportunity data into a Kanban-style interface. Agents see all active deals organized by stage, with click-through to full transaction details including associated contacts, properties, and key dates. Read-only view suitable for team leaders who need pipeline visibility without logging into Salesforce.
Create a real estate transaction pipeline tracker using Propertybase data. Build a GET /api/transactions API route that queries the Opportunity object (Propertybase stores transactions as Opportunities) with SOQL: SELECT Id, Name, StageName, Amount, CloseDate, AccountId, Property__c, Agent__c FROM Opportunity WHERE IsClosed = false ORDER BY StageName, CloseDate. Group results by StageName and render as a Kanban board with columns for each pipeline stage. Each card shows property name, amount, close date, and a link to full details via GET /api/transactions/[id].
Copy this prompt to try it in Bolt.new
Troubleshooting
OAuth error: 'invalid_grant' when calling Salesforce token endpoint
Cause: The Username-Password OAuth flow is failing due to incorrect credentials. Common causes: wrong security token (it changes every time you reset your Salesforce password), IP not whitelisted in org's trusted IP ranges, or the Connected App has not finished propagating (takes up to 10 minutes after creation).
Solution: Reset your Salesforce security token via Settings → Personal Information → Reset My Security Token — a new token is emailed to your Salesforce registered email. Update SALESFORCE_SECURITY_TOKEN in .env. If using a sandbox org, change the login URL to https://test.salesforce.com/services/oauth2/token. Wait 10 minutes after creating a new Connected App before testing.
SOQL query returns 'INVALID_FIELD: No such column pb__Property__c'
Cause: The Propertybase object and field names in the SOQL query do not match the actual API names in the org. Namespace prefixes vary between Propertybase versions and org configurations.
Solution: Discover actual field names by calling the Salesforce Describe API: GET YOUR_INSTANCE_URL/services/data/v58.0/sobjects/YOUR_OBJECT/describe/ with the Bearer token. This returns all valid field names. In Salesforce Setup → Object Manager, the 'API Name' column shows the exact names to use in SOQL.
1// Add this debug endpoint to discover your org's object fields:2// GET /api/debug/describe?object=pb__Property__c3export async function GET(request: Request) {4 const { searchParams } = new URL(request.url);5 const objectName = searchParams.get('object') ?? 'Contact';6 const { access_token, instance_url } = await getSalesforceToken();7 const res = await fetch(8 `${instance_url}/services/data/v58.0/sobjects/${objectName}/describe/`,9 { headers: { Authorization: `Bearer ${access_token}` } }10 );11 const data = await res.json();12 const fields = (data.fields as Array<{name: string; type: string; label: string}>)13 .map(f => ({ name: f.name, type: f.type, label: f.label }));14 return NextResponse.json(fields);15}Salesforce PATCH update fails with 'FIELD_INTEGRITY_EXCEPTION' or 'INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY'
Cause: The Connected App's user does not have permission to edit the object or specific fields, or the field is read-only due to a Salesforce validation rule or field-level security setting.
Solution: In Salesforce Setup, check the Profile assigned to your integration user — go to Profiles → [Your Profile] → Field-Level Security and verify the target fields have Edit permission. For record-level access, check Sharing Rules. Propertybase adds its own permissions on top of standard Salesforce profiles, so consult your Propertybase admin.
Outbound Message webhook not receiving events after deployment
Cause: The Salesforce Workflow Rule is inactive, the Outbound Message endpoint URL does not match the deployed URL, or Salesforce requires an HTTPS URL with a valid certificate (self-signed certs are rejected).
Solution: In Salesforce Setup → Workflow Rules, confirm the rule status is Active. Verify the Outbound Message endpoint URL is your exact Netlify HTTPS URL. Netlify automatically provides valid TLS certificates. Check Salesforce's Outbound Message delivery log in Setup → Monitoring → Outbound Messages for error details.
Best practices
- Always use server-side API routes to proxy Salesforce calls — never expose your Connected App client_id or client_secret to the browser
- Cache Salesforce access tokens in memory with a 1.5-hour expiry to avoid making a token call before every API request
- Sanitize all user-provided values before interpolating them into SOQL queries to prevent SOQL injection — use a whitelist approach for field names and validate numeric values
- Use the Salesforce Describe API to discover actual object and field API names in your specific Propertybase org rather than guessing namespace prefixes
- Set up a health check endpoint that tests the Salesforce OAuth connection on startup so deployment failures are caught immediately
- During Bolt WebContainer development, outbound calls to Salesforce work fine — only incoming Salesforce webhooks require a deployed URL
- Use Salesforce sandbox orgs (accessible at test.salesforce.com) for development and testing before connecting to your production Propertybase org
- Consider polling the Salesforce API every 60 seconds for data freshness instead of implementing Outbound Message webhooks — polling is simpler and sufficient for most real estate dashboard use cases
Alternatives
Yardi is property management software focused on operations (rent collection, maintenance, accounting) for landlords and managers, while Propertybase is a sales CRM for agents and brokerages — choose based on whether your use case is operations or sales.
Salesforce is the underlying platform Propertybase runs on — integrate directly with Salesforce if your needs go beyond real estate CRM into general sales automation, customer service, or marketing workflows.
HubSpot offers a simpler REST API without OAuth complexity, a generous free CRM tier, and is easier to integrate for teams that do not already have a Salesforce subscription.
Zoho CRM has a straightforward REST API with API key authentication and real estate-specific modules, making it a lower-barrier alternative to the Salesforce/Propertybase OAuth complexity.
Frequently asked questions
Does Bolt.new work with Propertybase during development in the preview?
Yes, for outbound API calls. Bolt's WebContainer can make HTTPS requests to Salesforce's servers, so the OAuth token flow, SOQL queries, and record updates all work in the Bolt preview. What does not work is receiving incoming data from Salesforce — Outbound Messages and Platform Event webhooks require a public HTTPS URL, which the WebContainer cannot provide. For real-time Salesforce-to-app sync, deploy first and then register webhook endpoints.
Do I need to know SOQL to integrate Propertybase with Bolt.new?
Basic SOQL knowledge is very helpful. SOQL is similar to SQL: SELECT fields FROM object WHERE condition ORDER BY field LIMIT n. The main differences are no SELECT *, no JOINs (use relationship queries like Account.Name instead), and all field names must be the API names (not display labels). Bolt's AI can generate SOQL queries for you if you describe what data you need — just ask it to query specific Propertybase objects with the fields you want.
Can I use the Propertybase API without a Salesforce Connected App?
No. Since Propertybase runs entirely on Salesforce infrastructure, all API access goes through Salesforce's OAuth 2.0 system, which requires a Connected App. The Connected App acts as the API credential set for your integration. Creating one is free and takes about 5 minutes — it requires Salesforce System Administrator access to your org.
How do I find the correct object names for Propertybase custom objects?
Open Salesforce Setup → Object Manager and check the API Name column for any Propertybase-specific objects. They typically have a namespace prefix like pb__ before the object name. Alternatively, call the Salesforce REST API at /services/data/v58.0/sobjects/ with your Bearer token to get a complete list of all objects in your org, including Propertybase custom objects.
Is it possible to let end users log into Propertybase through a Bolt app with their own credentials?
Yes, using the Salesforce Web Server OAuth flow instead of the Username-Password flow used in this tutorial. The Web Server flow redirects users to a Salesforce login page, they authorize your Connected App, and Salesforce returns an authorization code that you exchange for an access token. This requires storing per-user tokens and implementing the full OAuth callback route. For an internal tool where a single integration user is sufficient, the Username-Password flow is simpler and works well.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation