PixSpeed API

Analyze Airbnb and Booking.com listings programmatically. Submit URLs, get structured pricing, occupancy, and market data.

REST JSON HTTPS v1
Base URL: https://app.pixspeed.com/api/v1/

Quick Start

1
Get your API key

Create a key from the Developer Portal in your dashboard. Keys use the pxs_ prefix and are shown only once — store it securely. Each API call consumes credits (1 credit per URL analyzed).

2
Submit a batch

POST /api/v1/analyze/ with 1-10 Airbnb or Booking.com URLs. Batches of 1-3 URLs return results immediately; 4-10 process asynchronously.

3
Get results

For sync batches, results are in the response. For async batches, poll GET /api/v1/analyze/{batch_id}/ or configure a webhook.

Authentication

All API requests require an API key sent in the X-API-Key header:

X-API-Key: pxs_your_api_key_here
Your API key is shown only once when created. Store it in a secure location (e.g., environment variable). If lost, revoke the old key and create a new one.

API access requires a Portfolio or Enterprise plan. Requests with keys from other plans receive a 403 response.

Credits

The PixSpeed API uses a credit-based billing model. Each URL submitted for analysis costs 1 credit. GET requests (polling for batch status) are free.

ActionCredit Cost
Submit URL for analysis (POST /analyze/)1 credit per URL
Poll batch status (GET /analyze/{id}/)Free
How it works
  • Credits are deducted atomically when you submit a batch. If you submit 5 URLs, 5 credits are consumed.
  • If you don't have enough credits, the API returns 402 Payment Required.
  • Monitor your balance and purchase credits from the Developer Portal.
Manage your credits in the Developer Portal — create API keys, check balances, and view transaction history.

Endpoints

POST /api/v1/analyze/ Submit batch

Submit 1-10 Airbnb or Booking.com URLs for analysis. Batches with 1-3 URLs are processed synchronously (results in the 201 response). Batches with 4-10 URLs are queued and return a 202 with a poll URL.

Request body
{
  "urls": [
    "https://www.airbnb.com/rooms/12345678",
    "https://www.airbnb.com/rooms/87654321"
  ],
  "month": 4,
  "year": 2026,
  "currency": "USD",
  "webhook_url": "https://your-server.com/webhook"
}
FieldTypeRequiredDescription
urlsarrayYes1-10 Airbnb or Booking.com URLs
monthintNoTarget month (1-12). Defaults to current month.
yearintNoTarget year (2024-2030). Defaults to current year.
currencystringNoUSD (default) or PEN
webhook_urlstringNoURL to receive a POST when the batch completes
Response — Sync (201)
{
  "batch_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "completed",
  "total_urls": 2,
  "processed_count": 2,
  "failed_count": 0,
  "progress_pct": 100,
  "created_at": "2026-03-02T14:30:00Z",
  "completed_at": "2026-03-02T14:30:05Z",
  "results": [
    {
      "url": "https://www.airbnb.com/rooms/12345678",
      "clean_url": "https://www.airbnb.com/rooms/12345678",
      "platform": "airbnb",
      "status": "completed",
      "result_data": {
        "title": "Stylish Loft in Barranco",
        "nightly_rate": 85.00,
        "currency": "USD",
        "rating": 4.92,
        "reviews_count": 128,
        "capacity": 4,
        "bedrooms": 1,
        "bathrooms": 1,
        "availability": { "... rate grid ..." : "..." }
      },
      "error_message": "",
      "processed_at": "2026-03-02T14:30:04Z"
    }
  ]
}
Response — Async (202)
{
  "batch_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "queued",
  "total_urls": 8,
  "poll_url": "https://app.pixspeed.com/api/v1/analyze/a1b2c3d4-e5f6-7890-abcd-ef1234567890/"
}
GET /api/v1/analyze/{batch_id}/ Poll status

Check the status of an async batch. Poll until status is "completed" or "failed". Results are included once available.

Response (200)
{
  "batch_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "processing",
  "total_urls": 8,
  "processed_count": 5,
  "failed_count": 0,
  "progress_pct": 62,
  "created_at": "2026-03-02T14:30:00Z",
  "completed_at": null,
  "results": [
    { "...": "results for processed URLs appear here" }
  ]
}

Code Samples

Submit a batch
curl -X POST https://app.pixspeed.com/api/v1/analyze/ \
  -H "Content-Type: application/json" \
  -H "X-API-Key: pxs_your_api_key" \
  -d '{
    "urls": ["https://www.airbnb.com/rooms/12345678"],
    "currency": "USD"
  }'
