PixSpeed API
Analyze Airbnb and Booking.com listings programmatically. Submit URLs, get structured pricing, occupancy, and market data.
https://app.pixspeed.com/api/v1/
Quick Start
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).
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.
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
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.
| Action | Credit 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.
Endpoints
/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"
}
| Field | Type | Required | Description |
|---|---|---|---|
urls | array | Yes | 1-10 Airbnb or Booking.com URLs |
month | int | No | Target month (1-12). Defaults to current month. |
year | int | No | Target year (2024-2030). Defaults to current year. |
currency | string | No | USD (default) or PEN |
webhook_url | string | No | URL 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/"
}
/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"
}
| Detail | Value |
|---|---|
| Method | POST |
| Content-Type | application/json |
| User-Agent | PixSpeed-Webhook/1.0 |
| Timeout | 10 seconds |
| Retries | 3 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.
| Plan | Rate Limit | API Access |
|---|---|---|
| Free | — | No access |
| Pro | — | No access |
| Portfolio | 100 requests / hour | Enabled |
| Enterprise | 500 requests / hour | Enabled |
Need a higher limit? Contact hello@pixspeed.com for a custom rate limit on your API key.
Error Reference
| HTTP Code | Meaning | Common 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