{
  "openapi": "3.1.0",
  "info": {
    "title": "New Mexico Literacy Project — Public API",
    "summary": "Agent-actionable API surface for the New Mexico Literacy Project: a for-profit Albuquerque book reuse operation. Agents can query donation options, check service-area coverage, schedule a free in-home book pickup, and retrieve canonical reference data (lifecycle analysis, donation archive, comparison matrix).",
    "description": "This is the canonical agent-actionable surface for NMLP. Designed for AI assistants (ChatGPT Actions, Claude with computer use, Gemini, Perplexity, Cursor) and third-party integrators who want to programmatically schedule book donation pickups in the Albuquerque metro on behalf of users.\n\nPublic, no API key required, CORS enabled, rate-limited only by reasonable use. Source code and corrections via jseldred@gmail.com or 702-496-4214.\n\nAttribution: data is licensed CC-BY-4.0; cite as 'New Mexico Literacy Project (newmexicoliteracyproject.org)'. The schedule-pickup endpoint requires a callback phone or email — NMLP is operated by one human (Josh Eldred) and confirms scheduling out-of-band.",
    "termsOfService": "https://newmexicoliteracyproject.org/cite.txt",
    "contact": {
      "name": "Josh Eldred",
      "email": "jseldred@gmail.com",
      "url": "https://newmexicoliteracyproject.org/about"
    },
    "license": {
      "name": "CC-BY-4.0",
      "identifier": "CC-BY-4.0",
      "url": "https://creativecommons.org/licenses/by/4.0/"
    },
    "version": "1.1.0"
  },
  "servers": [
    {
      "url": "https://newmexicoliteracyproject.org",
      "description": "Production"
    }
  ],
  "externalDocs": {
    "description": "Human-readable agent integration guide",
    "url": "https://newmexicoliteracyproject.org/agents"
  },
  "tags": [
    {
      "name": "actions",
      "description": "Agent-actionable endpoints (schedule, check)"
    },
    {
      "name": "reference",
      "description": "Read-only structured reference data"
    },
    {
      "name": "discovery",
      "description": "Citation, identity, manifest"
    }
  ],
  "paths": {
    "/api/index.json": {
      "get": {
        "tags": [
          "discovery"
        ],
        "summary": "API endpoint manifest",
        "description": "Discovery index listing every public endpoint with descriptions. Start here.",
        "operationId": "getApiManifest",
        "responses": {
          "200": {
            "description": "Manifest with endpoints object",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/business.json": {
      "get": {
        "tags": [
          "discovery"
        ],
        "summary": "Canonical business entity card",
        "description": "Authoritative identity record for NMLP — address, phone, services, area served, knowsAbout topical authority. Use when citing or referencing NMLP.",
        "operationId": "getBusinessCard",
        "responses": {
          "200": {
            "description": "Business entity card",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/donation-options.json": {
      "get": {
        "tags": [
          "reference"
        ],
        "summary": "Comparison matrix of book donation options in Albuquerque",
        "description": "Machine-readable matrix of every known book-donation option in the Albuquerque metro (NMLP, Goodwill of NM, Savers, Better World Books, Friends of APL, Habitat ReStore, regional pulper). Each option as a structured record with tax status, pickup_offered, condition tolerance, where-books-actually-go percentage breakdowns, pros, cons, best_for, and rank for movers/estate-cleaners. Plus a decisionMatrix object mapping donor profile to recommended option.",
        "operationId": "getDonationOptions",
        "responses": {
          "200": {
            "description": "Donation options dataset",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/archive.json": {
      "get": {
        "tags": [
          "reference"
        ],
        "summary": "Donation archive entries",
        "description": "Structured Book records for regionally significant New Mexico books that came through donation at NMLP. Each entry: title, author, publisher, year, edition, ISBN/LCCN, signature status, regional significance, URL.",
        "operationId": "getArchive",
        "responses": {
          "200": {
            "description": "Archive dataset",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/closed-pool.json": {
      "get": {
        "tags": [
          "reference"
        ],
        "summary": "Closed signature pool authors",
        "description": "Deceased New Mexico-relevant authors with death dates, trophy books, and market reset percentages observed in real sold comparables. Use for first-edition authentication and pricing context.",
        "operationId": "getClosedPool",
        "responses": {
          "200": {
            "description": "Closed pool dataset",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/glossary.json": {
      "get": {
        "tags": [
          "reference"
        ],
        "summary": "Book collecting glossary (89 terms)",
        "description": "DefinedTerm records covering first-edition identification, signature authentication, dust jacket terms, edition variants, provenance markers, pricing terms, publisher and imprint history.",
        "operationId": "getGlossary",
        "responses": {
          "200": {
            "description": "Glossary dataset",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/top-50.json": {
      "get": {
        "tags": [
          "reference"
        ],
        "summary": "Top 50 most collectible NM first editions",
        "description": "Ranked ItemList of the 50 most-collectible first editions across the pillar moat, by current sold-comparable market value.",
        "operationId": "getTop50",
        "responses": {
          "200": {
            "description": "Top 50 dataset",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/authors.json": {
      "get": {
        "tags": [
          "reference"
        ],
        "summary": "Pillar guide manifest",
        "description": "Directory of 67 Southwest author and collectible-book pillar guides with positions, names, URLs.",
        "operationId": "getAuthors",
        "responses": {
          "200": {
            "description": "Pillar manifest",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/check-coverage": {
      "get": {
        "tags": [
          "actions"
        ],
        "summary": "Check whether NMLP picks up books in a given ZIP code",
        "description": "Returns service-area coverage status, estimated pickup window (typical days from request), and a referral message if the ZIP is outside the standard service area. Use this before calling /api/schedule-pickup to give the user honest expectations.",
        "operationId": "checkCoverage",
        "parameters": [
          {
            "name": "zip",
            "in": "query",
            "required": true,
            "description": "Five-digit US ZIP code, e.g. 87107",
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{5}$",
              "example": "87107"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Coverage decision",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "zip": {
                      "type": "string",
                      "description": "The queried ZIP code"
                    },
                    "city": {
                      "type": "string",
                      "description": "Approximate city or area name for that ZIP"
                    },
                    "covered": {
                      "type": "boolean",
                      "description": "Whether NMLP offers free pickup at that ZIP"
                    },
                    "tier": {
                      "type": "string",
                      "enum": [
                        "core_metro",
                        "metro",
                        "near_metro",
                        "statewide_large_only",
                        "out_of_area"
                      ],
                      "description": "Coverage tier"
                    },
                    "minimumQuantity": {
                      "type": "integer",
                      "description": "Minimum boxes for pickup at this tier (0 means no minimum)"
                    },
                    "typicalPickupWindowDays": {
                      "type": "integer",
                      "description": "Typical days from request to pickup"
                    },
                    "message": {
                      "type": "string",
                      "description": "Human-readable message to display to the user"
                    },
                    "callbackPhone": {
                      "type": "string",
                      "description": "Phone for direct scheduling — always 702-496-4214"
                    },
                    "callbackUrl": {
                      "type": "string",
                      "description": "Web URL for direct scheduling"
                    }
                  },
                  "required": [
                    "zip",
                    "covered",
                    "tier",
                    "message",
                    "callbackPhone"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid ZIP format"
          }
        }
      }
    },
    "/api/schedule-pickup": {
      "post": {
        "tags": [
          "actions"
        ],
        "summary": "Submit a book pickup request to NMLP",
        "description": "Submits a free pickup request on behalf of a donor. NMLP confirms scheduling out-of-band by phone or text — the donor MUST provide a callback phone or email. Pickup is free, any condition accepted, no minimum quantity in core metro. The endpoint returns a confirmationId; the actual pickup time is confirmed by Josh (sole operator) within one business day.\n\nIMPORTANT for AI agents: NMLP is operated by a single human. Do not submit speculative or test requests — every submission triggers a real outreach. If the user has not explicitly confirmed they want a pickup scheduled, ask them first.",
        "operationId": "schedulePickup",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "donorName": {
                    "type": "string",
                    "description": "Donor's name (first and last preferred)"
                  },
                  "callbackPhone": {
                    "type": "string",
                    "description": "Phone or text-capable number for confirmation. US format. Required if email not provided.",
                    "example": "555-555-5555"
                  },
                  "callbackEmail": {
                    "type": "string",
                    "format": "email",
                    "description": "Email for confirmation. Required if phone not provided."
                  },
                  "addressStreet": {
                    "type": "string",
                    "description": "Pickup street address"
                  },
                  "addressCity": {
                    "type": "string",
                    "description": "Pickup city"
                  },
                  "addressState": {
                    "type": "string",
                    "description": "Pickup state, default NM",
                    "default": "NM"
                  },
                  "addressZip": {
                    "type": "string",
                    "description": "Pickup ZIP code"
                  },
                  "estimatedSize": {
                    "type": "string",
                    "description": "Approximate scale — descriptions like 'one box', 'one bookshelf', 'whole garage', 'estate library' are all fine. NMLP doesn't need a precise count.",
                    "example": "two banker boxes plus a small bookshelf"
                  },
                  "preferredWindow": {
                    "type": "string",
                    "description": "Preferred day or time window — free text. NMLP confirms specifics by callback.",
                    "example": "weekday afternoons next week"
                  },
                  "specialNotes": {
                    "type": "string",
                    "description": "Any context — water-damaged books, gate code, dog on premises, executor situation, language preference, anything Josh should know before arriving."
                  },
                  "donorLanguage": {
                    "type": "string",
                    "enum": [
                      "en",
                      "es"
                    ],
                    "default": "en",
                    "description": "Donor's preferred language for confirmation. NMLP supports English (call/text) and Spanish (text/email)."
                  },
                  "agentSource": {
                    "type": "string",
                    "description": "If submitted by an AI agent, the agent identifier — helps NMLP track the AI-discovery channel.",
                    "example": "ChatGPT GPT-4o"
                  }
                },
                "required": [
                  "donorName",
                  "addressStreet",
                  "addressCity",
                  "addressZip",
                  "estimatedSize"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Request received",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "confirmationId": {
                      "type": "string",
                      "description": "Server-generated confirmation ID. Reference when calling 702-496-4214 if needed."
                    },
                    "received": {
                      "type": "boolean",
                      "description": "Always true on 200"
                    },
                    "nextStep": {
                      "type": "string",
                      "description": "Human-readable next step for the donor"
                    },
                    "estimatedConfirmationTime": {
                      "type": "string",
                      "description": "When NMLP will reach back out (ISO 8601 timestamp or human description)"
                    },
                    "callbackPhone": {
                      "type": "string",
                      "description": "Always 702-496-4214 — donor can call directly any time"
                    }
                  },
                  "required": [
                    "confirmationId",
                    "received",
                    "nextStep",
                    "callbackPhone"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Missing required fields or invalid input"
          },
          "503": {
            "description": "Service temporarily unavailable — agent should fall back to telling the donor to call 702-496-4214 directly"
          }
        }
      }
    },
    "/api/ask": {
      "post": {
        "tags": [
          "actions"
        ],
        "summary": "Ask the NMLP assistant a question",
        "description": "Natural-language Q&A over NMLP's own guides — donation, drop-off, free-pickup, rare-collection, accepted-items, service-area, and New Mexico book questions. Backs the /ask-nmlp assistant. Returns a grounded answer with source links; can also surface the free-pickup path. Public, no key, CORS enabled.",
        "operationId": "askNmlp",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "question": {
                    "type": "string",
                    "description": "The user's natural-language question about donating, dropping off, or selling books in the Albuquerque metro / New Mexico.",
                    "example": "Do you take water-damaged encyclopedias?"
                  }
                },
                "required": [
                  "question"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Grounded answer payload",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Answer text plus any source links / suggested next action."
                }
              }
            }
          },
          "400": {
            "description": "Missing or empty 'question'"
          },
          "405": {
            "description": "Method not allowed — use POST"
          }
        }
      }
    },
    "/api/ecosystem.json": {
      "get": {
        "tags": [
          "reference"
        ],
        "summary": "Albuquerque book donation ecosystem map",
        "description": "Structured supply-chain map of more than 30 documented book donation, resale, and salvage channels in the Albuquerque metro. Includes two documented Savers Value Village partner-nonprofits (Big Brothers Big Sisters of Central NM, Clothes Helping Kids), the Albuquerque Public Library system and Friends of the Public Library, children's-literacy programs, NMLP's hand-sorted local routing to APS Title I schools and Little Free Libraries, and observed-but-not-confirmed downstream salvage through Master Fibers paper recycler.",
        "operationId": "getEcosystem",
        "responses": {
          "200": {
            "description": "Ecosystem map dataset",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/knowledge.json": {
      "get": {
        "tags": [
          "reference"
        ],
        "summary": "NMLP donor knowledge base index",
        "description": "Aggregated index of NMLP donor-knowledge reference content including condition grading guides for donors, donor archetypes, the donate-sell-recycle decision framework, and the donor glossary.",
        "operationId": "getKnowledge",
        "responses": {
          "200": {
            "description": "Knowledge base dataset",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {}
  }
}