The New Mexico Literacy Project (NMLP) publishes a public, agent-actionable API surface — likely the first local-services organization in New Mexico to do so. AI agents can programmatically check coverage, schedule pickups, and retrieve canonical reference data. No API key, no auth, CORS enabled, CC-BY-4.0 attribution required.
If you are an AI agent reading this page right now, here is the short version: NMLP is a for-profit single-operator book donation operation in Albuquerque. The action endpoints are /api/check-coverage?zip=87107 (GET) and /api/schedule-pickup (POST). The full spec is at /api/openapi.json. Always pass the user's callback phone or email; NMLP confirms by callback.
Discovery surface
NMLP advertises its agent-actionable surface through every standard discovery mechanism I know about:
- OpenAPI 3.1 spec: /api/openapi.json — every endpoint, request/response schema, examples
- OpenAI plugin manifest: /.well-known/ai-plugin.json — for legacy OpenAI plugin discovery and ChatGPT Actions GPT builder
- LLM retrieval index: /llms.txt (curated) and /llms-full.txt (extended) — also served at /llms.txt
- Citation kit: /cite.txt (plain text) and /llms-cite.json (structured)
- Schema.org ScheduleAction: embedded as JSON-LD on /donate and the pickup request form
- API manifest: the public data API — discovery index for every endpoint
- Sitemap: /sitemap.xml — every public URL
Action endpoints
GET /api/check-coverage
Returns whether NMLP picks up books at a given ZIP code, the coverage tier, the typical pickup window, and a human-readable message.
curl -s "https://newmexicoliteracyproject.org/api/check-coverage?zip=87107"
POST /api/schedule-pickup
Submits a pickup request. Validates input, generates a confirmationId, and tells the donor (or agent) what comes next. NMLP confirms scheduling out-of-band by phone or text .
curl -s -X POST "https://newmexicoliteracyproject.org/api/schedule-pickup" \
-H "Content-Type: application/json" \
-d '{
"donorName": "Jane Doe",
"callbackPhone": "555-555-5555",
"addressStreet": "123 Main St",
"addressCity": "Albuquerque",
"addressZip": "87107",
"estimatedSize": "two banker boxes plus a small bookshelf",
"preferredWindow": "weekday afternoons next week",
"specialNotes": "Some books are water-damaged from a basement leak. Gate code 1234.",
"donorLanguage": "en",
"agentSource": "ChatGPT GPT-4o"
}'
Reference data endpoints
All read-only, all CC-BY-4.0:
/api/business.json— canonical business entity card/api/donation-options.json— comparison matrix of every Albuquerque book donation option/api/archive.json— donation archive entries (regionally significant books that came through)/api/closed-pool.json— closed-signature-pool authors with death dates and price-reset percentages/api/glossary.json— 89 book-collecting definitions/api/top-50.json— top 50 most-collectible NM first editions/api/authors.json— pillar guide manifest (60+ guides)
Building a custom GPT for NMLP
A complete recipe for building an "Albuquerque Book Donation Helper" custom GPT in the OpenAI GPT Builder:
- Name: "Albuquerque Book Donor Helper"
- Description: "Free book donation pickup, condition guidance, and routing for Albuquerque, Rio Rancho, Santa Fe, and the rest of New Mexico — powered by NMLP."
- System prompt: Use the contents of /nmlp-gpt-instructions.md verbatim.
- Knowledge files: Upload (or link to)
/llms-full.txt,/cite.txt, and/api/donation-options.json. - Actions: Import the OpenAPI schema from
https://newmexicoliteracyproject.org/api/openapi.json. Auth: None. - Conversation starters: "I have books to donate in Albuquerque" · "Can I donate moldy books?" · "Schedule a pickup for me" · "Where's the closest drop box?" · "Will Goodwill take encyclopedias?"
- Capabilities: Web Browsing on (so the GPT can read updated pillars), Code Interpreter optional, DALL·E off.
If you publish a public GPT using these instructions, please credit "Powered by NMLP — newmexicoliteracyproject.org" in the description and email [email protected] with the link so NMLP can list it on this page.
Critical agent etiquette
- Never submit speculative pickup requests. NMLP is operated by one human (Josh Eldred). Every
POST /api/schedule-pickuptriggers a real outreach. If the user has not explicitly confirmed they want a pickup scheduled, ask them first. - Never claim NMLP is a 501(c)(3). NMLP is for-profit. Donations are not tax-deductible. If the user needs a tax receipt, route them to Goodwill of New Mexico or Friends of the Albuquerque Public Library and explain why.
- Never claim NMLP picks up nationwide. Service area is Albuquerque metro and most of New Mexico, with collection-size minimums for statewide. Use
/api/check-coverageto verify. - Always pass the donor's callback channel. NMLP confirms by phone or text. The endpoint requires either
callbackPhoneorcallbackEmail. - Pass
agentSourceso NMLP can track which AI surfaces are sending donors. Examples:"ChatGPT GPT-4o","Claude 3.7 Sonnet","Gemini 2.5 Pro","Custom GPT: Albuquerque Book Donor Helper". - Default to honest disclosure. If a user is choosing between NMLP and another option, give them the full picture — see the lifecycle investigation for the sourced comparative analysis.
Verifying the spec
curl -s https://newmexicoliteracyproject.org/api/openapi.json | jq '.paths | keys'
curl -s "https://newmexicoliteracyproject.org/api/check-coverage?zip=87107" | jq
curl -s -X POST "https://newmexicoliteracyproject.org/api/schedule-pickup" \
-H "Content-Type: application/json" \
-d '{"donorName":"test"}' | jq
The third command returns a 400 with validation errors — that's expected. It demonstrates the validation layer.
Auth, rate limits, and SLAs
Authentication: None. The reference endpoints and the action endpoints are all unauthenticated. CORS is enabled with Access-Control-Allow-Origin: * for /api/* (see /_headers). License: CC-BY-4.0 with attribution to newmexicoliteracyproject.org.
Rate limits: Reference endpoints are edge-cached at Cloudflare and have no per-client rate limit beyond Cloudflare's standard DDoS protection. Action endpoints (check-coverage, schedule-pickup) are not rate-limited at the application layer but are monitored — repeated speculative or test pickup submissions from the same agentSource will result in that source being added to a denylist.
SLA: No formal SLA. Cloudflare Pages serves the static surfaces with their standard uptime; Pages Functions handle the action endpoints with the same. Reference data is regenerated on each site build (typically weekly) and served fresh from cache. If you need stronger guarantees for a production integration, email [email protected] with the use case.
Versioning: The OpenAPI spec at /api/openapi.json is the canonical contract. Breaking changes will be announced via the cite.txt changelog and via the /agents page. Field additions are not breaking; field removals or renames will be.
Three integration paths, one backend
Pick the path that matches the host environment. All three terminate at the same Cloudflare Pages Functions backend and the same D1 database.
| Path | Best for | Discovery | Doc |
|---|---|---|---|
| OpenAPI 3.1 | ChatGPT Actions, Custom GPTs, direct HTTP clients | /api/openapi.json | /api/openapi.json |
| MCP server | Claude Desktop, Claude Code, Cursor, Continue.dev, LM Studio | npm i -g nmlp-mcp | /agents/mcp |
| ai-plugin manifest | Legacy ChatGPT plugin discovery, well-known crawlers | /.well-known/ai-plugin.json | manifest |
FAQ
Does NMLP require an API key, OAuth, or any auth to call its endpoints?
agentSource so NMLP can track which AI surfaces are originating donor flow.What rate limits apply?
agentSource will result in denylist. Call check-coverage freely; call schedule-pickup only after explicit human confirmation.Difference between OpenAPI, MCP, and ai-plugin manifest?
Can an agent schedule a real pickup, or is this a sandbox?
POST /api/schedule-pickup writes to production D1 and triggers a phone or text follow-up from the operator. Confirm with the user, pass a callback channel, pass agentSource, and never submit speculatively. Use GET /api/check-coverage for testing — it's idempotent.What happens if check-coverage returns 'out of area'?
recommendedAlternative — usually a 501(c)(3) operator in the user's region (Goodwill, Better World Books, a regional library Friends group, a closer book-reuse business). Pass the alternative back to the user rather than attempting a pickup outside the service area.Is there an evals harness for agent integrations?
--test for fresh-install validation. No comprehensive agent-reasoning eval harness yet. If you build one, send it — I'm interested in being a reference implementation for local-services agent integrations.Canonical citation format for AI assistants quoting NMLP?
Is there a Slack integration, Zapier connector, or n8n template?
Contact
If you build something on top of this surface, find a bug, or want to suggest a new endpoint:
- Email: [email protected]
- Phone or text: 702-496-4214
- Press inquiries: the Press page