Endpoint reference
The Valara public API has 10 endpoints across 4 resource groups.
All endpoints are under the /api/v1/ prefix and require an
X-API-Key header (see Authentication).
The full machine-readable OpenAPI specification is at:
https://valara.cloud/api/openapi.json(primary)https://dash.jacoballenmedia.com/api/openapi.json(legacy alias)
Base URLs
https://valara.cloud/api/v1/ (primary)
https://dash.jacoballenmedia.com/api/v1/ (legacy alias)
Both hosts serve live traffic. See CLAUDE.md rule 10a for the two-domain policy.
Listings (7 endpoints)
The listing lifecycle is the core of the API. A "listing" is what the internal data model calls a "tour" (the two terms are synonymous).
| Method | Path | Scope | Idempotency key required |
|---|---|---|---|
POST | /listings | listings:write | Yes |
GET | /listings | listings:read | No |
GET | /listings/{listing_number} | listings:read | No |
GET | /listings/{listing_number}/orders | listings:read | No |
PATCH | /listings/{listing_number}/status | listings:write | Yes |
POST | /listings/{listing_number}/cancel | listings:write | Yes |
PATCH | /listings/{listing_number}/sections/{section} | listings:write | Yes |
POST /listings - Create a listing
Creates a new listing and returns its listing_number (the short slug
used everywhere else in the API).
Required fields: address, owner_user_id, agent_one_id
Optional fields: agent_two_id, package, notes
Response: 201 Created with the full listing object including
listing_number, status: "Coming Soon", and the canonical property
page URL.
GET /listings - List listings
Returns a cursor-paginated list of listings owned by your agency.
Query params: cursor (pagination cursor), limit (1-200, default 50),
status filter, agent_id filter.
GET /listings/{listing_number} - Get one listing
Returns the full listing object including status, address, assigned users, media sections, and order references.
GET /listings/{listing_number}/orders - Get listing orders
Returns orders and Square invoice state for a listing.
PATCH /listings/{listing_number}/status - Update status
Valid status values: Coming Soon, Active, Sold, Off Market.
Transitions must follow the listing lifecycle. Invalid transitions
return 422 Unprocessable Entity with a lifecycle_violation error
code.
POST /listings/{listing_number}/cancel - Cancel a listing
Cancels a listing. A 409 Conflict is returned if a cancellation
window guard is active (e.g. shoot is within 24 hours).
PATCH /listings/{listing_number}/sections/{section} - Patch a section
Updates a listing section. section must be one of:
matterport, floorplan.
Media (1 endpoint)
| Method | Path | Scope | Auth |
|---|---|---|---|
POST | /media/upload | media:write | X-API-Key or session cookie (dual-auth endpoint) |
Accepts multipart form data. Uploads are associated with a specific
listing via the listing_number field in the form data.
Scheduling (1 endpoint)
| Method | Path | Scope |
|---|---|---|
GET | /scheduling/availability | scheduling:read |
Returns available shoot time slots for a given address and package.
Users (1 endpoint)
| Method | Path | Scope |
|---|---|---|
GET | /users | users:read |
Returns users in your agency hierarchy (team members, agents, assistants, viewers).
Webhook events catalog (1 endpoint)
| Method | Path | Scope |
|---|---|---|
GET | /webhooks/events | webhooks:read |
Returns the full list of subscribable event types with payload schemas.
This is the machine-readable version of the in-app catalog at
/manage/webhooks/catalog.
Request conventions
Idempotency keys
Every state-changing request (POST, PATCH) MUST include an
X-Idempotency-Key header. Use any UUID v4. The server caches the
response for 24 hours keyed on (agency_id, idempotency_key). Retries
with the same key return the cached response with
X-Idempotent-Replay: true. A conflicting body returns 409.
POST /api/v1/listings HTTP/1.1
X-API-Key: sk_live_your_key_here
X-Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json
Pagination
List endpoints return:
{
"items": [...],
"next_cursor": "eyJpZCI6Ik9...",
"total": 142
}
Pass next_cursor value as ?cursor= on the next request. Empty
string means end of collection.
Error envelope
All errors use a consistent JSON envelope:
{
"error": {
"code": "listing_not_found",
"message": "No listing with number ABC123 exists in your agency.",
"request_id": "req_01HXREQUESTID"
}
}
Include request_id in any support request - it correlates to the
exact log entry in our backend.