# Create or update broker
Source: https://developers.venturu.com/api-reference/partner/create-or-update-broker
/openapi.json put /partner/v1/brokers/{externalBrokerId}
Create or update a broker in Venturu's system. If the broker with the specified external ID already exists, their information will be updated. If not, a new broker will be created.
# Create or update listing
Source: https://developers.venturu.com/api-reference/partner/create-or-update-listing
/openapi.json put /partner/v1/listings/{externalListingId}
Create or update a listing in Venturu's system. If the listing with the specified external ID already exists, its information will be updated. If not, a new listing will be created.
# Get health
Source: https://developers.venturu.com/api-reference/partner/get-health
/openapi.json get /partner/v1/health
Get information about the health of the API. Useful to verify if the API is reachable and you can successfully authenticate against it.
# Get leads for office
Source: https://developers.venturu.com/api-reference/partner/get-leads-for-office
/openapi.json get /partner/v1/offices/{officeId}/leads/count
Get lead statistics for a specific partner agent organization office. This endpoint may not be supported for all Venturu partners.
# Get leads for organization
Source: https://developers.venturu.com/api-reference/partner/get-leads-for-organization
/openapi.json get /partner/v1/organizations/{organizationId}/leads/count
Get lead statistics and per-office breakdowns for a specific partner agent organization. This endpoint may not be supported for all Venturu partners.
# Authentication
Source: https://developers.venturu.com/getting-started/authentication
## Authenticating Your Requests
All requests to the Venturu API must be authenticated using a bearer token. This ensures that only authorized applications can access the API.
### API Key Format
Your API key is a secret token that you will receive during the [onboarding process](../introduction/onboarding).
You must include your key in the `Authorization` header with every API request. The value must be prefixed with `Bearer `.
```bash title="Header Format" theme={null}
Authorization: Bearer YOUR_API_KEY
```
### Handling Errors
If your API key is missing, malformed, or invalid, the API will return a `401 Unauthorized` status code.
```json title="Response: 401 Unauthorized" theme={null}
{
"status": "error",
"error": "Unauthorized"
}
```
If you receive this error, double-check that you have correctly copied your API key and included the `Bearer ` prefix.
Now that you understand authentication, let's [make your first API call](./making-your-first-call).
# Core Concepts
Source: https://developers.venturu.com/getting-started/core-concepts
Before you start integrating, understanding these core concepts will help you build a robust and reliable solution with the Venturu API.
## Idempotency
Our API is designed to be idempotent. This means that you can safely send the same request multiple times without creating duplicate entries or causing unintended side effects.
We achieve this by using the `PUT` HTTP method for both creating and updating resources like Brokers and Listings.
* **If you `PUT` data for an `externalId` that doesn't exist:** We create a new resource.
* **If you `PUT` data for an `externalId` that already exists:** We update the existing resource with the new information.
This makes your integration resilient. If a request fails due to a network error, you can simply retry it without worrying about creating duplicates.
**Best Practice:** Design your sync jobs to be idempotent as well. This allows you to run them repeatedly without worrying about duplicates or inconsistent state.
## External IDs
You are the source of truth for your data. To keep our systems in sync, we rely on your unique identifiers. Throughout the API, you will see parameters like:
* `externalBrokerId`
* `externalListingId`
These are the unique IDs for brokers and listings **from your system**. You must provide these in the URL path when creating or updating a resource. We will store this ID and link it to the corresponding resource ID in Venturu's system.
This allows you to manage resources using the IDs you already know, without needing to store Venturu's internal IDs.
**Important:** External IDs are permanent. Once you create a resource with an external ID, that ID will always refer to that specific resource. Don't reuse external IDs for different resources.
### Best Practices for External IDs
Choose IDs that won't change over time. Database primary keys or MLS numbers are good choices.
Stick to alphanumeric characters, hyphens, and underscores. Avoid spaces and special characters.
Use the same ID format across your integration for easier debugging and maintenance.
Keep a record of how your internal IDs map to Venturu external IDs.
## Flexible Resource Management
The Venturu API is designed to adapt to your workflow. When creating listings, you have two options for broker association:
1. **Reference by ID**: If you manage brokers separately, simply reference them using `brokerExternalId` when creating a listing
2. **Inline Creation**: Create or update both the broker and listing in a single API call by including the full broker object
This flexibility means you can choose the approach that best matches your system architecture:
* **Separate Management**: Ideal for systems where brokers are managed independently from listings (e.g., CRMs with distinct broker and listing modules)
* **Coupled Creation**: Perfect for syndication feeds where broker and listing data come together (e.g., MLS exports where both are in the same record)
Learn more about both approaches in the [Creating a Listing](../guides/creating-a-listing) guide.
## Environments
The Venturu API provides two server environments. You can see these defined in our [OpenAPI specification](/openapi.json).
* **Production:** `https://www.venturu.com/api`
This is the live environment. All data sent to this server will be visible on the public Venturu marketplace.
* **Local Development:** `http://localhost:3000/api`
This URL is provided for our internal development and testing. As an external developer, you should always use the **Production URL**. We do not currently offer a public sandbox environment.
If you need a dedicated sandbox or staging environment for your integration, please contact [joel@venturu.com](mailto:joel@venturu.com) to discuss your requirements.
## Next Steps
Now that you understand these core concepts, you're ready to start building your integration:
Get started by creating your first broker
Learn how to create business listings
Explore all available endpoints
Visit the Venturu marketplace
# Making Your First Call
Source: https://developers.venturu.com/getting-started/making-your-first-call
## Quickstart: Verify Your Setup
The best way to confirm your API key is working correctly is to make a simple request to our `health` endpoint. This endpoint requires authentication but doesn't modify any data, making it the perfect first call.
### Prerequisites
* You must have your unique API key from the [Onboarding](../introduction/onboarding) process.
### 1. The Endpoint
We will be making a `GET` request to the following URL:
`https://www.venturu.com/api/partner/v1/health`
### 2. Making the Request
Use your preferred HTTP client or tool, like cURL, to make the request. Remember to replace `YOUR_API_KEY` with the secret token provided to you.
```bash title="cURL Request" theme={null}
curl -X GET "https://www.venturu.com/api/partner/v1/health" \
-H "Authorization: Bearer YOUR_API_KEY"
```
### 3. The Successful Response
If your API key is valid, you will receive a `200 OK` status code and a JSON response body similar to this:
```json title="Response: 200 OK" theme={null}
{
"status": "success",
"timestamp": "2023-10-26T10:00:00.000Z"
}
```
Congratulations! You have successfully connected to the Venturu API.
### Next Steps
Now that your connection is verified, it's a good time to understand some [Core Concepts](./core-concepts) of our API before diving into the guides.
# Rate Limiting
Source: https://developers.venturu.com/getting-started/rate-limiting
## API Usage and Limits
Our API is designed to handle a high volume of requests typical for syndication workflows.
At present, we do not enforce strict, published rate limits on a per-key basis. We monitor API usage to ensure stability and fair use for all our partners.
If you are planning an integration that will involve a very high volume of requests (e.g., more than 1,000 requests per minute), we kindly ask that you reach out to us during the [onboarding process](../introduction/onboarding) to discuss your use case.
This helps us ensure that our infrastructure is prepared and can provide you with the best possible performance.
### Future Changes
We reserve the right to implement rate limiting in the future to maintain the quality of service. Any such changes will be communicated to all active developers well in advance.
### Best Practices
To ensure optimal performance and reliability:
Group multiple updates together when possible rather than making individual requests for each change.
Use exponential backoff when retrying failed requests to avoid overwhelming the API.
Cache responses where appropriate to reduce unnecessary API calls.
Keep track of your API usage patterns to optimize your integration.
### Need Higher Limits?
If your use case requires guaranteed high-volume access or dedicated infrastructure, please contact us at [joel@venturu.com](mailto:joel@venturu.com) to discuss enterprise options.
# Creating a Broker
Source: https://developers.venturu.com/guides/creating-a-broker
## Create Your First Broker
Brokers are business professionals who list and sell businesses on Venturu. Every listing created through the API needs a broker, so let's create one.
## Quick Start
**Endpoint:** `PUT /partner/v1/brokers/{externalBrokerId}`
**What you need:**
* Your API key
* A unique ID from your system (like your broker's employee ID or email)
* Basic broker information (name, email)
Pick a stable, unique identifier from your system. Good choices:
* Employee ID: `EMP-12345`
* Email-based: `jane-doe`
* Database ID: `broker-789`
This ID is permanent - once you use it, it always refers to this broker.
Create a JSON object with the broker's information:
```json theme={null}
{
"name": "Jane Doe",
"email": "jane@realestate.com",
"phone": "+1-555-0123"
}
```
```bash theme={null}
curl -X PUT "https://www.venturu.com/api/partner/v1/brokers/BROKER-789" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Jane Doe",
"email": "jane@realestate.com",
"phone": "+1-555-0123"
}'
```
You'll get back the broker's Venturu ID and profile URL:
```json theme={null}
{
"status": "success",
"message": "Broker created successfully",
"venturuBrokerId": "cmhnmzme1000b396q58yx17fm",
"venturuProfileUrl": "https://www.venturu.com/u/jane-doe"
}
```
Broker created! They can now have listings assigned to them.
## Full Example with All Fields
Want to create a complete, professional profile? Here's an example with all optional fields:
```json Complete Broker Profile theme={null}
{
"name": "Jane Doe",
"email": "jane@realestate.com",
"phone": "+1-555-0123",
"avatarUrl": "https://example.com/photos/jane.jpg",
"forwardingEmail": "leads-jane@crm.example.com",
"profile": {
"bio": "With over 10 years of experience in business brokerage, Jane specializes in restaurant and retail acquisitions.",
"website": "https://janedoe.com",
"linkedInUrl": "https://linkedin.com/in/janedoe"
},
"licenses": [
{
"licenseNumber": "BK123456",
"state": "Florida",
"country": "US"
}
],
"serviceAreas": [
{
"city": "Miami",
"state": "Florida",
"country": "US"
}
]
}
```
```bash cURL theme={null}
curl -X PUT "https://www.venturu.com/api/partner/v1/brokers/BROKER-789" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d @broker.json
```
```python Python theme={null}
import requests
import os
url = "https://www.venturu.com/api/partner/v1/brokers/BROKER-789"
headers = {
"Authorization": f"Bearer {os.getenv('VENTURU_API_KEY')}",
"Content-Type": "application/json"
}
broker_data = {
"name": "Jane Doe",
"email": "jane@realestate.com",
# ... rest of broker data
}
response = requests.put(url, json=broker_data, headers=headers)
print(response.json())
```
```javascript JavaScript theme={null}
const response = await fetch(
'https://www.venturu.com/api/partner/v1/brokers/BROKER-789',
{
method: 'PUT',
headers: {
'Authorization': `Bearer ${process.env.VENTURU_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Jane Doe',
email: 'jane@realestate.com',
// ... rest of broker data
})
}
);
const data = await response.json();
console.log(data);
```
## Field Reference
* **name**: Broker's full name
* **email**: Primary email address (used for Venturu account)
* **phone**: Contact number (include country code: `+1-555-0123`)
* **avatarUrl**: Professional headshot (at least 400x400px)
* **profile.bio**: Brief professional bio (2-3 sentences)
* **forwardingEmail**: Send leads directly to your CRM
Many CRMs provide unique email addresses that automatically create leads. Set this field to pipe Venturu leads straight into your system!
* **licenses**: Array of license objects (`licenseNumber`, `state`, `country`)
* **serviceAreas**: Where the broker operates (can specify by `city`, `county`, or `state`)
* **profile.website**: Personal or company website
* **profile.linkedInUrl**: LinkedIn profile URL
## Common Questions
No problem! If you use the same `externalBrokerId`, the broker will be **updated** instead of creating a duplicate. See [Updating a Broker](./updating-a-broker) for details.
No - the `externalBrokerId` is permanent. It's the link between your system and Venturu. Choose wisely!
Provide a URL to the photo with `avatarUrl`. We'll download and optimize it. Photos are processed asynchronously, so they might not appear immediately.
Set the `forwardingEmail` field to your CRM's lead ingestion email. When someone contacts this broker on Venturu, we'll forward the lead there automatically.
## Next Steps
Learn how to update broker details
Now create a listing for this broker
Full API documentation
Understanding external IDs
# Creating a Listing
Source: https://developers.venturu.com/guides/creating-a-listing
## Create Your First Listing
A listing represents a business for sale on Venturu. Let's get one live!
## Quick Start
**Every listing created through the API needs a broker.** You can either reference an existing broker or create one inline with the listing. Both approaches work great!
**Endpoint:** `PUT /partner/v1/listings/{externalListingId}`
Pick a unique ID from your system:
* MLS number: `MLS-123456`
* Database ID: `LISTING-789`
* Custom format: `biz-miami-restaurant-001`
This ID is permanent - choose wisely!
You have two options:
Use the broker's external ID:
```json theme={null}
{
"brokerExternalId": "BROKER-789",
// ... rest of listing
}
```
Include full broker data:
```json theme={null}
{
"broker": {
"externalBrokerId": "BROKER-789",
"name": "Jane Doe",
"email": "jane@realestate.com"
},
// ... rest of listing
}
```
```json Minimum Required Fields theme={null}
{
"brokerExternalId": "BROKER-789",
"status": "FOR_SALE",
"businessType": "Restaurant",
"location": {
"city": "Miami",
"state": "Florida",
"country": "US",
"visibility": "SHOW_CITY_STATE"
}
}
```
```bash theme={null}
curl -X PUT "https://www.venturu.com/api/partner/v1/listings/LISTING-123" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d @listing.json
```
```json theme={null}
{
"status": "success",
"message": "Listing created successfully",
"venturuListingId": 98765,
"venturuListingUrl": "https://www.venturu.com/business/restaurant-miami-98765"
}
```
Listing is live! Buyers can now find it on Venturu.
## Complete Example
Here's a full listing with all the important fields:
```json Complete Restaurant Listing theme={null}
{
"brokerExternalId": "BROKER-789",
"status": "FOR_SALE",
"title": "Profitable Downtown Pizzeria",
"description": "Well-established pizzeria in the heart of downtown. Famous for authentic recipes and loyal customer base. Turnkey operation with fully equipped kitchen.",
"businessType": "Restaurant",
"establishedAt": "2010-05-15T00:00:00.000Z",
"location": {
"streetAddress1": "123 Main St",
"city": "Miami",
"state": "Florida",
"postalCode": "33101",
"country": "US",
"visibility": "SHOW_FULL_ADDRESS"
},
"financials": {
"askingPrice": 550000,
"revenue": 800000,
"sde": 220000,
"inventory": 25000,
"ffande": 150000
},
"property": {
"propertyKind": "RENTED",
"areaSqft": 2500,
"rentData": {
"amount": 5000,
"frequency": "MONTHLY",
"leaseRenewable": true,
"leaseExpiration": "2028-12-31T00:00:00.000Z"
}
},
"financing": {
"financingAvailable": true,
"sbaPrequalified": true,
"minimumDownPayment": 100000
},
"photos": [
{
"url": "https://example.com/photos/storefront.jpg",
"sortKey": 1
},
{
"url": "https://example.com/photos/kitchen.jpg",
"sortKey": 2
}
]
}
```
```bash cURL theme={null}
curl -X PUT "https://www.venturu.com/api/partner/v1/listings/LISTING-123" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d @listing.json
```
```python Python theme={null}
import requests
import os
url = "https://www.venturu.com/api/partner/v1/listings/LISTING-123"
headers = {
"Authorization": f"Bearer {os.getenv('VENTURU_API_KEY')}",
"Content-Type": "application/json"
}
# Load your listing data
with open('listing.json') as f:
listing_data = json.load(f)
response = requests.put(url, json=listing_data, headers=headers)
print(response.json())
```
## Essential Fields
**Option 1:** Reference existing broker
```json theme={null}
"brokerExternalId": "BROKER-789"
```
**Option 2:** Create broker inline
```json theme={null}
"broker": {
"externalBrokerId": "BROKER-789",
"name": "Jane Doe",
"email": "jane@realestate.com"
}
```
Controls visibility:
* `FOR_SALE` - Live and searchable (use this!)
* `DRAFT` - Not yet published
* `ARCHIVED` - Temporarily hidden
* `UNDER_CONTRACT` - Deal in progress
* `SOLD` - Business sold
See [Managing Listing Status](./managing-listing-status) for all options.
The type of business:
* `Restaurant`
* `Retail`
* `Service Business`
* `E-commerce`
* `Manufacturing`
* And more...
```json theme={null}
"location": {
"city": "Miami",
"state": "Florida",
"country": "US",
"visibility": "SHOW_CITY_STATE"
}
```
**Visibility options:**
* `SHOW_FULL_ADDRESS` - Show complete address
* `SHOW_CITY_STATE` - Show only city and state
* `SHOW_STATE_ONLY` - Show only state
## Recommended Fields
```json theme={null}
"financials": {
"askingPrice": 550000,
"revenue": 800000,
"sde": 220000,
"inventory": 25000,
"ffande": 150000
}
```
**SDE** = Seller's Discretionary Earnings. This is what most buyers care about!
```json theme={null}
"property": {
"propertyKind": "RENTED",
"areaSqft": 2500,
"rentData": {
"amount": 5000,
"frequency": "MONTHLY",
"leaseExpiration": "2028-12-31T00:00:00.000Z"
}
}
```
**Property Kind:**
* `OWNED` - Business owns the property
* `RENTED` - Business leases the property
* `NEGOTIABLE` - Terms are flexible
```json theme={null}
"photos": [
{
"url": "https://example.com/photo1.jpg",
"sortKey": 1
},
{
"url": "https://example.com/photo2.jpg",
"sortKey": 2
}
]
```
**Pro tip:** Use 5-10 high-quality photos. Lower `sortKey` = appears first. Photos should be at least 1200px wide.
```json theme={null}
"title": "Profitable Downtown Pizzeria",
"description": "A well-established pizzeria in the heart of downtown..."
```
**Note:** We may optimize your description using AI to improve buyer engagement. Your original is always preserved.
## Common Questions
No worries! If you use the same `externalListingId`, it will **update** instead of creating a duplicate. See [Updating a Listing](./updating-a-listing).
Yes! Use the inline `broker` object. Both will be created/updated in one API call.
Instantly for `FOR_SALE` listings. We generate SEO-optimized URLs and descriptions in the background (takes \~1 minute).
Use `"status": "DRAFT"` to create without publishing. Change to `FOR_SALE` when ready. See [Managing Listing Status](./managing-listing-status).
## Next Steps
Learn how to update listing details
Control visibility and status
Create a broker first
Full field documentation
# Managing Listing Status
Source: https://developers.venturu.com/guides/managing-listing-status
## Control Your Listing Visibility
Every listing has a `status` that controls whether it appears on Venturu. Let's make it simple.
## The Main Statuses
**Live and searchable**\
Appears in search results and on the marketplace
**Sale in progress**\
Shows "Under Contract" badge, removed from search
**Business has sold**\
Marked as sold, removed from active search
**Temporarily hidden**\
Not visible to buyers, but data is preserved
**Not yet published**\
For internal use, completely hidden
**Evaluating offers**\
Still visible, indicates active negotiations
## Quick Reference
| Status | Visible to Buyers? | In Search? | Use When |
| ------------------ | ------------------ | ---------- | --------------------------------- |
| `FOR_SALE` | ✅ Yes | ✅ Yes | Ready to sell |
| `REVIEWING_OFFERS` | ✅ Yes | ✅ Yes | Have offers, still accepting more |
| `PENDING_CONTRACT` | ✅ Yes | ✅ Yes | Offer accepted, pending docs |
| `UNDER_CONTRACT` | ✅ Yes | ✅ Yes | Contract signed, in due diligence |
| `SOLD` | ❌ No | ❌ No | Deal closed |
| `ARCHIVED` | ❌ No | ❌ No | Temporarily off market |
| `DRAFT` | ❌ No | ❌ No | Still preparing |
## Changing Status
### Make a Listing Live
```bash theme={null}
curl -X PUT "https://www.venturu.com/api/partner/v1/listings/LISTING-123" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"brokerExternalId": "BROKER-789",
"status": "FOR_SALE",
"businessType": "Restaurant",
"location": {
"city": "Miami",
"state": "Florida",
"country": "US",
"visibility": "SHOW_CITY_STATE"
}
}'
```
Now live! Buyers can find and contact you about this listing.
### Mark as Under Contract
```bash theme={null}
curl -X PUT "https://www.venturu.com/api/partner/v1/listings/LISTING-123" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"brokerExternalId": "BROKER-789",
"status": "UNDER_CONTRACT"
}'
```
Shows "Under Contract" badge. Deal is in progress, NOT removed from active search.
### Mark as Sold
```bash theme={null}
curl -X PUT "https://www.venturu.com/api/partner/v1/listings/LISTING-123" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"brokerExternalId": "BROKER-789",
"status": "SOLD",
}'
```
Congratulations on the sale! The listing is now marked as sold.
### Archive (Temporarily Hide)
```bash theme={null}
curl -X PUT "https://www.venturu.com/api/partner/v1/listings/LISTING-123" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"brokerExternalId": "BROKER-789",
"status": "ARCHIVED",
"businessType": "Restaurant",
"location": {
"city": "Miami",
"state": "Florida",
"country": "US",
"visibility": "SHOW_CITY_STATE"
}
}'
```
**Archived!** The listing is hidden but all data is preserved. Change back to `FOR_SALE` anytime.
### Mark as Reviewing Offers
```bash theme={null}
curl -X PUT "https://www.venturu.com/api/partner/v1/listings/LISTING-123" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"brokerExternalId": "BROKER-789",
"status": "REVIEWING_OFFERS",
"businessType": "Restaurant",
"location": {
"city": "Miami",
"state": "Florida",
"country": "US",
"visibility": "SHOW_CITY_STATE"
}
}'
```
Still visible and searchable. Shows you're actively evaluating offers.
## Common Workflows
### Seller Pulls Listing Off Market
**Scenario:** Seller decides not to sell right now.
```json theme={null}
{
"status": "ARCHIVED"
}
```
### You Have Interested Buyers
**Scenario:** Multiple offers coming in, still accepting more.
```json theme={null}
{
"status": "REVIEWING_OFFERS"
}
```
### Offer Accepted, Pending Paperwork
**Scenario:** You've accepted an offer, waiting on signed contract.
```json theme={null}
{
"status": "PENDING_CONTRACT"
}
```
### Contract Signed, In Due Diligence
**Scenario:** Contract is signed, buyer is doing their research.
```json theme={null}
{
"status": "UNDER_CONTRACT"
}
```
### Deal Closes Successfully
**Scenario:** Transaction complete, business sold!
```json theme={null}
{
"status": "SOLD"
}
```
### Deal Falls Through
**Scenario:** Pending deal didn't work out, back on market.
```json theme={null}
{
"status": "FOR_SALE"
}
```
## Important Notes
**DRAFT:** For new listings you're still preparing. Not visible anywhere.
**FOR\_SALE:** For ready-to-show listings. Appears in search, gets traffic.
Start with `DRAFT`, switch to `FOR_SALE` when ready!
Yes! If a deal falls through, just change status back to `FOR_SALE` or `UNDER_CONTRACT`. No data is lost.
**ARCHIVED:** Was active before, temporarily hidden (like "archiving")
**DRAFT:** Never been active, still being prepared
Both are hidden from buyers. Use whichever makes sense for your workflow!
The listing is not removed from search. Leads may still come through the direct URL.
**REVIEWING\_OFFERS:** You have offers but haven't accepted yet. Still accepting new offers.
**PENDING\_CONTRACT:** You've accepted an offer, waiting for contract to be signed.
Both are visible to buyers with appropriate badges.
## The Complete Status Flow
Here's the typical lifecycle of a listing:
```mermaid theme={null}
graph LR
A[DRAFT] --> B[FOR_SALE]
B --> C[REVIEWING_OFFERS]
C --> D[PENDING_CONTRACT]
D --> E[UNDER_CONTRACT]
E --> F[SOLD]
E -.-> B
D -.-> B
C -.-> B
B --> G[ARCHIVED]
G -.-> B
style B fill:#16a34a
style F fill:#3b82f6
style G fill:#6b7280
```
**Solid arrows** = normal progression\
**Dotted arrows** = deal fell through, back to market
## Status Change Rules
**You can change between any statuses** at any time. The API doesn't enforce a specific workflow - use whatever makes sense for your business!
Common transitions:
* `DRAFT` → `FOR_SALE` (publish for the first time)
* `FOR_SALE` → `REVIEWING_OFFERS` (offers coming in)
* `REVIEWING_OFFERS` → `PENDING_CONTRACT` (offer accepted)
* `PENDING_CONTRACT` → `UNDER_CONTRACT` (contract signed)
* `UNDER_CONTRACT` → `SOLD` (deal closed)
* `UNDER_CONTRACT` → `FOR_SALE` (deal fell through)
* `FOR_SALE` → `ARCHIVED` (seller changed mind)
* `ARCHIVED` → `FOR_SALE` (back on market)
## Bulk Status Updates
Need to change many listings at once? Just loop through them:
```python theme={null}
import requests
listings = ['LISTING-1', 'LISTING-2', 'LISTING-3']
for listing_id in listings:
response = requests.put(
f'https://www.venturu.com/api/partner/v1/listings/{listing_id}',
headers={'Authorization': f'Bearer {API_KEY}'},
json={
'brokerExternalId': 'BROKER-789',
'status': 'ARCHIVED', # Archive all
'businessType': 'Restaurant',
'location': {...}
}
)
print(f'{listing_id}: {response.json()["message"]}')
```
## Best Practices
Update status as deals progress. Buyers appreciate accurate information.
Shows momentum and creates urgency for other buyers.
Use `ARCHIVED` or `SOLD` instead of deleting. Preserves history and data.
Too many `FOR_SALE` listings? Consider archiving stale ones.
## Troubleshooting
### Status Not Changing?
Make sure you're including all required fields in your request:
* `brokerExternalId` or `broker` object
* `businessType`
* `location` object
### Invalid Status Error?
Check the spelling. Valid statuses are:
* `FOR_SALE`, `REVIEWING_OFFERS`, `PENDING_CONTRACT`, `UNDER_CONTRACT`, `SOLD`, `ARCHIVED`, `DRAFT`
### Listing Still Appearing?
Changes are instant, but:
* Clear your browser cache
* Wait \~1 minute for search index to update
* Check you used the correct `externalListingId`
## Next Steps
Change other listing details
Create a new listing
Full API documentation
Understanding the API
# Tracking Leads
Source: https://developers.venturu.com/guides/tracking-leads
## Monitor Lead Performance
**Note:** Lead tracking endpoints are only available for certain partners with organization-level access. Contact [joel@venturu.com](mailto:joel@venturu.com) to enable this feature.
Track how many leads your organization and offices are receiving from Venturu. Perfect for monitoring performance and ROI.
## Two Levels of Tracking
Get lead counts for a specific office
Get totals across all offices with breakdowns
## Office Level Leads
Get the total number of leads for a specific office, optionally filtered by date range.
**Endpoint:** `GET /partner/v1/offices/{officeId}/leads/count`
### Basic Request
```bash Get all leads for an office theme={null}
curl -X GET "https://www.venturu.com/api/partner/v1/offices/12345/leads/count" \
-H "Authorization: Bearer YOUR_API_KEY"
```
### Response
```json theme={null}
{
"status": "success",
"officeId": 12345,
"officeName": "Downtown Miami Office",
"totalLeads": 247
}
```
### Filter by Date Range
Add query parameters to filter leads within a specific time period:
```bash Last 30 Days theme={null}
curl -X GET "https://www.venturu.com/api/partner/v1/offices/12345/leads/count?startDate=2024-10-01T00:00:00Z&endDate=2024-10-31T23:59:59Z" \
-H "Authorization: Bearer YOUR_API_KEY"
```
```bash This Month theme={null}
# Get current month's leads
START_DATE=$(date -u +"%Y-%m-01T00:00:00Z")
END_DATE=$(date -u +"%Y-%m-%dT23:59:59Z")
curl -X GET "https://www.venturu.com/api/partner/v1/offices/12345/leads/count?startDate=${START_DATE}&endDate=${END_DATE}" \
-H "Authorization: Bearer YOUR_API_KEY"
```
```python Python theme={null}
import requests
from datetime import datetime, timedelta
import os
# Last 30 days
end_date = datetime.utcnow()
start_date = end_date - timedelta(days=30)
url = "https://www.venturu.com/api/partner/v1/offices/12345/leads/count"
params = {
"startDate": start_date.isoformat() + "Z",
"endDate": end_date.isoformat() + "Z"
}
response = requests.get(
url,
params=params,
headers={"Authorization": f"Bearer {os.getenv('VENTURU_API_KEY')}"}
)
print(response.json())
```
```javascript JavaScript theme={null}
const endDate = new Date();
const startDate = new Date();
startDate.setDate(startDate.getDate() - 30);
const params = new URLSearchParams({
startDate: startDate.toISOString(),
endDate: endDate.toISOString()
});
const response = await fetch(
`https://www.venturu.com/api/partner/v1/offices/12345/leads/count?${params}`,
{
headers: {
'Authorization': `Bearer ${process.env.VENTURU_API_KEY}`
}
}
);
const data = await response.json();
console.log(data);
```
## Organization Level Leads
Get lead counts across your entire organization, with optional breakdown by office.
**Endpoint:** `GET /partner/v1/organizations/{organizationId}/leads/count`
### Basic Request
```bash Get all organizational leads theme={null}
curl -X GET "https://www.venturu.com/api/partner/v1/organizations/789/leads/count" \
-H "Authorization: Bearer YOUR_API_KEY"
```
### Response
```json theme={null}
{
"status": "success",
"organizationId": 789,
"organizationName": "ABC Realty Group",
"totalLeads": 1523,
"officeBreakdown": [
{
"officeId": 12345,
"officeName": "Downtown Miami Office",
"totalLeads": 247
},
{
"officeId": 12346,
"officeName": "Boca Raton Office",
"totalLeads": 189
},
{
"officeId": 12347,
"officeName": "Fort Lauderdale Office",
"totalLeads": 312
}
]
}
```
### Filter by Date Range
```bash Last Quarter theme={null}
curl -X GET "https://www.venturu.com/api/partner/v1/organizations/789/leads/count?startDate=2024-07-01T00:00:00Z&endDate=2024-09-30T23:59:59Z" \
-H "Authorization: Bearer YOUR_API_KEY"
```
```python Python - Monthly Report theme={null}
import requests
from datetime import datetime
from calendar import monthrange
import os
def get_monthly_leads(org_id, year, month):
# Calculate first and last day of month
first_day = datetime(year, month, 1)
last_day_num = monthrange(year, month)[1]
last_day = datetime(year, month, last_day_num, 23, 59, 59)
url = f"https://www.venturu.com/api/partner/v1/organizations/{org_id}/leads/count"
params = {
"startDate": first_day.isoformat() + "Z",
"endDate": last_day.isoformat() + "Z"
}
response = requests.get(
url,
params=params,
headers={"Authorization": f"Bearer {os.getenv('VENTURU_API_KEY')}"}
)
return response.json()
# Get October 2024 leads
leads = get_monthly_leads(789, 2024, 10)
print(f"Total leads in October: {leads['totalLeads']}")
```
## Query Parameters
Both endpoints support the same optional query parameters:
Start date for filtering leads (ISO 8601 format: `2024-10-01T00:00:00Z`)
* If not provided, returns all leads from the beginning
* Must be a valid ISO 8601 datetime string
* Timezone aware (use UTC for consistency)
End date for filtering leads (ISO 8601 format: `2024-10-31T23:59:59Z`)
* If not provided, defaults to current date/time
* Must be a valid ISO 8601 datetime string
* Timezone aware (use UTC for consistency)
## Date Format
All dates must be in **ISO 8601 format**:
```text Format theme={null}
YYYY-MM-DDTHH:MM:SSZ
```
```text Examples theme={null}
2024-10-01T00:00:00Z ← Start of October 1, 2024 (UTC)
2024-10-31T23:59:59Z ← End of October 31, 2024 (UTC)
2024-01-15T12:30:00Z ← January 15, 2024 at 12:30 PM (UTC)
```
**Pro Tip:** Always use UTC timezone (ending with `Z`) to avoid timezone confusion across different systems.
## Common Use Cases
### Monthly Performance Report
```python theme={null}
# Get leads for each month of the quarter
import requests
from datetime import datetime
import os
def get_leads_for_month(org_id, year, month):
# Calculate month boundaries
if month == 12:
next_month = datetime(year + 1, 1, 1)
else:
next_month = datetime(year, month + 1, 1)
start = datetime(year, month, 1)
end = next_month - timedelta(seconds=1)
params = {
"startDate": start.isoformat() + "Z",
"endDate": end.isoformat() + "Z"
}
response = requests.get(
f"https://www.venturu.com/api/partner/v1/organizations/{org_id}/leads/count",
params=params,
headers={"Authorization": f"Bearer {os.getenv('VENTURU_API_KEY')}"}
)
return response.json()
# Q4 2024 Report
q4_months = [10, 11, 12]
for month in q4_months:
data = get_leads_for_month(789, 2024, month)
print(f"Month {month}: {data['totalLeads']} leads")
```
### Compare Office Performance
```javascript theme={null}
// Get and compare multiple offices
async function compareOffices(officeIds, startDate, endDate) {
const params = new URLSearchParams({
startDate: startDate.toISOString(),
endDate: endDate.toISOString()
});
const results = await Promise.all(
officeIds.map(async (officeId) => {
const response = await fetch(
`https://www.venturu.com/api/partner/v1/offices/${officeId}/leads/count?${params}`,
{
headers: {
'Authorization': `Bearer ${process.env.VENTURU_API_KEY}`
}
}
);
return response.json();
})
);
// Sort by performance
results.sort((a, b) => b.totalLeads - a.totalLeads);
console.log('Top Performing Offices:');
results.forEach((office, index) => {
console.log(`${index + 1}. ${office.officeName}: ${office.totalLeads} leads`);
});
}
// Compare last 30 days
const end = new Date();
const start = new Date();
start.setDate(start.getDate() - 30);
compareOffices([12345, 12346, 12347], start, end);
```
### Year-to-Date Tracking
```bash theme={null}
# Get all leads from January 1 to now
START_OF_YEAR=$(date -u +"%Y-01-01T00:00:00Z")
NOW=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
curl -X GET "https://www.venturu.com/api/partner/v1/organizations/789/leads/count?startDate=${START_OF_YEAR}&endDate=${NOW}" \
-H "Authorization: Bearer YOUR_API_KEY"
```
## Error Handling
Invalid query parameters or date format.
```json theme={null}
{
"status": "error",
"error": "Invalid query parameters. Dates must be in ISO 8601 format."
}
```
**Solutions:**
* Check date format is ISO 8601: `YYYY-MM-DDTHH:MM:SSZ`
* Ensure dates include timezone (use `Z` for UTC)
* Verify `startDate` is before `endDate`
Missing or invalid API key, or insufficient permissions.
```json theme={null}
{
"status": "error",
"error": "Unauthorized"
}
```
**Solutions:**
* Verify your API key is correct
* Check that your key has lead tracking permissions
* Contact [joel@venturu.com](mailto:joel@venturu.com) to enable this feature
Office or organization doesn't exist or you don't have access.
```json theme={null}
{
"status": "error",
"error": "Office not found"
}
```
**Solutions:**
* Verify the office/organization ID is correct
* Check that the office belongs to your organization
* Ensure you're using the Venturu ID, not your external ID
## Best Practices
Always use UTC (Z suffix) for consistent cross-system reporting.
Lead counts don't change retroactively. Cache historical data.
Use organization endpoint instead of multiple office calls.
Pull data on a schedule (daily/weekly) for trend analysis.
## Common Questions
A lead is created when a buyer expresses interest in a listing through:
* Direct contact form submission
* Phone inquiries (if tracked)
* Email inquiries to the broker
Currently, the API only provides lead **counts** and statistics. Individual lead details (names, emails, messages) are not available through the API for privacy reasons.
Lead counts update in real-time. When you query the API, you get the current count for your specified date range.
Contact [joel@venturu.com](mailto:joel@venturu.com). The organization ID is provided during partnership setup for partners with this feature enabled.
Yes! Use the organization endpoint - it returns total leads plus a breakdown by each office automatically.
## Integration Example
Here's a complete example building a simple lead dashboard:
```python Complete Dashboard Example theme={null}
import requests
from datetime import datetime, timedelta
import os
API_KEY = os.getenv('VENTURU_API_KEY')
BASE_URL = "https://www.venturu.com/api/partner/v1"
ORG_ID = 789
def get_leads_by_period(org_id, start_date, end_date):
"""Get leads for a specific date range."""
params = {
"startDate": start_date.isoformat() + "Z",
"endDate": end_date.isoformat() + "Z"
}
response = requests.get(
f"{BASE_URL}/organizations/{org_id}/leads/count",
params=params,
headers={"Authorization": f"Bearer {API_KEY}"}
)
return response.json()
# Generate monthly report for Q4 2024
months = [
("October", datetime(2024, 10, 1), datetime(2024, 10, 31, 23, 59, 59)),
("November", datetime(2024, 11, 1), datetime(2024, 11, 30, 23, 59, 59)),
("December", datetime(2024, 12, 1), datetime(2024, 12, 31, 23, 59, 59)),
]
print("=== Q4 2024 Lead Report ===\n")
for month_name, start, end in months:
data = get_leads_by_period(ORG_ID, start, end)
print(f"{month_name} {start.year}")
print(f"Total Leads: {data['totalLeads']}")
print("\nOffice Breakdown:")
for office in data['officeBreakdown']:
print(f" - {office['officeName']}: {office['totalLeads']} leads")
print("\n" + "-" * 50 + "\n")
```
## Next Steps
Set up brokers to receive leads
Create listings to generate leads
Full API documentation
Enable lead tracking
# Updating a Broker
Source: https://developers.venturu.com/guides/updating-a-broker
## Update Broker Information
Need to change a broker's phone number? Update their bio? It's the same simple process.
**Same Endpoint:** Updating uses the exact same endpoint as creating. Just use the same `externalBrokerId` you used before.
## How It Works
`PUT /partner/v1/brokers/{externalBrokerId}`
When you send a PUT request with an `externalBrokerId` that already exists, we update that broker with the new information.
Use the exact same `externalBrokerId` you used when creating the broker.
For example, if you created: `/brokers/BROKER-789`\
To update, use: `/brokers/BROKER-789`
Include all the fields you want to update. You can send:
* **Just the changed fields** (recommended)
* **All fields** (safest - ensures everything is in sync)
```json theme={null}
{
"name": "Jane Doe-Smith",
"email": "jane@realestate.com",
"phone": "+1-555-NEW-NUMBER"
}
```
You'll receive a `200 OK` response (not `201` like creation):
```json theme={null}
{
"status": "success",
"message": "Broker updated successfully",
"venturuBrokerId": "cmhnmzme1000b396q58yx17fm",
"venturuProfileUrl": "https://www.venturu.com/u/jane-doe-smith"
}
```
## Common Update Scenarios
### Changing Contact Information
```bash theme={null}
curl -X PUT "https://www.venturu.com/api/partner/v1/brokers/BROKER-789" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Jane Doe",
"email": "jane.new@realestate.com",
"phone": "+1-555-9999"
}'
```
### Adding or Updating Photo
```json theme={null}
{
"name": "Jane Doe",
"email": "jane@realestate.com",
"avatarUrl": "https://example.com/photos/jane-new-headshot.jpg"
}
```
When you update `avatarUrl`, we'll download and process the new image. It may take a few minutes to appear on the profile.
### Updating Bio and Social Links
```json theme={null}
{
"name": "Jane Doe",
"email": "jane@realestate.com",
"profile": {
"bio": "Award-winning business broker with 15+ years of experience. Specializing in restaurant acquisitions $500K-$5M.",
"website": "https://janedoebroker.com",
"linkedInUrl": "https://linkedin.com/in/jane-doe-broker"
}
}
```
### Adding or Updating Licenses
```json theme={null}
{
"name": "Jane Doe",
"email": "jane@realestate.com",
"licenses": [
{
"licenseNumber": "BK123456",
"state": "Florida",
"country": "US"
},
{
"licenseNumber": "BK789012",
"state": "Georgia",
"country": "US"
}
]
}
```
**Important:** The `licenses` array replaces ALL existing licenses. Include all licenses you want the broker to have, not just new ones.
### Expanding Service Areas
```json theme={null}
{
"name": "Jane Doe",
"email": "jane@realestate.com",
"serviceAreas": [
{
"city": "Miami",
"state": "Florida",
"country": "US"
},
{
"city": "Fort Lauderdale",
"state": "Florida",
"country": "US"
},
{
"county": "Broward County",
"state": "Florida",
"country": "US"
}
]
}
```
**Important:** The `serviceAreas` array replaces ALL existing areas. Include all areas you want to display.
## Best Practices
When updating, send all fields (not just changed ones) to keep everything in perfect sync.
Update broker profiles whenever data changes in your system to keep Venturu current.
If an update fails, retry with exponential backoff. Updates are idempotent - safe to retry.
Track `200 OK` vs `201 Created` to see if you're accidentally creating duplicates.
## Partial Updates
You can update just specific fields if you prefer:
```json Only updating phone number theme={null}
{
"name": "Jane Doe",
"email": "jane@realestate.com",
"phone": "+1-555-NEW-PHONE"
}
```
**Note:** While partial updates work, sending the complete broker object is safer and ensures data consistency across systems.
## Common Questions
You'll create a **new broker** instead of updating. Always use the same `externalBrokerId` for the same broker.
Yes, but you still need to include `name` and `email` (the required fields). Other fields will keep their existing values.
As often as you need! There are no rate limits on updates. Just be respectful of the API.
Most updates are instant. Photos and some profile changes may take a few minutes to propagate.
## Troubleshooting
### Getting 404 Broker Not Found?
This means the `externalBrokerId` doesn't exist yet. Double-check:
1. You're using the correct external ID
2. The broker was created successfully
3. You're using the same partner API key
### Photo Not Updating?
Photos are processed asynchronously:
1. Wait 5-10 minutes
2. Clear your browser cache
3. Check that the image URL is publicly accessible
4. Ensure the image is at least 400x400px
## Next Steps
Create a listing for this broker
Learn to update listings
Control listing visibility
Full API documentation
# Updating a Listing
Source: https://developers.venturu.com/guides/updating-a-listing
## Update Listing Information
Need to change the price? Update photos? Add new details? Same endpoint, same process.
**Same Endpoint:** Updating uses the exact same endpoint as creating. Just use the same `externalListingId` you used before.
## How It Works
`PUT /partner/v1/listings/{externalListingId}`
When you send a PUT request with an `externalListingId` that already exists, we update that listing.
Use the exact same `externalListingId` from when you created the listing.
Created with: `/listings/LISTING-123`\
Update with: `/listings/LISTING-123`
Include the fields you want to update. We recommend sending **all fields** to keep everything in sync.
You'll receive a `200 OK` response:
```json theme={null}
{
"status": "success",
"message": "Listing updated successfully",
"venturuListingId": 98765,
"venturuListingUrl": "https://www.venturu.com/business/..."
}
```
## Common Updates
### Change Price
```json theme={null}
{
"brokerExternalId": "BROKER-789",
"status": "FOR_SALE",
"businessType": "Restaurant",
"location": {...},
"financials": {
"askingPrice": 495000, // Reduced from $550k
"revenue": 800000,
"sde": 220000
}
}
```
### Update Photos
```json theme={null}
{
"brokerExternalId": "BROKER-789",
"status": "FOR_SALE",
"businessType": "Restaurant",
"location": {...},
"photos": [
{
"url": "https://example.com/new-photo1.jpg",
"sortKey": 1
},
{
"url": "https://example.com/new-photo2.jpg",
"sortKey": 2
}
]
}
```
**Important:** The `photos` array replaces ALL existing photos. Include all photos you want to display.
### Change Description
```json theme={null}
{
"brokerExternalId": "BROKER-789",
"status": "FOR_SALE",
"title": "Profitable Downtown Pizzeria - Price Reduced!",
"description": "Updated description with new details...",
"businessType": "Restaurant",
"location": {...}
}
```
### Update Financials
```json theme={null}
{
"brokerExternalId": "BROKER-789",
"status": "FOR_SALE",
"businessType": "Restaurant",
"location": {...},
"financials": {
"askingPrice": 550000,
"revenue": 850000, // Updated numbers
"sde": 240000,
"inventory": 30000,
"ffande": 150000
}
}
```
### Change Location Visibility
```json theme={null}
{
"brokerExternalId": "BROKER-789",
"status": "FOR_SALE",
"businessType": "Restaurant",
"location": {
"streetAddress1": "123 Main St",
"city": "Miami",
"state": "Florida",
"country": "US",
"visibility": "SHOW_FULL_ADDRESS" // Now showing full address
}
}
```
### Update Property Info
```json theme={null}
{
"brokerExternalId": "BROKER-789",
"status": "FOR_SALE",
"businessType": "Restaurant",
"location": {...},
"property": {
"propertyKind": "RENTED",
"areaSqft": 2500,
"rentData": {
"amount": 5500, // Rent increased
"frequency": "MONTHLY",
"leaseExpiration": "2029-12-31T00:00:00.000Z" // Lease renewed
}
}
}
```
## Best Practices
Always send all fields, not just what changed. Ensures perfect sync.
Keep listings current - update when prices or details change.
After updating, visit the listing URL to verify changes appear correctly.
Monitor `200 OK` responses. If you get `201`, you might have the wrong ID.
## Common Questions
You'll create a **new listing** instead of updating. Always use the same ID for the same listing.
Yes, but you still need required fields (`brokerExternalId`, `status`, `businessType`, `location`). Other fields keep their existing values.
Yes! Changes are live immediately. Photos may take a minute to process.
Yes! Just change the `brokerExternalId` to a different broker.
## Field-Specific Tips
### Updating Arrays (Photos, etc.)
Arrays like `photos` **replace** the entire list. Always include all items:
```json Good - All photos included (use fully qualified URLs) theme={null}
{
"photos": [
{"url": "https://cdn.yoursite.com/photo1.jpg", "sortKey": 1},
{"url": "https://cdn.yoursite.com/photo2.jpg", "sortKey": 2},
{"url": "https://cdn.yoursite.com/photo3.jpg", "sortKey": 3}
]
}
```
```json Bad - Missing photos will be removed theme={null}
{
"photos": [
{"url": "https://cdn.yoursite.com/photo3.jpg", "sortKey": 3} // Only this photo will remain!
]
}
```
### Updating Nested Objects
For nested objects like `financials` or `property`, you **don't** need to include the entire object:
```json theme={null}
"financials": {
"askingPrice": 550000, // Only include changed fields
"revenue": 800000,
"sde": 220000
}
```
## Troubleshooting
### Getting 404 Listing Not Found?
The `externalListingId` doesn't exist. Check:
1. Correct ID spelling/format
2. Listing was created successfully
3. Using same API key
### Changes Not Appearing?
* Wait \~1 minute for search index
* Clear browser cache
* Check the returned `venturuListingUrl`
### Getting 201 Instead of 200?
You're creating a new listing, not updating. The `externalListingId` doesn't match any existing listing.
## Next Steps
Change listing visibility
Create a new listing
Update broker information
Full API documentation
# Welcome to the Developer Center
Source: https://developers.venturu.com/introduction/index
## Let's Build Together
Welcome to the Venturu Developer Center! Our API provides a simple and powerful way for developers to syndicate business listings and broker profiles directly to the Venturu marketplace.
By integrating with our API, you can automate your workflow, ensure data is always up-to-date, and connect brokers with thousands of active buyers searching for their next opportunity.
Push and update business listings programmatically. No more manual data entry.
Keep broker photos, bios, licenses, and service areas perfectly in sync.
Integrate directly with your CRM's lead-capture email system for instant delivery.
Built with idempotent principles to handle network issues gracefully and prevent duplicates.
### Who is this API for?
This API is designed for our strategic partners and developers, including:
* **Broker CRMs:** Offer Venturu as a premium syndication channel to your customers.
* **Large Brokerages:** Automate the management of your firm's entire listing inventory on Venturu.
* **Franchise Networks:** Ensure brand consistency and timely updates for all franchisee listings.
### Trusted By Leading Organizations
Venturu is proud to partner with premier business brokerage associations and networks:
Ready to get started? The first step is to [get your API key](/introduction/onboarding).
# Getting an API Key
Source: https://developers.venturu.com/introduction/onboarding
## Let's Get You Connected
Access to the Venturu API is currently available to approved developers and partners. We provide a white-glove onboarding experience to ensure your integration is a success from day one.
### The Onboarding Process
The entire process, from your first email to making your first API call, is simple and straightforward.
```mermaid theme={null}
sequenceDiagram
participant You as Developer
participant Joel as Venturu Partnerships
participant YourSystem as Your System
participant VenturuAPI as Venturu API
You->>Joel: 1. Email to request API access
Joel-->>You: 2. Welcome! Let's chat.
Note over You,Joel: Partnership Agreement & Use Case Review
Joel-->>You: 3. Here is your unique API Key.
You->>YourSystem: 4. Configure system with API Key.
YourSystem->>VenturuAPI: 5. Test key with GET /health
VenturuAPI-->>YourSystem: 200 OK
```
### How to Get Started
To begin the process, please reach out to our Head of Partnerships:
**[joel@venturu.com](mailto:joel@venturu.com)**
**What to include in your email:**
* Your company's name and website.
* A brief description of your platform or brokerage.
* How you envision using the Venturu API.
Once your application is approved, our team will provide you with a unique API key and all the support you need to begin a smooth integration.
# Authentication
Source: https://developers.venturu.com/mcp-server/authentication
OAuth 2.0 + PKCE authentication for the Venturu MCP server.
## Authentication is Optional
Most tools on the Venturu MCP server work **without authentication**. You can search businesses, browse brokers, and retrieve details without logging in.
Authentication is only required for tools that take action on behalf of a user:
| Tool | Auth Required |
| -------------------------- | ------------- |
| `search_businesses` | No |
| `search_brokers` | No |
| `get_business` | No |
| `get_broker` | No |
| `list_business_categories` | No |
| `list_languages` | No |
| `contact_broker` | **Yes** |
| `contact_seller` | **Yes** |
| `who_am_i` | **Yes** |
## How It Works
The Venturu MCP server implements the **OAuth 2.0 Authorization Code flow with PKCE** (Proof Key for Code Exchange), the standard for MCP authentication. Most MCP clients handle this flow automatically — you just approve the connection.
```mermaid theme={null}
sequenceDiagram
participant User
participant Client as MCP Client
participant Venturu as Venturu OAuth
Client->>Venturu: 1. Register client (Dynamic Client Registration)
Venturu-->>Client: client_id
Client->>Venturu: 2. Authorization request + PKCE challenge
Venturu-->>User: 3. Show consent screen
User->>Venturu: 4. Approve access
Venturu-->>Client: 5. Authorization code
Client->>Venturu: 6. Exchange code + PKCE verifier for tokens
Venturu-->>Client: 7. Access token + Refresh token
Client->>Venturu: 8. API calls with Bearer token
```
### What Happens in Practice
1. **You trigger an authenticated tool** — e.g., ask the AI to contact a broker
2. **Your MCP client opens a browser window** to the Venturu consent screen
3. **You approve the connection** with your Venturu account
4. **The client receives tokens** and can make authenticated requests
5. **Tokens refresh automatically** — you won't need to log in again
## OAuth Endpoints
For client developers building MCP integrations, here are the standard discovery endpoints:
| Endpoint | URL |
| --------------------------------- | ---------------------------------------------------------------- |
| **Authorization Server Metadata** | `https://www.venturu.com/.well-known/oauth-authorization-server` |
| **Protected Resource Metadata** | `https://www.venturu.com/.well-known/oauth-protected-resource` |
| **Authorization** | `https://www.venturu.com/api/oauth/mcp/authorize` |
| **Token** | `https://www.venturu.com/api/oauth/mcp/token` |
| **Dynamic Client Registration** | `https://www.venturu.com/api/oauth/mcp/register` |
## Scopes
| Scope | Description |
| ------------ | ------------------------------------------------ |
| `mcp:access` | Access to all MCP tools, including contact tools |
## Token Lifetimes
| Token | Lifetime |
| ----------------- | ----------------------------------- |
| **Access token** | 1 hour |
| **Refresh token** | Managed automatically by the client |
Access tokens are encrypted JWE tokens. When an access token expires, compliant MCP clients will automatically use the refresh token to obtain a new one without requiring you to log in again.
## Dynamic Client Registration
The Venturu MCP server supports [RFC 7591 Dynamic Client Registration](https://tools.ietf.org/html/rfc7591). MCP clients can register themselves automatically without manual configuration. This means:
* No need to pre-register your application
* No client secrets to manage
* The client receives a `client_id` on first connection
If your MCP client supports the standard OAuth 2.0 discovery flow (via `.well-known/oauth-authorization-server`), authentication will work out of the box with no manual configuration.
## Troubleshooting
You're calling a contact tool without being authenticated. Your MCP client should prompt you to log in — check for a browser popup or notification. If not, reconnect to the server and try again.
Some MCP clients may not support OAuth flows yet. Check your client's MCP documentation for authentication support. You can still use all read-only tools without authentication.
Access tokens last 1 hour. Your MCP client should automatically refresh them. If you're seeing auth errors after a long session, try disconnecting and reconnecting to the server.
# Compatible Clients
Source: https://developers.venturu.com/mcp-server/compatible-clients
AI assistants and development tools that work with the Venturu MCP server.
## Supported MCP Clients
The Venturu MCP server uses the **Streamable HTTP** transport, which is supported by a growing number of AI assistants and development tools. Any client that implements the MCP specification can connect.
### AI Assistants
| Client | Status | Notes |
| ------------------ | --------- | ------------------------------------------------------------- |
| **Claude Desktop** | Supported | Full tool support with OAuth authentication |
| **ChatGPT** | Supported | Enhanced experience with interactive listing and broker cards |
| **Claude (Web)** | Supported | Works via the MCP integrations panel |
### Development Tools
| Client | Status | Notes |
| ------------ | --------- | --------------------------- |
| **Cursor** | Supported | Available in Agent mode |
| **Windsurf** | Supported | Remote MCP server support |
| **VS Code** | Supported | Via MCP extensions |
| **Cline** | Supported | Remote server configuration |
### Frameworks & Libraries
| Framework | Transport | Notes |
| ---------------------- | --------------- | --------------------------------------- |
| **MCP TypeScript SDK** | Streamable HTTP | `@modelcontextprotocol/sdk` |
| **MCP Python SDK** | Streamable HTTP | `mcp` package |
| **mcp-handler** | Streamable HTTP | Used to build the Venturu server itself |
## Client-Specific Features
### ChatGPT Apps SDK Widgets
When accessed from ChatGPT, the Venturu MCP server returns interactive HTML widgets for search results. Business listings and broker profiles are rendered as rich, visual cards directly in the conversation — with images, pricing, and direct links.
Widget resources are served automatically when the server detects a ChatGPT client. No additional configuration is needed.
### Voice Agent Integration
The Venturu MCP server supports integration with voice AI platforms like **ElevenLabs Conversational AI**. A pre-registered OAuth client allows voice agents to authenticate and use all tools, including contact tools, on behalf of users.
## Building a Custom Client
If you're building your own MCP client, connect using these details:
```json theme={null}
{
"name": "com.venturu/mcp-server",
"version": "1.0.0",
"remotes": [
{
"type": "streamable-http",
"url": "https://www.venturu.com/mcp"
}
]
}
```
### Discovery Endpoints
| Endpoint | URL |
| ------------------------------- | ---------------------------------------------------------------- |
| **OAuth Authorization Server** | `https://www.venturu.com/.well-known/oauth-authorization-server` |
| **Protected Resource Metadata** | `https://www.venturu.com/.well-known/oauth-protected-resource` |
### Authentication Flow
1. Discover endpoints via `.well-known/oauth-authorization-server`
2. Register your client via Dynamic Client Registration (`/api/oauth/mcp/register`)
3. Initiate OAuth 2.0 + PKCE authorization flow
4. Exchange authorization code for access and refresh tokens
5. Include the access token as a `Bearer` token in MCP requests
See the [Authentication](/mcp/authentication) page for full details.
# Venturu MCP Server
Source: https://developers.venturu.com/mcp-server/index
Connect AI assistants to the Venturu business marketplace using the Model Context Protocol.
## Give Your AI Access to Business Data
The Venturu MCP server lets AI assistants search thousands of businesses for sale, discover brokers, and contact sellers — all through a standardized protocol that works with any MCP-compatible client.
Whether you're building an AI-powered business acquisition tool, a conversational broker finder, or just want to search Venturu from your favorite AI assistant, the MCP server is the fastest way to get started.
Full-featured business search with location, price, revenue, industry filters, and more.
Find verified business brokers by location, language, ratings, and experience.
Retrieve comprehensive details for any listing or broker profile.
Send messages to brokers and sellers through the platform (requires authentication).
## What is MCP?
The [Model Context Protocol](https://modelcontextprotocol.io) (MCP) is an open standard that lets AI assistants connect to external tools and data sources. Instead of building custom integrations for each AI platform, a single MCP server works with all compatible clients — Claude, ChatGPT, Cursor, Windsurf, and more.
## Server Details
| Property | Value |
| ------------------ | -------------------------------------------------------------- |
| **Server Name** | `com.venturu/mcp-server` |
| **Endpoint** | `https://www.venturu.com/mcp` |
| **Transport** | Streamable HTTP |
| **Authentication** | OAuth 2.0 with PKCE (optional for read-only tools) |
| **Tools** | 9 tools across search, detail, contact, and utility categories |
## Quick Start
Add the Venturu MCP server to your client in seconds:
```json theme={null}
{
"mcpServers": {
"venturu": {
"url": "https://www.venturu.com/mcp"
}
}
}
```
Step-by-step setup for Claude Desktop, ChatGPT, Cursor, and other clients.
## Available Tools
The server exposes 9 tools organized into four categories:
| Category | Tools | Auth Required |
| ------------ | -------------------------------------------- | ------------- |
| **Search** | `search_businesses`, `search_brokers` | No |
| **Detail** | `get_business`, `get_broker` | No |
| **Lookup** | `list_business_categories`, `list_languages` | No |
| **Contact** | `contact_broker`, `contact_seller` | Yes |
| **Identity** | `who_am_i` | Yes |
Most tools work without authentication, making it easy to start exploring right away. Authentication is only required for tools that take action on behalf of a user.
Complete documentation for all 9 tools with parameters, examples, and response formats.
# Quickstart
Source: https://developers.venturu.com/mcp-server/quickstart
Connect to the Venturu MCP server from your AI client in under a minute.
## Connect in Seconds
The Venturu MCP server uses **Streamable HTTP** transport, which means most modern MCP clients can connect with just a URL — no local installation, no API keys, no configuration files.
```
https://www.venturu.com/mcp
```
## Setup by Client
1. Open **Claude Desktop** and go to **Settings** > **Developer** > **Edit Config**
2. Add the Venturu server to your `claude_desktop_config.json`:
```json theme={null}
{
"mcpServers": {
"venturu": {
"url": "https://www.venturu.com/mcp"
}
}
}
```
3. Save the file and **restart Claude Desktop**
4. You should see the Venturu tools appear in the tools menu (hammer icon)
ChatGPT supports MCP servers natively. The Venturu server is available as a remote connection:
1. Open a new conversation in **ChatGPT**
2. Click the **paperclip icon** and select **Connect to MCP Server**
3. Enter the server URL: `https://www.venturu.com/mcp`
4. The Venturu tools will appear in the conversation
ChatGPT users get an enhanced experience with interactive listing and broker cards rendered directly in the chat.
1. Open **Cursor Settings** > **MCP**
2. Click **Add new MCP server**
3. Set the type to **streamable-http** and enter:
```json theme={null}
{
"mcpServers": {
"venturu": {
"url": "https://www.venturu.com/mcp"
}
}
}
```
4. The Venturu tools will be available in Agent mode
1. Open the **Windsurf** MCP settings
2. Add a new remote MCP server with the URL:
```
https://www.venturu.com/mcp
```
3. Save and the tools will be available in your AI conversations
Any client that supports the **Streamable HTTP** MCP transport can connect. Use the following details:
| Property | Value |
| ------------- | ------------------------------ |
| **URL** | `https://www.venturu.com/mcp` |
| **Transport** | Streamable HTTP |
| **Auth** | Optional — OAuth 2.0 with PKCE |
If your client supports `server.json` manifests, point it to:
```json theme={null}
{
"name": "com.venturu/mcp-server",
"remotes": [
{
"type": "streamable-http",
"url": "https://www.venturu.com/mcp"
}
]
}
```
## Verify the Connection
Once connected, try a simple prompt to confirm everything is working:
```txt title="Try This Prompt" theme={null}
Search for restaurants for sale in Miami under $500,000
```
The AI should call the `search_businesses` tool and return a list of matching business listings from Venturu.
If you see business results, you're connected. No API key needed for search tools.
## Optional: Authenticate for Full Access
Search and detail tools work without authentication. To use **contact tools** (sending messages to brokers and sellers), you'll need to authenticate with your Venturu account.
When you attempt to use a tool like `contact_broker`, your MCP client will walk you through an OAuth login flow — just approve the connection with your Venturu credentials.
Details on the OAuth 2.0 + PKCE flow and what each scope provides.
## Next Steps
See the full reference for all 9 available tools.
Understand the request limits for anonymous and authenticated usage.
# Rate Limiting
Source: https://developers.venturu.com/mcp-server/rate-limiting
Request limits and best practices for the Venturu MCP server.
## Rate Limits
The Venturu MCP server applies rate limiting per tool call to ensure fair usage and platform stability. Limits differ based on whether you're authenticated.
| Tier | Limit | Window | Identifier |
| ----------------- | ------------ | ---------- | ---------- |
| **Anonymous** | 300 requests | 60 seconds | IP address |
| **Authenticated** | 500 requests | 60 seconds | User ID |
Rate limits are applied using a **sliding window** algorithm. This means the window moves continuously rather than resetting at fixed intervals, providing smoother rate limiting behavior.
## How It Works
Every MCP tool call counts as one request. When you exceed the limit, the tool will return a message:
```
Rate limit exceeded. Please try again later.
```
The rate limiter identifies anonymous users by their IP address. Authenticated users are identified by their Venturu user ID, giving them a higher limit regardless of IP.
## Best Practices
Authenticated users get 500 requests per minute vs. 300 for anonymous. Connect your Venturu account for the best experience.
Narrow your searches with filters (location, price range, business type) to get better results in fewer requests.
Results return up to 15 items at a time with cursor-based pagination. Fetch more only when needed.
The `list_business_categories` and `list_languages` tools return relatively static data. Avoid calling them repeatedly in the same session.
## Need Higher Limits?
If you're building an integration that requires higher throughput, reach out to discuss enterprise options:
**[joel@venturu.com](mailto:joel@venturu.com)** — We're happy to work with you on custom limits.
# contact_broker
Source: https://developers.venturu.com/mcp-server/tools/contact-broker
Send a message to a broker on Venturu. Requires authentication.
## contact\_broker
Send a contact message to a broker on Venturu by their profile slug. The broker will be notified and can respond through the platform.
This tool **requires authentication**. You must be signed in with your Venturu account. See [Authentication](/mcp/authentication) for details.
## Parameters
| Parameter | Type | Required | Description |
| ------------- | ------------------------- | --------------------------- | --------------------------------------------------------------------------------------------------- |
| `slug` | `string` | **Yes** | The broker's profile slug (from `search_brokers` or `get_broker`) |
| `message` | `string` | **Yes** | The message to send to the broker |
| `inquiryType` | `"buying"` \| `"selling"` | No (defaults to `"buying"`) | Whether the message is for buyer representation (`"buying"`) or seller representation (`"selling"`) |
## Response
On success:
```
Your message has been sent to Jane Smith on Venturu (buyer
representation). They will be notified and can respond through the
platform.
Message: "Hi Jane, I'm interested in learning more about restaurant
opportunities in the Miami area. Do you have any upcoming listings?"
```
## Error Responses
```
This tool requires authentication. Please connect your Venturu
account to contact brokers.
```
**Solution:** Connect your Venturu account through the OAuth flow in your MCP client.
```
No verified broker found with slug "invalid-slug". Check the slug
and try again, or use search_brokers to find brokers.
```
**Solution:** Use `search_brokers` to find the correct slug.
## Typical Flow
1. Call `search_brokers` to find brokers in your area
2. Call `get_broker` to view a broker's full profile
3. Decide whether your inquiry is about buying or selling
4. Call `contact_broker` with the broker's slug, your message, and optional `inquiryType`
## Tool Annotations
| Annotation | Value |
| ----------------- | ------- |
| `readOnlyHint` | `false` |
| `destructiveHint` | `false` |
| `openWorldHint` | `true` |
This tool sends a message to an external party, which is why it's annotated as open-world.
# contact_seller
Source: https://developers.venturu.com/mcp-server/tools/contact-seller
Send a message to a business listing seller on Venturu. Requires authentication.
## contact\_seller
Send a contact message to the seller (or their representing broker) of a specific business listing on Venturu. The recipient will be notified and can respond through the platform.
This tool **requires authentication**. You must be signed in with your Venturu account. See [Authentication](/mcp/authentication) for details.
## Parameters
| Parameter | Type | Required | Description |
| ----------- | --------- | -------- | ----------------------------------------------------------------------------- |
| `listingId` | `integer` | **Yes** | The listing's numeric ID (from `search_businesses` or `get_business` results) |
| `message` | `string` | **Yes** | The message to send to the seller |
If the listing has a seller's agent (broker), the message is sent to the broker. Otherwise, it goes directly to the business owner.
## Response
On success:
```
Your message has been sent to the seller on Venturu. They will be
notified and can respond through the platform.
Message: "I'm interested in this business. Could we schedule a call
to discuss the financials in more detail?"
```
## Error Responses
```
This tool requires authentication. Please connect your Venturu
account to contact sellers.
```
**Solution:** Connect your Venturu account through the OAuth flow in your MCP client.
```
Listing not found with ID "99999".
```
**Solution:** Use `search_businesses` to find valid listing IDs.
```
Listing has no seller or seller agent.
```
This is rare — most listings have a seller or broker associated.
## Typical Flow
1. Call `search_businesses` to find listings matching your criteria
2. Call `get_business` to view full details of a listing
3. Call `contact_seller` with the listing ID and your message
## Tool Annotations
| Annotation | Value |
| ----------------- | ------- |
| `readOnlyHint` | `false` |
| `destructiveHint` | `false` |
| `openWorldHint` | `true` |
This tool sends a message to an external party, which is why it's annotated as open-world.
# get_broker
Source: https://developers.venturu.com/mcp-server/tools/get-broker
Get full details for a single broker by their profile slug.
## get\_broker
Retrieve the full profile for a specific broker (agent) on Venturu. Use this after `search_brokers` to get detailed information about a broker the user is interested in.
This is a **read-only** tool. No authentication required.
## Parameters
| Parameter | Type | Required | Description |
| --------- | -------- | -------- | --------------------------------------------------------- |
| `slug` | `string` | **Yes** | The broker's profile slug (from `search_brokers` results) |
## Response
The tool returns detailed broker information including:
* Name, title, and company
* Bio and professional background
* Service areas and specializations
* Languages spoken
* Number of active listings
* Ratings and reviews
* Years of experience
* Professional licenses
Email and phone are **redacted** for privacy. Use `contact_broker` to send a message.
## Response Format
* **Text content** — Formatted summary of the broker's profile
* **Structured content** — Machine-readable JSON:
```json theme={null}
{
"broker": {
"slug": "jane-smith",
"name": "Jane Smith",
"title": "Senior Business Broker",
"company": "Smith & Associates",
"bio": "15+ years of experience in business brokerage...",
"serviceAreas": ["Miami, FL", "Fort Lauderdale, FL"],
"languages": ["English", "Spanish"],
"activeListings": 12,
"rating": 4.8,
"reviewCount": 23
}
}
```
## Examples
**Step 1:** Search for brokers → results include `slug: "jane-smith"`
**Step 2:** Call `get_broker` with `slug: "jane-smith"`
**Result:** Full broker profile with bio, service areas, and experience.
If the slug doesn't match a verified broker, the tool returns:
```
No verified broker found with slug "invalid-slug". Use search_brokers to find brokers.
```
# get_business
Source: https://developers.venturu.com/mcp-server/tools/get-business
Get full details for a single business listing by its slug.
## get\_business
Retrieve comprehensive details for a specific business listing on Venturu. Use this after `search_businesses` to get the full picture on a listing the user is interested in.
This is a **read-only** tool. No authentication required.
## Parameters
| Parameter | Type | Required | Description |
| --------- | -------- | -------- | ------------------------------------------------------------------ |
| `slug` | `string` | **Yes** | The business listing's URL slug (from `search_businesses` results) |
## Response
The tool returns detailed listing information including:
* Business name, description, and highlights
* Asking price, revenue, profit, and SDE
* Financial multiples (SDE multiple, revenue multiple)
* Location (city, state, country — exact address may be censored)
* Business type and industry category
* Establishment year and employee count
* Financing details (down payment, SBA qualification)
* Facility information (if applicable)
* Listing status and seller type
Some listing fields may be **censored** based on the seller's visibility settings. Titles and addresses may be partially hidden for confidential listings.
## Response Format
* **Text content** — Formatted summary with all available details
* **Structured content** — Machine-readable JSON:
```json theme={null}
{
"listing": {
"id": 1234,
"slug": "profitable-restaurant-miami",
"title": "Profitable Restaurant in Miami",
"description": "Well-established restaurant with loyal customer base...",
"askingPrice": 450000,
"revenue": 1200000,
"cashFlow": 250000,
"sde": 280000,
"location": "Miami, FL",
"businessType": "Restaurant",
"yearEstablished": 2015,
"employees": 12,
"status": "ACTIVE"
}
}
```
## Examples
**Step 1:** Search for businesses → results include `slug: "profitable-restaurant-miami"`
**Step 2:** Call `get_business` with `slug: "profitable-restaurant-miami"`
**Result:** Full listing details including financials, description, and facility info.
If the slug doesn't match any listing, the tool returns:
```
No business found with slug "invalid-slug". Use search_businesses to find listings.
```
# Tools Overview
Source: https://developers.venturu.com/mcp-server/tools/index
Complete reference for all 9 tools available on the Venturu MCP server.
## All Tools
The Venturu MCP server provides 9 tools for discovering, exploring, and contacting businesses and brokers. Tools are organized into functional categories.
### Search Tools
Find businesses and brokers using rich filters and natural-language location queries.
Search listings with 30+ filters — location, price, revenue, industry, and more.
Find verified brokers by location, language, name, and rating.
### Detail Tools
Retrieve full information about a specific business or broker.
Get comprehensive details for a business listing by its slug.
Get a broker's full profile by their slug.
### Lookup Tools
Discover available categories and languages to use as filter values in search tools.
All industry categories and business type IDs for filtering searches.
All available languages with IDs for filtering broker searches.
### Contact Tools
Send messages to brokers and sellers. These tools require authentication.
Send a message to a broker by their profile slug. Requires auth.
Send a message to a listing's seller by listing ID. Requires auth.
### Identity
Verify the currently authenticated user's identity. Requires auth.
## Tool Annotations
Each tool includes MCP annotations that inform AI clients about the tool's behavior:
| Annotation | Meaning |
| ------------------------ | ----------------------------------------------------------------- |
| `readOnlyHint: true` | The tool does not modify any data |
| `destructiveHint: false` | The tool will not delete or irreversibly change data |
| `openWorldHint: true` | The tool interacts with external systems (e.g., sending messages) |
| `openWorldHint: false` | The tool only reads from the Venturu database |
All search, detail, and lookup tools are annotated as **read-only** and **non-destructive**. Contact tools are annotated as **non-destructive** but **open-world** since they send messages.
## Common Patterns
### Search → Detail Flow
The typical usage pattern is to search first, then get details:
1. Call `list_business_categories` to discover category IDs (if filtering by industry)
2. Call `search_businesses` with your desired filters
3. Call `get_business` with a slug from the search results to see full details
### Pagination
Search tools use **cursor-based pagination** for businesses and **page-based pagination** for brokers:
* `search_businesses` returns a `nextCursor` value — pass it as `cursor` in the next call
* `search_brokers` accepts a `page` parameter (starting at 1)
Both tools default to 15 results per page (maximum 15).
# list_business_categories
Source: https://developers.venturu.com/mcp-server/tools/list-business-categories
Get all industry categories and business type IDs for filtering searches.
## list\_business\_categories
Returns all industry categories and their associated business types with IDs. Use the returned business type IDs as the `businessTypeIds` parameter in `search_businesses` to filter listings by industry.
This is a **read-only** tool. No authentication required. No input parameters needed.
## Parameters
This tool takes no parameters.
## Response
A structured list of all industry categories and their business types:
```
Industry categories and business types (use the IDs in search_businesses businessTypeIds):
Industry: Food & Beverage (category ID: 1)
- Restaurant (ID: 1, slug: restaurant)
- Bar & Nightclub (ID: 2, slug: bar-nightclub)
- Cafe & Coffee Shop (ID: 3, slug: cafe-coffee-shop)
- Food Truck (ID: 4, slug: food-truck)
Industry: Hospitality (category ID: 2)
- Hotel (ID: 10, slug: hotel)
- Motel (ID: 11, slug: motel)
- Bed & Breakfast (ID: 12, slug: bed-breakfast)
...
```
## Usage
This tool is typically called **once** at the start of a conversation when the user mentions a specific business type or industry. The returned IDs can then be used in subsequent `search_businesses` calls.
### Example Flow
1. User asks: "Find laundromats for sale in Texas"
2. AI calls `list_business_categories` to find the laundromat business type ID
3. AI calls `search_businesses` with `businessTypeIds: []` and `state: "Texas"`
The categories and business types are relatively stable. In a multi-turn conversation, you only need to call this tool once — reuse the IDs for subsequent searches.
# list_languages
Source: https://developers.venturu.com/mcp-server/tools/list-languages
Get all available languages with IDs for filtering broker searches.
## list\_languages
Returns all available languages with their IDs and codes. Use the returned language IDs as the `languageIds` parameter in `search_brokers` to find brokers who speak specific languages.
This is a **read-only** tool. No authentication required. No input parameters needed.
## Parameters
This tool takes no parameters.
## Response
A list of all languages:
```
Languages (use the IDs in search_brokers languageIds):
- Arabic (ID: 1, code: ar)
- Chinese (ID: 2, code: zh)
- English (ID: 3, code: en)
- French (ID: 4, code: fr)
- Portuguese (ID: 5, code: pt)
- Spanish (ID: 6, code: es)
...
```
## Usage
Call this tool when the user wants to find brokers who speak a specific language. Use the returned IDs in `search_brokers`.
### Example Flow
1. User asks: "Find French-speaking brokers in Miami"
2. AI calls `list_languages` to find the French language ID
3. AI calls `search_brokers` with `languageIds: []`, `city: "Miami"`, `countryCode: "US"`
Like `list_business_categories`, this data is relatively static. Call it once per conversation and reuse the IDs.
# search_brokers
Source: https://developers.venturu.com/mcp-server/tools/search-brokers
Search for verified business brokers on Venturu by location, language, and more.
## search\_brokers
Search for verified business brokers (agents) on Venturu. Filter by location, name, language, and sort by various criteria.
This is a **read-only** tool. No authentication required.
## Parameters
### Location
| Parameter | Type | Description |
| -------------- | -------- | ----------------------------------------------- |
| `zipCode` | `string` | Find brokers advertising in a specific ZIP code |
| `neighborhood` | `string` | Neighborhood name |
| `city` | `string` | City name |
| `county` | `string` | County name |
| `state` | `string` | State or region |
| `countryCode` | `string` | ISO country code (e.g., `"US"`, `"CA"`) |
For the best results, provide `countryCode` along with more specific location fields like `state` or `city`. The server uses geo-localized subdivision queries to match brokers to their service areas.
### Filters
| Parameter | Type | Description |
| ------------------ | ---------- | ---------------------------------------------------------- |
| `name` | `string` | Search brokers by name (case-insensitive partial match) |
| `languageIds` | `number[]` | Filter by languages spoken. Get IDs from `list_languages`. |
| `opportunityScore` | `object` | Filter by opportunity score range (`min` / `max`) |
### Sorting
| Parameter | Type | Default | Description |
| --------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------------- |
| `sort` | `string` | — | Sort by: `"recommended"`, `"ai_score"`, `"most_active"`, `"highest_rated"`, `"most_experienced"`, or `"most_reviews"` |
### Pagination
| Parameter | Type | Default | Description |
| --------- | --------- | ------- | ------------------------- |
| `limit` | `integer` | `15` | Results per page (max 15) |
| `page` | `integer` | `1` | Page number (1-indexed) |
## Response
The tool returns:
* **Text content** — A formatted summary of matching brokers
* **Structured content** — Machine-readable JSON:
```json theme={null}
{
"brokers": [
{
"slug": "jane-smith",
"name": "Jane Smith",
"title": "Senior Business Broker",
"company": "Smith & Associates",
"serviceAreas": ["Miami, FL", "Fort Lauderdale, FL"],
"languages": ["English", "Spanish"],
"activeListings": 12
}
],
"total": 34
}
```
Broker email addresses and phone numbers are **redacted** in search results for privacy. Use the `contact_broker` tool to send a message.
## Examples
**Prompt:** "Find business brokers in Los Angeles"
Parameters: `city: "Los Angeles"`, `state: "California"`, `countryCode: "US"`
**Prompt:** "Find brokers who speak Spanish in Florida"
First call `list_languages` to get the Spanish language ID, then pass it in `languageIds` along with `state: "Florida"`.
**Prompt:** "Show me the most experienced brokers in Texas"
Parameters: `state: "Texas"`, `countryCode: "US"`, `sort: "most_experienced"`
# search_businesses
Source: https://developers.venturu.com/mcp-server/tools/search-businesses
Search for businesses (listings) for sale on Venturu with 30+ filters.
## search\_businesses
Search for businesses for sale on Venturu. Supports natural-language location queries, financial filters, business type filtering, and pagination.
This is a **read-only** tool. No authentication required.
## Parameters
### Location
| Parameter | Type | Description |
| ---------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `location` | `string` | Natural-language location query (e.g., "Palm Beach, FL", "Miami", "33101"). Geocoded to a bounding box automatically. Ignored if `bbox` is provided. |
| `state` | `string` | State or region filter. |
| `bbox` | `object` | Explicit bounding box with `sw` (lat/lng) and `ne` (lat/lng). Overrides `location`. |
### Business Type
| Parameter | Type | Description |
| ----------------- | ---------- | ---------------------------------------------------------------------- |
| `businessTypeIds` | `number[]` | Filter by business type IDs. Get IDs from `list_business_categories`. |
| `statuses` | `string[]` | Filter by listing status (only publicly visible statuses are allowed). |
| `listedBy` | `string[]` | Filter by who listed: `"owner"` or `"broker"`. |
| `saleTypes` | `string[]` | Filter by sale type: `"ASSET_SALE"`, `"STOCK_SALE"`, or `"HYBRID"`. |
### Financial Filters
All financial filters use flat `min`/`max` parameters:
| Parameter | Type | Description |
| ------------------------------------------- | -------- | ------------------------------------- |
| `minPrice` / `maxPrice` | `number` | Asking price range |
| `minRevenue` / `maxRevenue` | `number` | Annual revenue range |
| `minProfit` / `maxProfit` | `number` | Annual profit range |
| `minSde` / `maxSde` | `number` | Seller's discretionary earnings range |
| `minSdeMultiple` / `maxSdeMultiple` | `number` | SDE multiple range |
| `minRevenueMultiple` / `maxRevenueMultiple` | `number` | Revenue multiple range |
| `minDownPayment` / `maxDownPayment` | `number` | Down payment range |
### Business Characteristics
| Parameter | Type | Description |
| --------------------------------------------- | --------- | ------------------------------------------- |
| `minEstablishmentAge` / `maxEstablishmentAge` | `number` | Business age in years |
| `minEmployeeCount` / `maxEmployeeCount` | `number` | Number of employees |
| `minOwnerWorkedHours` / `maxOwnerWorkedHours` | `number` | Owner's weekly working hours |
| `propertyIncluded` | `boolean` | Whether real estate is included in the sale |
| `buyerFinancingAvailable` | `boolean` | Whether seller financing is available |
| `sbaPrequalified` | `boolean` | Whether the business is SBA pre-qualified |
| `visaQualified` | `boolean` | Whether the business qualifies for E-2 visa |
### Scoring
| Parameter | Type | Description |
| --------------------------------------------- | --------- | ----------------------------------------------- |
| `minOpportunityScore` / `maxOpportunityScore` | `number` | Venturu opportunity score range |
| `includeMissingMultiples` | `boolean` | Include listings that don't have multiples data |
### Pagination & Sorting
| Parameter | Type | Default | Description |
| ------------------ | --------- | --------------- | ----------------------------------------------------------------- |
| `limit` | `integer` | `15` | Results per page (max 15) |
| `cursor` | `integer` | — | Cursor for pagination (from `nextCursor` in previous response) |
| `orderByProperty` | `string` | `"recommended"` | Sort by: `"recommended"`, `"relevance"`, `"price"`, or `"recent"` |
| `orderByDirection` | `string` | `"desc"` | Sort direction: `"asc"` or `"desc"` |
## Response
The tool returns:
* **Text content** — A formatted summary of matching listings with key details
* **Structured content** — Machine-readable JSON with full listing data:
```json theme={null}
{
"listings": [
{
"id": 1234,
"slug": "profitable-restaurant-miami",
"title": "Profitable Restaurant in Miami",
"askingPrice": 450000,
"revenue": 1200000,
"cashFlow": 250000,
"location": "Miami, FL",
"businessType": "Restaurant"
}
],
"total": 87,
"nextCursor": 1235
}
```
## Examples
**Prompt:** "Find businesses for sale in Palm Beach, Florida"
The tool geocodes "Palm Beach, Florida" into a bounding box and returns listings within that area.
**Prompt:** "Show me businesses under $200,000 with at least $500,000 in revenue"
Parameters: `maxPrice: 200000`, `minRevenue: 500000`
**Prompt:** "Find hotels for sale in California"
First call `list_business_categories` to get the hotel business type ID, then pass it in `businessTypeIds`.
**Prompt:** "Show me the next page of results"
Pass the `nextCursor` value from the previous response as `cursor`.
# who_am_i
Source: https://developers.venturu.com/mcp-server/tools/who-am-i
Verify the currently authenticated user identity.
## who\_am\_i
Returns the identity of the currently authenticated user. Use this to verify that the MCP connection is correctly authenticated.
This tool **requires authentication**. See [Authentication](/mcp/authentication) for details.
## Parameters
This tool takes no parameters.
## Response
When authenticated:
```
Authenticated as Venturu user: Jane Smith (ID: abc123, email: jane@example.com).
You can use tools like contact_broker on their behalf.
```
When not authenticated:
```
Not authenticated. This tool requires a valid Venturu session or
MCP access token.
```
## Use Cases
Confirm that OAuth authentication completed successfully before attempting to use contact tools.
Used by voice agents (e.g., ElevenLabs) to verify that dynamic auth variables are correctly configured.
## Tool Annotations
| Annotation | Value |
| ----------------- | ------- |
| `readOnlyHint` | `true` |
| `destructiveHint` | `false` |
| `openWorldHint` | `false` |