Developers

JSON API

We run Little Outreach as a public directory backed by provenance and citations; this HTTP API is how you query and add that data from apps, automations, and agents. It is versioned under /api/v1. It powers search, profiles, organizations, memberships, places, aliases, and provenance-backed citations. Everything below is public — no account is required to read the spec or try read-only requests if you have a key.

Authentication

Send your API key on every request (same value everywhere):

  • Authorization: Bearer <your-api-key>
  • X-Api-Key: <your-api-key>

Keys are issued per user. Sign in from the header, then open Account to copy a key. Requests without a valid key receive 401 Unauthorized.

Credits & billing

Each /api/v1 request uses one credit (site admins are not metered). New accounts include 1,000 free credits. Responses include X-API-Credits-Remaining; at zero credits you receive 402 Payment Required. Call GET /api/v1/me to read your balance without spending a credit. After sign in, use Account to top up with Stripe when the operator has configured billing.

Adding a person

The directory is citation-backed, so every write needs a source reference. Pick the path that matches your situation — they all produce the same data.

Prefer a form to curl? Try the People playground — labelled fields for the same endpoint, no JSON typing required.

Option A — one call (recommended)

POST /api/v1/people/quick_add takes a flat body. Only first_name, last_name, and a citation signal are required.

curl -X POST https://www.littleoutreach.com/api/v1/people/quick_add \
  -H "Authorization: Bearer $LITTLE_OUTREACH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "first_name": "Ada",
    "last_name": "Lovelace",
    "email": "ada@example.com",
    "aliases": ["Ada L"],
    "linkedin_url": "https://www.linkedin.com/in/ada-lovelace",
    "source_url": "https://example.com/press/ada-joins",
    "source_category": "news"
  }'

Valid source_category values: social, news, organization, public_data, academic, legal, regulatory, website, database, broadcast, publication, communication, professional_directory, survey, internal.

Add organization_public_id (plus optional role, title, start_date) and the membership is created in the same transaction — no follow-up call needed. The response includes both person and membership.

Option B — canonical POST /api/v1/people

Use this when you want the full feature surface: setting public_id, birthday, description, or crafting nested citations by hand. The canonical shape uses a person wrapper plus a source_reference sibling.

curl -X POST https://www.littleoutreach.com/api/v1/people \
  -H "Authorization: Bearer $LITTLE_OUTREACH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "person": {
      "first_name": "Ada",
      "last_name": "Lovelace",
      "linkedin_url": "https://www.linkedin.com/in/ada-lovelace",
      "aliases": ["Ada L"],
      "emails": ["ada@example.com"]
    },
    "source_reference": {
      "source_category": "social",
      "url": "https://www.linkedin.com/in/ada-lovelace",
      "title": "LinkedIn profile"
    }
  }'

Friendlier aliases that the endpoint accepts:

  • source or citation in place of source_reference.
  • category in place of source_category inside the citation.
  • Flat top-level fields — skip the person: wrapper entirely and send first_name / last_name at the root.
  • emails and aliases arrays (strings or objects) rewrite to Rails-nested attributes server-side.

Adding a person to an organization

In two separate calls:

  1. Find or create the organization: GET /api/v1/organizations?domain=acme.com, or POST /api/v1/organizations when it doesn't exist.
  2. Create the person with the membership in one call: POST /api/v1/people/quick_add with organization_public_id. Or keep them separate with POST /api/v1/people + POST /api/v1/memberships.

When things go wrong

  • 400 provenance_required — include a citation. The response body's details.expected shows the exact shape plus the accepted aliases.
  • 403 forbidden — the API key is read-only. Ask a site admin to grant can_edit before retrying.
  • 422 unprocessable_entity — validation failed (e.g. the email is already on another record). Inspect details.messages and details.field_errors.

Adding an organization

Organizations anchor memberships, places, and email patterns. Every write needs a source reference, but the shorthand keeps that boilerplate to a single URL.

Want to click through it instead of composing JSON? The Organizations playground wraps the same endpoint in a form.

Option A — one call (recommended)

POST /api/v1/organizations/quick_add takes a flat body. Only name, domain, organization_type, and a citation signal are required.

curl -X POST https://www.littleoutreach.com/api/v1/organizations/quick_add \
  -H "Authorization: Bearer $LITTLE_OUTREACH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Analytical Engine Ltd.",
    "domain": "analyticalengine.example.com",
    "organization_type": "company",
    "aliases": ["AEL"],
    "source_url": "https://analyticalengine.example.com/about",
    "source_category": "organization"
  }'

Pass a nested person block (with optional role, title, start_date, email) to bootstrap the first member in the same transaction. The response includes organization, person, and membership:

curl -X POST https://www.littleoutreach.com/api/v1/organizations/quick_add \
  -H "Authorization: Bearer $LITTLE_OUTREACH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Analytical Engine Ltd.",
    "domain": "analyticalengine.example.com",
    "organization_type": "company",
    "source_url": "https://analyticalengine.example.com/about",
    "person": {
      "first_name": "Ada",
      "last_name": "Lovelace",
      "email": "ada@analyticalengine.example.com",
      "role": "founder",
      "title": "Chief Analytical Officer",
      "start_date": "1843-10-01"
    }
  }'

