Use the PawPlacer public API to fetch pet data, adopter/foster records, adoption fee rules, and contract terms. All endpoints require an API key sent in the x-api-key header. A Read only key from Settings > SDK & API is enough for every endpoint on this page.
Endpoint Summary
| Endpoint | Purpose | Rate Limit |
|---|---|---|
GET /api/pets | Paginated list of public pets | 100/hr |
GET /api/pets/{petId} | Single public pet | 400/hr |
GET /api/pets/custom-fields | Custom field metadata for pet forms | 15/hr |
GET /api/people?type=adopter|foster | Paginated list of adopters or fosters | 100/hr |
GET /api/people/{id}?type=adopter|foster | Single adopter or foster | 400/hr |
GET /api/people/custom-fields?type=adopter|foster | Custom field metadata for people forms | 15/hr |
GET /api/adoption-fees | Adoption fee configuration rules | 15/hr |
GET /api/contracts?type=adopter|foster|volunteer|surrender | Terms & conditions (markdown) | 15/hr |
Cache responses for at least a few minutes to stay well below the hourly limits. The payloads are stable and work well with server-side or per-process caching.
OpenAPI 3.1 contract: https://pawplacer.com/openapi/public-api-v1.yaml
Standard Response Headers
All public GET endpoints include diagnostic and rate-limit headers:
X-Request-Id: unique request identifier for support/debuggingX-Api-Version: current public API contract versionX-Generated-At: response generation timestamp (ISO-8601)X-RateLimit-Limit: endpoint hourly limitX-RateLimit-Remaining: remaining calls in current window (-1when unavailable)X-RateLimit-Reset: Unix timestamp for next limit reset windowRetry-After: present on429responses
Conditional Requests (ETag)
All GET endpoints return an ETag header containing a hash of the response payload. You can use this to avoid re-downloading data that hasn't changed.
Send the ETag value back as an If-None-Match header on your next request. If the data is unchanged, the API responds with 304 Not Modified and an empty body, saving bandwidth and counting toward your rate limit at a reduced cost.
// First request: store the ETag
const response = await fetch('https://pawplacer.com/api/pets?species=dog', {
headers: { 'x-api-key': process.env.PAWPLACER_API_KEY }
});
const etag = response.headers.get('ETag');
const pets = await response.json();
// Subsequent request: send If-None-Match
const check = await fetch('https://pawplacer.com/api/pets?species=dog', {
headers: {
'x-api-key': process.env.PAWPLACER_API_KEY,
'If-None-Match': etag
}
});
if (check.status === 304) {
// Data unchanged: use your cached copy
} else {
const freshPets = await check.json();
}
GET responses also include a Cache-Control: private, max-age=60, stale-while-revalidate=300 header, so HTTP-aware clients and CDNs can cache responses for up to 60 seconds with a 5-minute stale-while-revalidate window.
GET /api/pets – List Public Pets
Returns a paginated list of public pets with a full pet profile payload (including custom fields and metadata).
Request
GET https://pawplacer.com/api/pets
x-api-key: YOUR_API_KEY
Optional query parameters
limit: 1–100 (default 20)offset: results to skip (default 0)species:dog,cat, orrabbitstatus: matches your custom status labels (case-insensitive)search: fuzzy match on name, description, and breed valuesupdated_since: ISO-8601 timestamp; returns only pets withupdated_at >= updated_since
JavaScript example
const response = await fetch('https://pawplacer.com/api/pets?status=available&species=dog&limit=12', {
headers: { 'x-api-key': process.env.PAWPLACER_API_KEY }
});
const { pets, total, hasMore } = await response.json();
Response
{
"pets": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"name": "Max",
"species": "dog",
"status": "Available",
"health": "good",
"show_public": true,
"breed": ["Labrador Retriever"],
"color": ["Black"],
"age_category": "young",
"age_years": null,
"age_months": null,
"age_birthday": null,
"sex": "male",
"size": "medium",
"description": "Friendly and energetic dog",
"spayed": true,
"adoption_fee": "250",
"microchip_id": null,
"good_with": ["families", "kids"],
"bad_with": [],
"temperaments": ["playful", "social"],
"image_urls": [
"https://pawplacer.com/pets/max.jpg",
"https://pawplacer.com/pets/max-2.jpg"
],
"image_url": "https://pawplacer.com/pets/max.jpg",
"coat_length": "short",
"custom_id": "EXT-1001",
"custom_field_data": {
"favorite_toy": "Tennis ball"
},
"intake_date": null,
"outcome_date": null,
"primary_veterinarian": "Downtown Vet Clinic",
"special_needs": [],
"tags": ["Senior", "Special Care"],
"status_change_notes": null,
"weight": null,
"adopted_on": null,
"adopted_by": "Jane Foster",
"created_at": "2026-02-17T12:00:00.000000+00:00",
"updated_at": "2026-02-17T12:00:00.000000+00:00"
}
],
"total": 42,
"limit": 12,
"offset": 0,
"hasMore": true
}
Fields returned
pets: array of public pets. Each object includes a full profile payload:- Core:
id,name,species,status,health,show_public - Demographics:
breed,color,age_category,age_years,age_months,age_birthday,sex,size,weight,spayed - Behavior/compatibility:
good_with,bad_with,temperaments,special_needs - Tags:
tags(pet tag labels) - Identifiers:
custom_id,microchip_id - Notes + dates:
description,intake_date,outcome_date,status_change_notes - Relationships (resolved names):
primary_veterinarian,adopted_by - Media:
image_urls,image_url,coat_length - Custom data:
custom_field_data - Metadata:
created_at,updated_at,adopted_on
- Core:
total,limit,offset,hasMore: pagination metadata
GET /api/pets/{petId} – Single Pet
Fetch a single public pet by ID. This endpoint returns the same field set as the list endpoint.
Request
GET https://pawplacer.com/api/pets/{petId}
x-api-key: YOUR_API_KEY
JavaScript example
const response = await fetch(`https://pawplacer.com/api/pets/${petId}`, {
headers: { 'x-api-key': process.env.PAWPLACER_API_KEY }
});
const pet = await response.json();
If the pet is not public, deleted, or does not exist, the API responds with 404 and { "error": "Pet not found" }.
GET /api/pets/custom-fields – Custom Field Metadata
Retrieve configured custom form fields so you can send valid keys when creating pets.
Request
GET https://pawplacer.com/api/pets/custom-fields
x-api-key: YOUR_API_KEY
Response
{
"custom_fields": [
{
"field_key": "favorite_toy",
"label": "Favorite Toy",
"field_type": "text",
"required": false,
"help_text": "Include any comfort objects",
"options": null,
"section": "Behavior",
"hidden": false,
"internal_only": false
}
]
}
Use the field_key (not the label) when populating custom_field_data in POST /api/pets requests. hidden is true when the field or its section is hidden in the form builder. internal_only is true when the field is marked for staff-only use.
Rate Limit Errors
Rate limits are enforced per API key and endpoint on the current hourly window. If the limit is exceeded, the response is 429 with a descriptive error payload, for example:
{
"error": "Rate limit exceeded. Maximum 100 requests per hour. Cache responses to avoid throttling.",
"code": "rate_limited",
"request_id": "3dfabc8f-3f6f-4f4e-bffe-5d0dc5292e6f"
}
Reduce the frequency of calls or increase your cache window before retrying.
Error Reference
| Status | Reason | Example Payload |
|---|---|---|
| 401 | Missing or invalid API key | { "error": "API key required", "code": "api_key_required", "request_id": "..." } |
| 404 | Record not found | { "error": "Pet not found", "code": "pet_not_found", "request_id": "..." } |
| 429 | Rate limit exceeded | see example above |
| 500 | Unexpected server issue | { "error": "Something went wrong", "code": "internal_error", "request_id": "..." } |
Always handle non-200 status codes and back off when you see 429 responses.
GET /api/people – List Adopters or Fosters
Returns a paginated list of adopters or fosters. The type query parameter is required.
Request
GET https://pawplacer.com/api/people?type=adopter
x-api-key: YOUR_API_KEY
Query parameters
type: required:adopterorfosterlimit: 1–100 (default 20)offset: results to skip (default 0)status: filter by status (e.g.active,pending)search: fuzzy match on name, email, phoneupdated_since: ISO-8601 timestamp
Response
{
"type": "adopter",
"people": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"type": "adopter",
"name": "Jane Smith",
"email": "jane@example.com",
"phone": "555-0100",
"address": "123 Main St",
"status": "active",
"status_change_notes": null,
"custom_field_data": {},
"tags": ["VIP"],
"capacity": null,
"created_at": "2026-03-01T10:00:00.000000+00:00",
"updated_at": "2026-03-01T10:00:00.000000+00:00"
}
],
"total": 1,
"limit": 20,
"offset": 0,
"hasMore": false
}
GET /api/people/{id} – Single Adopter or Foster
GET https://pawplacer.com/api/people/{id}?type=adopter
x-api-key: YOUR_API_KEY
Returns the same person object shape as the list endpoint. The type parameter is required. Invalid UUIDs return 400. Missing records return 404.
GET /api/people/custom-fields – People Form Fields
GET https://pawplacer.com/api/people/custom-fields?type=adopter
x-api-key: YOUR_API_KEY
Response
{
"type": "adopter",
"custom_fields": [
{
"field_key": "has_yard",
"label": "Has Yard",
"field_type": "boolean",
"required": false,
"help_text": null,
"options": null,
"section": "Housing",
"hidden": false,
"internal_only": false
}
]
}
Use the field_key values when populating custom_field_data in POST /api/people requests. hidden is true when the field or its section is hidden in the form builder. internal_only is true when the field is marked for staff-only use.
GET /api/adoption-fees – Fee Configuration
Returns the account's adoption fee rules. Each rule maps a species + attribute combination to a dollar adjustment.
GET https://pawplacer.com/api/adoption-fees
x-api-key: YOUR_API_KEY
Response
{
"fees": [
{
"species": "dog",
"attribute_type": "age",
"attribute_value": "youngest",
"adjustment": 350
},
{
"species": "dog",
"attribute_type": "health",
"attribute_value": "poor",
"adjustment": -50
}
]
}
Pet responses also include a global_adoption_fee field (number or null) that resolves these rules against each pet's attributes when no manual fee override is set.
GET /api/contracts – Terms & Conditions
Returns the terms & conditions content for a given contract type. Content is markdown.
GET https://pawplacer.com/api/contracts?type=adopter
x-api-key: YOUR_API_KEY
Response
{
"type": "adopter",
"content": "# Adoption Agreement\n\nBy signing this agreement...",
"updated_at": "2026-01-15T00:00:00.000000+00:00"
}
Valid types: adopter, foster, volunteer, surrender. Returns empty content and null updated_at if no contract is configured.