Integrate real-time marketplace intelligence directly into your applications. Manage alerts, stream listing matches, trigger Stripe checkout flows, and more — all through a clean, consistent REST interface.
https://api.alerthound.io/api/v1From zero to your first alert match in under 5 minutes.
Register an account
POST /auth/register with your email and password. You'll get back a JWT token — keep it.
Create an alert
POST /alerts with keywords, a vertical (e.g. "lothound"), and optional price/location filters.
Check your matches
GET /alerts/:id/matches returns the listings that matched your criteria, paginated by cursor.
Configure notifications
PUT /notifications/preferences to enable email, SMS, push, or webhook delivery.
The API uses JWT Bearer tokens. All protected endpoints require an Authorization header.
curl -X POST https://api.alerthound.io/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"you@example.com","password":"your-password"}'
# Response:
# { "success": true, "data": { "token": "eyJhbGci...", "user": { ... } } }# Include the token in every authenticated request:
curl https://api.alerthound.io/api/v1/alerts \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..."Token lifetime: 7 days. There is no refresh endpoint — users re-authenticate to get a new token.
Stateless: Tokens cannot be server-side revoked. Invalidate client-side by discarding the token.
Algorithm: HS256-signed JWT with sub claim containing the user ID.
All responses use a consistent envelope. Check the success field before accessing data.
{
"success": true,
"data": {
"id": "clalert001abc",
"name": "Vintage Rolex",
...
}
}{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "Alert not found"
}
}Alerts and subscriptions are scoped to a vertical. Use these string values in your requests.
lothoundAuction lot tracking
unithoundStorage unit auctions
pickhoundMarketplace flip opportunities
surplushoundGovernment surplus auctions
estatehoundEstate sale monitoring
scanhoundCross-platform deal aggregation
All endpoints are prefixed with /api/v1. Use the interactive explorer to try them out.
Register, login, password reset, and email verification
/auth/register/auth/login/auth/me/auth/logout/auth/forgot-password/auth/reset-password/auth/verify-emailCreate and manage marketplace alerts with keyword/price/location filters
/alerts/alerts/alerts/:id/alerts/:id/alerts/:id/alerts/:id/pause/alerts/:id/resume/alerts/:id/matchesBrowse scraped marketplace listings — no auth required
/listings/listings/:idManage per-vertical subscription tiers
/subscriptions/subscriptions/subscriptions/:id/subscriptions/:idConfigure email, SMS, push, and webhook delivery preferences
/notifications/preferences/notifications/preferencesStripe checkout, customer portal, and plan catalog
/billing/plans/billing/checkout/billing/portalUser profile, password change, and account deletion
/users/me/users/me/users/me/password/users/meUsed by /alerts and /listings. Pass nextCursor as the cursor query param to get the next page.
{
"items": [...],
"pagination": {
"limit": 20,
"nextCursor": "clalert099xyz",
"hasNextPage": true
}
}Used by Admin endpoints. Pass page and limit query params.
{
"items": [...],
"pagination": {
"page": 1,
"limit": 25,
"total": 142,
"totalPages": 6,
"hasNextPage": true,
"hasPrevPage": false
}
}Rate limits protect platform stability. Exceeding them returns HTTP 429.
| Scope | Limit |
|---|---|
| Authenticated requests | 100 req/min |
| Unauthenticated requests | 30 req/min |
| Analytics event tracking | 60 req/min |
| Auth endpoints (login/register) | 10 req/min |
Rate limit state is communicated via headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.
End-to-end examples: register, create an alert, and read matches.
# 1. Register an account
curl -X POST https://api.alerthound.io/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"email":"you@example.com","password":"SecurePass123!","name":"Your Name"}'
# 2. Create an alert
curl -X POST https://api.alerthound.io/api/v1/alerts \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Vintage Rolex under $500",
"vertical": "lothound",
"keywords": ["rolex", "submariner"],
"maxPrice": 500,
"location": "Los Angeles, CA",
"radiusMiles": 50
}'
# 3. Get your matches
curl https://api.alerthound.io/api/v1/alerts/ALERT_ID/matches \
-H "Authorization: Bearer YOUR_JWT_TOKEN"const API = "https://api.alerthound.io/api/v1";
// Register and get a token
const { data: { token } } = await fetch(`${API}/auth/register`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email: "you@example.com",
password: "SecurePass123!",
}),
}).then(r => r.json());
// Create an alert
const { data: alert } = await fetch(`${API}/alerts`, {
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Storage unit deals — SoCal",
vertical: "unithound",
keywords: ["storage unit", "auction"],
location: "Los Angeles, CA",
radiusMiles: 75,
}),
}).then(r => r.json());
console.log("Alert created:", alert.id);
// Poll for matches
const { data: { items } } = await fetch(
`${API}/alerts/${alert.id}/matches`,
{ headers: { "Authorization": `Bearer ${token}` } }
).then(r => r.json());
console.log(`${items.length} matches found`);import requests
API = "https://api.alerthound.io/api/v1"
# Register and get a token
resp = requests.post(f"{API}/auth/register", json={
"email": "you@example.com",
"password": "SecurePass123!",
"name": "Your Name",
})
token = resp.json()["data"]["token"]
headers = {"Authorization": f"Bearer {token}"}
# Create an alert
resp = requests.post(f"{API}/alerts", json={
"name": "Government surplus vehicles",
"vertical": "surplushound",
"keywords": ["pickup truck", "ford f150", "chevy silverado"],
"maxPrice": 15000,
"location": "California",
}, headers=headers)
alert = resp.json()["data"]
print("Alert created:", alert["id"])
# Get matches
resp = requests.get(
f"{API}/alerts/{alert['id']}/matches",
headers=headers,
)
matches = resp.json()["data"]["items"]
print(f"{len(matches)} matches found")
for match in matches:
listing = match["listing"]
print(f" {listing['title']} — ${listing['price']} on {listing['platform']}")Machine-readable error codes in the error.code field.
EMAIL_TAKENINVALID_CREDENTIALSINVALID_RESET_TOKENINVALID_VERIFY_TOKENNOT_FOUNDINVALID_PRICE_RANGEALREADY_PAUSEDALREADY_ACTIVEALREADY_CANCELLEDNO_SUBSCRIPTIONSTRIPE_ERRORINVALID_CURRENT_PASSWORDNO_PASSWORDRATE_LIMITEDINVALID_SIGNATUREUSER_NOT_FOUNDGet your API token in 30 seconds. No credit card required.