Option B — canonical POST /api/v1/organizations

Use this when you want the full feature surface: parent_organization_public_id, email_local_part_pattern, or hand-crafted citations. The canonical shape uses an organization wrapper plus a source_reference sibling.

curl -X POST https://www.littleoutreach.com/api/v1/organizations \
  -H "Authorization: Bearer $LITTLE_OUTREACH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "organization": {
      "name": "Analytical Engine Ltd.",
      "domain": "analyticalengine.example.com",
      "organization_type": "company",
      "description": "Mechanical computing pioneers.",
      "aliases": ["AEL"]
    },
    "source_reference": {
      "source_category": "website",
      "url": "https://analyticalengine.example.com/about",
      "title": "About us"
    }
  }'

Friendlier aliases that the endpoint accepts:

  • source or citation in place of source_reference.
  • category in place of source_category inside the citation.
  • Flat top-level fields — skip the organization: wrapper and send name / domain / organization_type at the root.
  • aliases (or name_aliases) and emails arrays rewrite to Rails-nested attributes server-side.
  • /api/v1/advertisers is a drop-in alias — same behaviour, JSON uses advertiser / advertisers keys instead.

Before you create — check for duplicates

Domains are unique. A quick lookup avoids a 422 round-trip and keeps the directory clean:

curl https://www.littleoutreach.com/api/v1/organizations?domain=analyticalengine.example.com \
  -H "Authorization: Bearer $LITTLE_OUTREACH_API_KEY"

An empty result queues the domain for research automatically. If a result comes back, reuse its public_id with POST /api/v1/people/quick_add or POST /api/v1/memberships.

When things go wrong

  • 400 provenance_required — include a citation. The response body's details.expected shows the exact shape plus accepted aliases.
  • 422 unprocessable_entity — the domain is missing, isn't a public web hostname, or is already taken. Inspect details.field_errors for the specific field.
  • 403 forbidden — the API key is read-only. Ask a site admin to grant can_edit before retrying.

Adding data (agents & automations)

Independent agents and integrations populate the directory by calling POST and PATCH under /api/v1. Use an API key with can_edit. Most creates require a nested source_reference (citation URL + category)—see Writes & provenance and the OpenAPI schemas.

Suggested flow

  1. Optional: Unified search (GET) to avoid duplicate people or orgs.
  2. Create or update people and organizations (order can swap if you already have ids).
  3. Add memberships to link a person to an organization.
  4. Add places, name aliases, and source references as needed.

All write operations

Updates and deletes, plus every mutating method, in resource order—use when fixing or removing data.

Method Operation Path Open in Swagger
POST Create person /api/v1/people Open
POST Quick add person /api/v1/people/quick_add Open
PATCH Update person /api/v1/people/{public_id} Open
POST Create organization /api/v1/organizations Open
POST Quick add organization /api/v1/organizations/quick_add Open
PATCH Update organization /api/v1/organizations/{public_id} Open
POST Create membership /api/v1/memberships Open
PATCH Update membership /api/v1/memberships/{public_id} Open
DELETE Delete membership /api/v1/memberships/{public_id} Open
POST Create place /api/v1/places Open
PATCH Update place /api/v1/places/{public_id} Open
DELETE Delete place /api/v1/places/{public_id} Open
POST Create name alias /api/v1/name_aliases Open
PATCH Update name alias /api/v1/name_aliases/{public_id} Open
DELETE Delete name alias /api/v1/name_aliases/{public_id} Open
POST Create source reference /api/v1/source_references Open
PATCH Update source reference /api/v1/source_references/{public_id} Open
DELETE Delete source reference /api/v1/source_references/{public_id} Open
PATCH Update (mark complete or reopen) /api/v1/zero_result_searches/{id} Open

Reference

Writes & provenance

Creating or updating most records requires a source reference (citation): source_category, a valid http(s) URL, and optional metadata. Mutating methods need an API key with can_edit. The full rules and request shapes are in the OpenAPI document.

Frequently asked questions

What is the base URL for the Little Outreach JSON API?
All endpoints live under /api/v1 on the same host as the web app (unless your deployment documents a different base).
How do I authenticate API requests?
Send your per-user API key on every request as Authorization: Bearer <key> or duplicate the same value in X-Api-Key. Sign in, then use the API key link on your Account page to copy a key. Missing or invalid keys receive 401 Unauthorized.
Where is the machine-readable API specification?
The OpenAPI 3 document is at /api-docs/v1/swagger.yaml. Browse and try operations in Swagger UI or the API playground.
Which requests require an editor (write) API key?
POST, PATCH, PUT, and DELETE that change data require an API key with can_edit. Read-only keys still work for GET where the API allows it.

MCP & tools

For Claude Desktop, OpenClaw, or other MCP clients, see MCP server setup.

Endpoint reference

Each HTTP method and path has its own page with a stable URL, unique title, meta description, and structured data—so search engines and assistants can point to a specific operation.

Account

Lookups

Memberships

Name aliases

Organizations

People

Places

Search

Source references

Zero-result searches