Documentation
Learn how to integrate APIVine APIs into your applications. All our APIs are available through RapidAPI.
Quick Start
Get up and running in minutes
Code Examples
Sample code in multiple languages
API Reference
Detailed endpoint documentation
Response Schemas
Understand response structures
Getting Started
1. Sign up for RapidAPI
All APIVine APIs are hosted on RapidAPI. Create a free account to get started.
Sign up for RapidAPI2. Subscribe to an API
Browse our APIs and subscribe to the one you need. All APIs include a free tier for testing.
Browse APIs3. Get your API Key
Once subscribed, you'll receive an API key that you'll use to authenticate requests. Find your key in the RapidAPI dashboard.
Authentication
All API requests require authentication via RapidAPI. Include these headers with every request:
// Required headers for all requests
{
"X-RapidAPI-Key": "your-api-key-here",
"X-RapidAPI-Host": "api-host-here"
}Making Requests
All endpoints follow the same pattern — pass your RapidAPI key in the headers and your query as URL parameters. Here are examples using the /lookup endpoint to fetch a full property report:
// JavaScript — look up a property by BBL
const response = await fetch(
'https://new-york-city-violation-alerts.p.rapidapi.com/lookup?bbl=1004777501',
{
headers: {
'X-RapidAPI-Key': 'your-api-key',
'X-RapidAPI-Host': 'new-york-city-violation-alerts.p.rapidapi.com'
}
}
);
const data = await response.json();
// data.property — PLUTO fields (address, borough, year_built, …)
// data.violations / data.complaints / data.permits — arrays
// data.summary — { violation_count, complaint_count, permit_count }# Python — look up a property by address
import requests
response = requests.get(
'https://new-york-city-violation-alerts.p.rapidapi.com/lookup',
params={'address': '350 Fifth Ave'},
headers={
'X-RapidAPI-Key': 'your-api-key',
'X-RapidAPI-Host': 'new-york-city-violation-alerts.p.rapidapi.com'
}
)
data = response.json()
print(data['property']['bbl'])
print(data['summary'])Available endpoints
GET /lookup— Full report by address, BBL, or BINGET /violations— DOB + OATH/ECB violations by BINGET /complaints— DOB complaints by BINGET /permits— DOB permits by BINGET /search— Search cached properties by address, BBL, or BINGET /changes— Poll for new records since a given timestampGET /landlord— All properties owned by a name or LLCGET /timeline— Violations, complaints, and permits as a single chronological feedGET /neighborhood— Aggregate stats for a zip code
Response Format
All API responses are returned in JSON format with a consistent structure:
// Successful response
{
"status": "success",
"count": 10,
"data": [...],
"pagination": {
"page": 1,
"limit": 50,
"total": 100
}
}
// Error response
{
"status": "error",
"code": "INVALID_PARAMETER",
"message": "The 'address' parameter is required."
}Error Handling
The API uses standard HTTP status codes to indicate success or failure:
| Status Code | Meaning | Description |
|---|---|---|
200 | OK | Request successful |
400 | Bad Request | Invalid request parameters |
401 | Unauthorized | Invalid or missing API key |
403 | Forbidden | Not subscribed to this API |
429 | Too Many Requests | Rate limit exceeded |
500 | Server Error | Internal server error |
Rate Limits
Rate limits vary by subscription plan. Check the specific API page for details on limits. When you exceed the rate limit, you'll receive a 429 status code.
Rate Limit Headers
Each response includes headers indicating your current rate limit status:
X-RateLimit-Limit- Maximum requests allowedX-RateLimit-Remaining- Requests remainingX-RateLimit-Reset- Time when the limit resets
Search Properties
Use GET /search to find properties already cached by a previous /lookup call. Useful for autocomplete, portfolio lookups, and building a property picker in your UI.
Parameters
qrequired — Matches against address, BBL, or BINborough— Filter by borough:MANHATTAN,BROOKLYN,QUEENS,BRONX,STATEN ISLANDlimit— Max results (1–50, default 10)
// JavaScript
const response = await fetch(
'https://new-york-city-violation-alerts.p.rapidapi.com/search?q=Empire+State&borough=MANHATTAN&limit=5',
{
headers: {
'X-RapidAPI-Key': 'your-api-key',
'X-RapidAPI-Host': 'new-york-city-violation-alerts.p.rapidapi.com'
}
}
)
const data = await response.json()
// data.properties — array of matching property objects
// data.count — total matched# Python
import requests
r = requests.get(
'https://new-york-city-violation-alerts.p.rapidapi.com/search',
params={'q': 'Empire State', 'borough': 'MANHATTAN', 'limit': 5},
headers={
'X-RapidAPI-Key': 'your-api-key',
'X-RapidAPI-Host': 'new-york-city-violation-alerts.p.rapidapi.com'
}
)
data = r.json()
for prop in data['properties']:
print(prop['bbl'], prop['address'])Note
/search only returns properties already in the cache. If a property is not found, call /lookup first to fetch and cache it, then search again.
Polling for Changes
Instead of re-fetching a full property report on every request, use the /changes endpoint to retrieve only what is new since your last poll. Store the timestamp of your last successful request and pass it as the since parameter on the next call.
How it works
- Do an initial full lookup with
GET /lookup?bbl=...and recordDate.now(). - On a schedule (e.g. every hour), call
GET /changes?bbl=...&since=<last_poll>. - If
violation_count,complaint_count, orpermit_countis > 0, process the new records. - Update your stored timestamp to the current time.
// JavaScript — poll for new violations every hour
const BBL = '1004777501'
let lastPoll = new Date(Date.now() - 3600_000).toISOString() // 1 hour ago
async function pollChanges() {
const url = new URL('https://new-york-city-violation-alerts.p.rapidapi.com/changes')
url.searchParams.set('bbl', BBL)
url.searchParams.set('since', lastPoll)
const res = await fetch(url, {
headers: {
'X-RapidAPI-Key': 'your-api-key',
'X-RapidAPI-Host': 'new-york-city-violation-alerts.p.rapidapi.com'
}
})
const data = await res.json()
if (data.violation_count > 0 || data.complaint_count > 0) {
console.log(`${data.violation_count} new violations, ${data.complaint_count} new complaints`)
// handle data.violations, data.complaints, data.permits ...
}
lastPoll = new Date().toISOString()
}
setInterval(pollChanges, 60 * 60 * 1000) // every hour# Python — poll for new violations
import requests
from datetime import datetime, timedelta, timezone
BBL = '1004777501'
last_poll = (datetime.now(timezone.utc) - timedelta(hours=1)).isoformat()
def poll_changes():
global last_poll
response = requests.get(
'https://new-york-city-violation-alerts.p.rapidapi.com/changes',
params={'bbl': BBL, 'since': last_poll},
headers={
'X-RapidAPI-Key': 'your-api-key',
'X-RapidAPI-Host': 'new-york-city-violation-alerts.p.rapidapi.com'
}
)
data = response.json()
if data['violation_count'] > 0 or data['complaint_count'] > 0:
print(f"{data['violation_count']} new violations")
# process data['violations'], data['complaints'], data['permits']
last_poll = datetime.now(timezone.utc).isoformat()Response structure
{
"bbl": "1004777501",
"since": "2025-01-01T00:00:00Z",
"violations": [ /* new ViolationResponse objects */ ],
"complaints": [ /* new ComplaintResponse objects */ ],
"permits": [ /* new PermitResponse objects */ ],
"violation_count": 1,
"complaint_count": 0,
"permit_count": 0
}Landlord Lookup
Use GET /landlord to find every NYC property owned by a given person or LLC. Searches the PLUTO dataset by owner name (partial, case-insensitive match). New properties found upstream are cached automatically.
Parameters
ownerrequired — Owner name or LLC (partial match, e.g.TRUMPorBLACKSTONE)limit— Max properties to return (1–200, default 50)
// JavaScript — find all properties owned by an LLC
const response = await fetch(
'https://new-york-city-violation-alerts.p.rapidapi.com/landlord?owner=STUY+TOWN&limit=100',
{
headers: {
'X-RapidAPI-Key': 'your-api-key',
'X-RapidAPI-Host': 'new-york-city-violation-alerts.p.rapidapi.com'
}
}
)
const data = await response.json()
// data.owner_query — normalized search term
// data.count — number of matching properties
// data.properties — array of property objects with PLUTO fields# Python — portfolio lookup for a landlord
import requests
r = requests.get(
'https://new-york-city-violation-alerts.p.rapidapi.com/landlord',
params={'owner': 'BLACKSTONE', 'limit': 200},
headers={
'X-RapidAPI-Key': 'your-api-key',
'X-RapidAPI-Host': 'new-york-city-violation-alerts.p.rapidapi.com'
}
)
data = r.json()
for prop in data['properties']:
print(prop['bbl'], prop['address'], prop['assessed_total_value'])Property Timeline
Use GET /timeline to get violations, complaints, and permits for a BBL merged into a single event feed sorted newest-first. Each event has a type field (violation, complaint, or permit) so you can filter or color-code in your UI.
Parameters
bblrequired — Borough-Block-Lot identifier (e.g.1000477501)
// JavaScript — render a property history feed
const response = await fetch(
'https://new-york-city-violation-alerts.p.rapidapi.com/timeline?bbl=1000477501',
{
headers: {
'X-RapidAPI-Key': 'your-api-key',
'X-RapidAPI-Host': 'new-york-city-violation-alerts.p.rapidapi.com'
}
}
)
const { timeline, event_count } = await response.json()
console.log(`${event_count} events`)
for (const event of timeline) {
// event.type — 'violation' | 'complaint' | 'permit'
// event.date — ISO date string (or null)
// event.title — short label (violation_type, complaint_type, permit_type)
// event.description — longer description
// event.status — current status
console.log(event.date, event.type, event.title)
}# Python — due diligence timeline for a BBL
import requests
r = requests.get(
'https://new-york-city-violation-alerts.p.rapidapi.com/timeline',
params={'bbl': '1000477501'},
headers={
'X-RapidAPI-Key': 'your-api-key',
'X-RapidAPI-Host': 'new-york-city-violation-alerts.p.rapidapi.com'
}
)
data = r.json()
for event in data['timeline']:
print(f"[{event['type']}] {event['date']} — {event['title']}")Neighborhood Stats
Use GET /neighborhood to get aggregate stats for an NYC zip code. The pluto_summary field (total properties, units, average assessed value, average year built) comes directly from NYC Open Data and covers all properties in the zip. Violation, complaint, and permit rates are computed from properties already cached locally — call /lookup on individual properties first to warm the cache.
Parameters
zip_coderequired — NYC zip code (e.g.10001)
// JavaScript — site selection analytics for a zip code
const response = await fetch(
'https://new-york-city-violation-alerts.p.rapidapi.com/neighborhood?zip_code=10001',
{
headers: {
'X-RapidAPI-Key': 'your-api-key',
'X-RapidAPI-Host': 'new-york-city-violation-alerts.p.rapidapi.com'
}
}
)
const data = await response.json()
// data.pluto_summary.total_properties — all properties in zip (from PLUTO)
// data.pluto_summary.avg_assessed_total_value
// data.violation_rate — avg violations per cached property
// data.top_violation_types — [{ type, count }, ...]# Python — compare neighborhoods by violation rate
import requests
HOST = 'new-york-city-violation-alerts.p.rapidapi.com'
HEADERS = {
'X-RapidAPI-Key': 'your-api-key',
'X-RapidAPI-Host': HOST
}
for zip_code in ['10001', '10002', '10003']:
r = requests.get(
f'https://{HOST}/neighborhood',
params={'zip_code': zip_code},
headers=HEADERS
)
d = r.json()
print(f"{zip_code}: {d['violation_rate']} violations/property, "
f"{d['pluto_summary'].get('total_properties')} total properties")Property Owner Lookup
The National Property Owner Lookup API is a separate API with its own RapidAPI subscription and host (national-property-owner-lookup.p.rapidapi.com). It resolves property ownership from county assessor open data across multiple US counties. Use GET /owner/lookup to find who owns an address, and GET /owner/portfolio to find every property a person or LLC owns within a county.
Supported counties
Coverage currently spans New York City, Philadelphia, Washington DC, and Boston, with more counties added over time. Call GET /owner/counties for the live list — its slug values are what you pass as the county parameter. Every county returns the identical record shape.
Parameters
/owner/lookup
addressrequired — Street address to look up (matched as a case-insensitive substring)countyrequired — County slug from/owner/countieslimit— Max records to return (1–100, default 25)
/owner/portfolio
namerequired — Owner name or LLC to search (partial match)countyrequired — County slug from/owner/countieslimit— Max properties to return (1–200, default 50)
// JavaScript — who owns this property?
const response = await fetch(
'https://national-property-owner-lookup.p.rapidapi.com/owner/lookup?address=350+5+Avenue&county=nyc',
{
headers: {
'X-RapidAPI-Key': 'your-api-key',
'X-RapidAPI-Host': 'national-property-owner-lookup.p.rapidapi.com'
}
}
)
const data = await response.json()
// data.results — array of normalized owner records
// each record: owner_name, address, parcel_id, assessed_value,
// year_built, owner_mailing_address, owner_occupied# Python — skip-trace every property an LLC owns
import requests
HOST = 'national-property-owner-lookup.p.rapidapi.com'
r = requests.get(
f'https://{HOST}/owner/portfolio',
params={'name': 'CENTRAL CAPITAL GROUP', 'county': 'philadelphia', 'limit': 200},
headers={
'X-RapidAPI-Key': 'your-api-key',
'X-RapidAPI-Host': HOST
}
)
data = r.json()
for prop in data['results']:
print(prop['address'], '—', prop['owner_mailing_address'])Note
County assessor portals deliberately omit owner names for many jurisdictions. This API only covers counties that publish owner data openly. Fields a county does not publish — such as owner_mailing_address or owner_occupied — are returned as null rather than omitted, so the response shape stays stable across counties.
Business Entity Lookup
The US Business Entity Lookup API is a separate API with its own RapidAPI subscription and host (us-business-entity-lookup.p.rapidapi.com). It unifies state Secretary of State corporation and LLC registries behind one interface. Use GET /entity/search to find entities by name, and GET /entity/lookup to resolve a single entity by its state registry ID.
Supported states
Coverage currently spans New York, with more states added over time. Call GET /entity/states for the live list — its slug values are what you pass as the state parameter. Every state returns the identical record shape.
Parameters
/entity/search
namerequired — Entity name to search (matched as a case-insensitive substring)staterequired — State slug from/entity/stateslimit— Max entities to return (1–100, default 25)
/entity/lookup
registry_idrequired — State registry ID / file number (e.g. NY DOS ID)staterequired — State slug from/entity/states
// JavaScript — find an LLC by name
const response = await fetch(
'https://us-business-entity-lookup.p.rapidapi.com/entity/search?name=EMPIRE+STATE+REALTY&state=ny',
{
headers: {
'X-RapidAPI-Key': 'your-api-key',
'X-RapidAPI-Host': 'us-business-entity-lookup.p.rapidapi.com'
}
}
)
const data = await response.json()
// data.results — array of normalized entity records
// each record: entity_name, entity_type, status, formation_date,
// jurisdiction, county, registered_agent, registered_agent_address# Python — resolve a single entity by its registry ID
import requests
HOST = 'us-business-entity-lookup.p.rapidapi.com'
r = requests.get(
f'https://{HOST}/entity/lookup',
params={'registry_id': '4424185', 'state': 'ny'},
headers={
'X-RapidAPI-Key': 'your-api-key',
'X-RapidAPI-Host': HOST
}
)
entity = r.json()
print(entity['entity_name'], '—', entity['status'])
print('Registered agent:', entity['registered_agent_address'])Note
States publish business-registry data at very different depths. New York's open data covers active corporations and LLCs and exposes the DOS process agent — the state's service-of-process contact, the open-data equivalent of a registered agent — but not officers/directors. Fields a state does not publish, such as officers, are returned as null rather than omitted, so the response shape stays stable across states.
Website Screenshot
Use GET /screenshot to capture a full-page screenshot of any public website. The page is rendered in a headless Chromium browser and the result is returned as a base64-encoded image — ready to pipe directly into a vision model or save to disk.
Parameters
urlrequired — Full URL to screenshot (must start withhttp://orhttps://)full_page— Capture the entire page height, not just the visible viewport (defaulttrue)format— Image format:pngorjpeg(defaultpng)width— Viewport width in pixels, 320–2560 (default1280)
// JavaScript — screenshot a page and pass it to a vision model
const response = await fetch(
'https://website-screenshot.p.rapidapi.com/screenshot?url=https%3A%2F%2Fexample.com&full_page=true',
{
headers: {
'X-RapidAPI-Key': 'your-api-key',
'X-RapidAPI-Host': 'website-screenshot.p.rapidapi.com'
}
}
)
const data = await response.json()
// data.title — page <title> text
// data.screenshot — base64-encoded PNG/JPEG string
// data.format — 'png' or 'jpeg'
// data.url — the URL that was screenshotted
// Decode and save to disk (Node.js)
const fs = require('fs')
fs.writeFileSync('screenshot.png', Buffer.from(data.screenshot, 'base64'))# Python — screenshot a page and feed it to GPT-4o or Claude
import requests, base64, openai
HOST = 'website-screenshot.p.rapidapi.com'
r = requests.get(
f'https://{HOST}/screenshot',
params={'url': 'https://example.com', 'full_page': 'true', 'width': '1280'},
headers={
'X-RapidAPI-Key': 'your-api-key',
'X-RapidAPI-Host': HOST
}
)
data = r.json()
# Save to disk
with open('screenshot.png', 'wb') as f:
f.write(base64.b64decode(data['screenshot']))
# Or pass straight to a vision model
client = openai.OpenAI()
reply = client.chat.completions.create(
model='gpt-4o',
messages=[{
'role': 'user',
'content': [
{'type': 'text', 'text': 'Describe the design and layout of this page.'},
{'type': 'image_url', 'image_url': {
'url': f"data:image/{data['format']};base64,{data['screenshot']}"
}}
]
}]
)
print(reply.choices[0].message.content)Response structure
{
"url": "https://example.com",
"title": "Example Domain",
"format": "png",
"screenshot": "iVBORw0KGgoAAAANSUhEUgAA..." // base64-encoded image
}Notes
- The browser waits for network idle before capturing, so JavaScript-rendered content (SPAs, lazy images) is fully visible.
- Timeout is 30 seconds. Pages that never reach network idle (e.g. infinite WebSocket streams) will return a 422 error.
- Only public URLs are supported. Private IPs and
localhostare blocked. - Use
format=jpegfor smaller payloads on photo-heavy pages; useformat=pngfor crisp text and UI screenshots.