Website widgets are the quickest way to show your pets on your own site. If you want more control, such as a custom adoption page or a connection to another system, you can use the PawPlacer SDK.
pawplacer-sdk@^1.6.0 is a TypeScript/JavaScript client for the PawPlacer API, available on npm. It's fully typed, and it lets trusted server-side code read and write your shelter data. API keys are scoped, so website backends can
use read-only access while jobs that create records use write access.
What you can do with it
Build a custom pet listing on your website. Pull account pets with filters such as species, status, and search,
then apply show_public and your own publication rules before displaying them. The API key grants access to
non-deleted account pets; it does not apply the public-profile photo, status, or organization gates for you.
Create records from external forms. If you use a third-party form tool or your own website form, trusted server code can create pet, adopter, foster, surrender, or volunteer records. Adopter and foster submissions can also include a complete application payload.
Sync with other systems. Use updated_since to pull only records that changed since your last sync. Build nightly
jobs that keep PawPlacer in sync with whatever else your organization uses.
Display adoption fees dynamically. Pull your fee configuration (species rules, attribute adjustments) and show accurate fees on your website without hardcoding them.
Show contracts. Pull your adopter, foster, volunteer, or surrender contracts as markdown and render them on your site.
Getting started
Install it:
npm install pawplacer-sdk@^1.6.0
Generate an API key in Settings > SDK/API. The app labels the scopes Read only and Write + read: read-only keys are for trusted website backends and dashboards, while write keys are for trusted jobs that create records. Never put either key in browser or mobile-app code.
The same settings page has a Test Your Key health check. Paste a key, click Run Health Check, and PawPlacer runs the SDK methods for pets, people, custom fields, adoption fees, contracts, response metadata, and write access.
Then set up a client:
import { PawPlacerClient } from "pawplacer-sdk";
const pawplacer = new PawPlacerClient({
apiKey: process.env.PAWPLACER_API_KEY!,
});
You can then make calls like these:
// Get available dogs
const dogs = await pawplacer.pets.list({
status: "available",
species: "dog",
limit: 12,
});
// Get a specific pet
const pet = await pawplacer.pets.get("pet-uuid");
// List active adopters
const adopters = await pawplacer.people.list({
type: "adopter",
status: "active",
});
// Create an adopter from your own form
const newAdopter = await pawplacer.people.create({
type: "adopter",
name: "Jane Smith",
email: "jane@example.com",
status: "pending",
});
Every response is typed, so your editor knows the shape of Pet, Person, and AdoptionFeeEntry.
Custom fields work too
If you've set up custom form fields in PawPlacer (yard size, vet references, whatever), the SDK can read those definitions and include custom field data when creating records:
// See what custom fields exist
const fields = await pawplacer.pets.getCustomFields();
// Create a pet with custom field data
const pet = await pawplacer.pets.create({
name: "Max",
species: "dog",
age_category: "young",
sex: "male",
size: "medium",
status: "available",
health: "good",
custom_field_data: {
microchip_brand: "HomeAgain",
rescue_origin: "owner_surrender",
},
});
Submit complete applications
Version 1.6 can drive a rescue's current adopter or foster form instead of creating only a bare person record. Load the ordered custom fields and matching contract, render them in your own design, and submit the accepted application from trusted server code:
const [fields, contract] = await Promise.all([
pawplacer.people.getCustomFields("adopter"),
pawplacer.contracts.get("adopter"),
]);
// Render fields that are not hidden/internal_only and display contract.content.
// Generate this UUID once for the browser submission and retain it for retries.
const submissionId = "550e8400-e29b-41d4-a716-446655440002";
const applicant = await pawplacer.people.create(
{
type: "adopter",
name: "Jane Smith",
email: "jane@example.com",
custom_field_data: {
housing_type: "house",
has_yard: true,
},
application: {
pet_ids: ["550e8400-e29b-41d4-a716-446655440001"],
terms_accepted: true,
},
},
{ idempotencyKey: submissionId },
);
PawPlacer creates the pending person, application record, and selected-pet associations atomically. The returned person includes applicant.application.id, the selected pet_ids, and the submission timestamp.
Built-in caching
GET responses are cached in memory with stale-while-revalidate, so a website that shows the same pet listing to every visitor doesn't need to call the API on every page load. The default refresh is every 3 hours, but you can tune it:
const pawplacer = new PawPlacerClient({
apiKey: process.env.PAWPLACER_API_KEY!,
cache: { enabled: true, refreshFrequencyMinutes: 60 },
});
You can also clear the cache manually, invalidate specific patterns, or check hit/miss stats. The API's
Cache-Control headers take precedence when present.
Idempotency for create operations
Every create call sends an idempotency key automatically, so if a request gets retried (network hiccup, timeout),
you don't end up with duplicate records. For background jobs that might replay across restarts, you can pass your own
stable key:
const pet = await pawplacer.pets.create(
{ name: "Max", species: "dog", /* ... */ },
{ idempotencyKey: `nightly-sync:${externalId}` },
);
If the key was already used with the same payload, you get the original response back.
pawplacer.lastResponseMeta.idempotencyReplay tells you if that happened.
Rate limits and error handling
Rate limits are per API key and vary by endpoint. The SDK exposes them through pawplacer.lastResponseMeta.rateLimit
so you can see how many requests you have left. Listing endpoints get 2,000 requests/hour, individual gets are
5,000/hour, and create and update endpoints are 250/hour.
Errors are typed too. PawPlacerApiError for HTTP errors (with status, code, and message),
PawPlacerResponseValidationError if a response doesn't match the expected shape. Both are importable from the
package.
Works with Next.js, Express, and other servers
The SDK is server-side only by default: it blocks browser usage to keep your API key safe. Use it in API routes, server actions, getServerSideProps, Express handlers, cron jobs, or anything else that runs on a server.
// Next.js App Router example
// app/api/pets/route.ts
import { PawPlacerClient } from "pawplacer-sdk";
export async function GET() {
const client = new PawPlacerClient({
apiKey: process.env.PAWPLACER_API_KEY!,
});
const pets = await client.pets.list({
status: "available",
limit: 12,
});
return Response.json(pets);
}
CommonJS works too if that's your setup.
Where to go next
The SDK guide covers setup and the available methods, and the developer API guide covers the REST API. The OpenAPI spec and example code are linked from the package readme on npm.
If you don't have a developer available, PawPlacer's website widgets can add your pets and forms to most sites without any code.



