API Reference

Complete endpoint documentation for Miata Maestro

Base Information

Base URL: http://localhost:3000
Authentication: Session-based (cookies)
Content Types: application/json, application/x-www-form-urlencoded

Authentication

POST
/login
Authenticate with Facebook credentials and create session

Request Body

Content-Type: application/x-www-form-urlencoded

email=user@example.com&password=userpassword

Parameters

Parameter
Type
Description
email
string
Facebook email address
password
string
Facebook password

Response

HTTP/1.1 302 Found
Location: /search
Set-Cookie: connect.sid=s%3A...; Path=/; HttpOnly
POST
/logout
Destroy session and logout

Response

HTTP/1.1 302 Found
Location: /

Page Endpoints

GET
/
Login page (redirects to /search if authenticated)
GET
/search
Search configuration page

Authentication

Requires active session. Redirects to / if not logged in.

GET
/test
System status and health check page

Scraping

POST
/scrape
Initialize scraping session with search parameters

Request Body

Content-Type: application/x-www-form-urlencoded

zip=90210&radius=50&yearMin=1990&yearMax=1997&maxMileage=100000&limit=20&provider=ollama&ollamaPort=11434

Parameters

Parameter
Type
Description
zip
string
ZIP code for search center
radius
number
Search radius in miles (1-500)
yearMin
number
Minimum year (1989-1997)
yearMax
number
Maximum year (1989-1997)
maxMileage
number
Maximum mileage threshold
maxPrice
number
Optional maximum price limit
limit
number
Number of listings to process (1-100)
headless
boolean
Browser visibility (true/false)
provider
string
AI provider ("ollama" or "gpt-oss")
ollamaPort
number
Ollama service port (default: 11434)

Response

HTTP/1.1 200 OK
Content-Type: text/html

<!-- Search progress page with loading animation -->
GET
/scrape-results
Execute scraping and display results

Query Parameters

Parameter
Type
Description
debug
boolean
Enable debug mode (processes only 3 listings)

Response

HTTP/1.1 200 OK
Content-Type: text/html

<!-- Results page with listing cards -->

Real-time Updates

GET
/progress
Server-Sent Events stream for real-time progress updates

Headers

Accept: text/event-stream
Cache-Control: no-cache

Response

HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

data: {"step":"initializing","details":"Setting up scraping session...","timestamp":"2024-01-15T10:30:00.000Z"}

data: {"step":"browser_start","details":"Starting browser...","timestamp":"2024-01-15T10:30:01.000Z"}

data: {"step":"logging_in","details":"Navigating to Facebook login...","timestamp":"2024-01-15T10:30:02.000Z"}

Progress Steps

initializing: Setting up scraping session
browser_start: Starting Puppeteer browser
logging_in: Facebook authentication
navigating: Navigating to Marketplace
searching: Finding listings
extracting: Processing individual listings
complete: Scraping finished

AI Evaluation

POST
/evaluate-listing
Get AI analysis for a specific listing

Request Body

Content-Type: application/json

{
  "listingId": "listing_1234567890_0"
}

Response

HTTP/1.1 200 OK
Content-Type: application/json

{
  "evaluation": "<strong>Pros:</strong>\n• Clean title\n• Low mileage for year\n• Manual transmission\n\n<strong>Concerns:</strong>\n• Some rust visible in photos\n• No maintenance records provided\n\n<strong>Accurate Price:</strong> $4,500\n\n<strong>Lowball:</strong> $3,800"
}

Error Response

HTTP/1.1 404 Not Found
Content-Type: application/json

{
  "error": "Listing listing_1234567890_0 not found"
}
POST
/generate-lowball
Generate casual lowball message for negotiation

Request Body

Content-Type: application/json

{
  "listingId": "listing_1234567890_0"
}

Response

HTTP/1.1 200 OK
Content-Type: application/json

{
  "message": "hey! saw your miata listing, looks pretty good but noticed some rust spots and the paint could use work... would you consider $3800? can pick up this weekend 🚗"
}

Data Models

Listing Object

{
  "id": "listing_1705315200000_0",
  "title": "1995 Mazda Miata - Clean Title",
  "price": 5000,
  "year": 1995,
  "mileage": 80000,
  "transmission": "Manual",
  "description": "Well-maintained NA Miata with clean title. Recent timing belt service...",
  "url": "https://www.facebook.com/marketplace/item/1234567890",
  "images": [
    "https://scontent.xx.fbcdn.net/v/t45.5328-4/...",
    "https://scontent.xx.fbcdn.net/v/t45.5328-4/..."
  ],
  "rawText": "",
  "lowballPrice": 3800
}

Field Descriptions

id: Unique identifier generated from timestamp and index
title: Listing title from Facebook Marketplace
price: Asking price in USD (integer)
year: Vehicle year (1989-1997 for NA Miata)
mileage: Odometer reading in miles (integer)
transmission: "Manual", "Automatic", or null
description: Listing description (truncated to 500 chars)
url: Direct link to Facebook Marketplace listing
images: Array of image URLs (up to 2 for performance)
lowballPrice: AI-calculated lowball offer (added after evaluation)

Progress Update Object

{
  "step": "extracting",
  "details": "Processing listing 5/20...",
  "timestamp": "2024-01-15T10:30:00.000Z"
}

Error Codes

401 Unauthorized
Session required but not authenticated
Login via POST /login
404 Not Found
Listing ID not found in session
Ensure listing was scraped in current session
400 Bad Request
Missing or invalid parameters
Check parameter requirements
500 Internal Server Error
Scraping, AI, or browser automation failed
Check console logs, enable debug mode

Rate Limits & Best Practices

⚡ Performance Guidelines

Concurrent Sessions: Limit to 1 scraping session at a time
Request Frequency: Wait for previous scrape to complete
Result Limits: Start with 10-20 listings for testing
AI Evaluations: Process individually, not in batch

🔒 Security Considerations

Session Security: Sessions expire after 24 hours
Credential Storage: Only in server memory, never persisted
CORS: API restricted to same-origin requests
Facebook TOS: Respect platform terms of service