Skip to content

Get started

Build with AI agents

llms.txt, Markdown pages and the OpenAPI spec for coding agents and assistants.

These docs are written to be read by coding agents and AI assistants as well as people. Give your agent one of these and it has everything it needs.

ResourceURLUse it for
llms.txtundefinedAn index of every docs page, with agent instructions at the top
llms-full.txtundefinedEvery page in one Markdown file
Page as Markdownadd .md to any docs URL, e.g. undefinedOne page, clean, for a context window
OpenAPI specundefinedGenerating a client or tool definitions; the source of truth

Every page also has a Copy page button that copies its Markdown.

Rules for an agent

  • Base URL https://api.tailend.dev; every endpoint is a GET.
  • Send X-API-Key on every request. Keep the key on the server, never in a prompt, a browser bundle or a URL.
  • Start with GET /v1/metros for the metro slug.
  • Branch on error.code, not the status. Both limits return 429: rate_limited can be retried after Retry-After, quota_exceeded cannot. See Errors.
  • An empty list is a real answer, not an error. On /around, check coverage before saying an area has nothing.

Which endpoint to give a tool

The user asksTool endpoint
"Find a swim class for my 6-year-old"undefined
"What's on this weekend?"undefined with from/to
"What's it like for families near this address?"undefined
"Is this a lively area?" (a number only)undefined

Example tool definition

A function-calling definition for the address search, ready for an Anthropic or OpenAI tool list. Your tool handler sends the arguments as query parameters to GET /v1/{metro}/around.

JSON
{
  "name": "search_around_address",
  "description": "Search an address and get back what is around it for families: dated events, weekly programs, classes, camps and places, grouped and ranked, each with its distance in metres and walking minutes. Also returns a 0-100 activity score, counts for filtering, and a coverage block saying how many nearby listings cannot be placed on the map.",
  "input_schema": {
    "type": "object",
    "properties": {
      "metro": { "type": "string", "default": "philadelphia" },
      "address": { "type": "string", "maxLength": 300, "description": "Street address to search around. Give this OR lat+lng, not both." },
      "lat": { "type": "number", "minimum": -90, "maximum": 90 },
      "lng": { "type": "number", "minimum": -180, "maximum": 180 },
      "radius_m": { "type": "integer", "minimum": 100, "maximum": 8000, "default": 1600, "description": "1600 is about a mile, walking distance for a family." },
      "from": { "type": "string", "description": "YYYY-MM-DD in the metro's timezone. Defaults to today." },
      "to": { "type": "string", "description": "YYYY-MM-DD, inclusive. Defaults to from + 30 days." },
      "ages": { "type": "array", "items": { "type": "string", "enum": ["baby", "toddler", "young_kids", "bigger_kids"] } },
      "free": { "type": "boolean" },
      "types": { "type": "array", "items": { "type": "string", "enum": ["event", "class", "camp", "place"] } },
      "limit": { "type": "integer", "minimum": 1, "maximum": 50, "default": 10, "description": "Per group, not per response." }
    },
    "required": ["metro"]
  }
}

Prefer lat/lng when your app already has coordinates: address lookups have their own usage limits, and the coordinate form always works.