Poll for results
curl https://app.pixspeed.com/api/v1/analyze/BATCH_UUID/ \
  -H "X-API-Key: pxs_your_api_key"
import time
import requests

API_KEY = "pxs_your_api_key"
BASE_URL = "https://app.pixspeed.com/api/v1"
HEADERS = {
    "Content-Type": "application/json",
    "X-API-Key": API_KEY,
}

# 1. Submit batch
resp = requests.post(f"{BASE_URL}/analyze/", headers=HEADERS, json={
    "urls": [
        "https://www.airbnb.com/rooms/12345678",
        "https://www.airbnb.com/rooms/87654321",
    ],
    "currency": "USD",
})
data = resp.json()
print(f"Batch {data['batch_id']} — status: {data['status']}")

# 2. If async (202), poll until completed
if resp.status_code == 202:
    poll_url = data["poll_url"]
    while True:
        time.sleep(5)
        r = requests.get(poll_url, headers=HEADERS)
        batch = r.json()
        print(f"  Progress: {batch['progress_pct']}%")
        if batch["status"] in ("completed", "failed"):
            break

    # 3. Print results
    for result in batch["results"]:
        print(f"  {result['url']} → {result['status']}")
        if result["result_data"]:
            print(f"    Rate: ${result['result_data'].get('nightly_rate')}")
const API_KEY = "pxs_your_api_key";
const BASE_URL = "https://app.pixspeed.com/api/v1";
const headers = {
  "Content-Type": "application/json",
  "X-API-Key": API_KEY,
};

async function analyzeListing(urls) {
  // 1. Submit batch
  const resp = await fetch(`${BASE_URL}/analyze/`, {
    method: "POST",
    headers,
    body: JSON.stringify({ urls, currency: "USD" }),
  });
  let data = await resp.json();
  console.log(`Batch ${data.batch_id} — status: ${data.status}`);

  // 2. If async (202), poll until completed
  if (resp.status === 202) {
    const pollUrl = data.poll_url;
    while (true) {
      await new Promise((r) => setTimeout(r, 5000));
      const r = await fetch(pollUrl, { headers });
      data = await r.json();
      console.log(`  Progress: ${data.progress_pct}%`);
      if (data.status === "completed" || data.status === "failed") break;
    }
  }

  // 3. Print results
  for (const result of data.results) {
    console.log(`${result.url} → ${result.status}`);
    if (result.result_data) {
      console.log(`  Rate: $${result.result_data.nightly_rate}`);
    }
  }
}

analyzeListing(["https://www.airbnb.com/rooms/12345678"]);

Webhooks

Instead of polling, you can provide a webhook_url when submitting a batch. When the batch completes, PixSpeed sends a POST request to your URL with the following payload:

{
  "event": "batch.completed",
  "batch_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "completed",
  "total_urls": 8,
  "processed_count": 8,
  "failed_count": 0,
  "completed_at": "2026-03-02T14:35:00Z"
}
DetailValue
MethodPOST
Content-Typeapplication/json
User-AgentPixSpeed-Webhook/1.0
Timeout10 seconds
Retries3 attempts with exponential backoff (2s, 4s, 8s)

Your endpoint should return a 2xx status code to acknowledge receipt. After 3 failed attempts, the webhook is abandoned (you can still poll for results).

Rate Limits

Rate limits are applied per API key. When exceeded, the API returns 429 Too Many Requests with a Retry-After header.

PlanRate LimitAPI Access
FreeNo access
ProNo access
Portfolio100 requests / hourEnabled
Enterprise500 requests / hourEnabled

Need a higher limit? Contact hello@pixspeed.com for a custom rate limit on your API key.

Error Reference

HTTP CodeMeaningCommon Cause
400 Bad Request Invalid URL format, missing urls field, or unsupported domain
401 Unauthorized Missing or invalid X-API-Key header
402 Payment Required Insufficient credits — purchase more from the Developer Portal
403 Forbidden API key is revoked, client inactive, or plan does not include API access
404 Not Found Batch UUID does not exist or belongs to a different client
429 Too Many Requests Rate limit exceeded — wait and retry after the Retry-After period
Error response format
{
  "detail": "Invalid API key."
}

Validation errors (400) return field-level details:

{
  "urls": [
    "Only airbnb.com and booking.com URLs are accepted. Got: https://example.com"
  ]
}
Interactive API Explorer

Try endpoints directly in your browser with the Swagger UI.

Open Swagger UI