API reference

Company Intel API

Post a domain, get a firmographic dossier where every field carries the live URL it was read from. One synchronous call, JSON in and out. Three rails share one meter: 12 Ounie credits per dossier on REST and MCP, $0.144 USDC per dossier keyless over x402.

Quickstart

curl -X POST https://company.ounie.com/api/dossiers \
  -H "Authorization: Bearer cin_live_…" \
  -H "Content-Type: application/json" \
  -d '{"domain":"stripe.com"}'

The dossier comes back on the same request — expect 15–45 seconds, since it renders up to 5 pages. There is no job to poll.

Authentication

Three credentials work, in this order of precedence. Every one of them spends the same Ounie wallet, and none of them can overdraw it: a caller short on credits gets a 402 naming the shortfall, never a silent debt.

  • Session cookie. The shared .ounie.com cookie. This is what the dashboard uses; you get it by signing in.
  • App key. Authorization: Bearer cin_live_…, minted at /dashboard/api-keys. Five active per account; only its hash is stored, so the token is shown once.
  • Fleet master key. Your ounie.com ounie_live_… developer key, if you have turned on “Use across Ounie apps” in your ounie.com settings. One key for every Ounie app.
Hosts that cannot set an Authorization header — the Ounie AI Team’s manual MCP entry, for one — can pass ?api_key=cin_live_… on the URL instead. It works on every REST route and on the MCP transport.

POST /api/dossiers

Build one dossier. Costs 12 credits; thin results refund in full.

FieldTypeNotes
domainstring, requiredA bare domain or a full URL. url is accepted as an alias.
sectionsstring[], optionalAny of identity, size, stack, funding, contact. Narrows the fetches, so it returns faster. The price is the same.
recency_daysinteger, optionalOnly count funding and news coverage published in this window. Max 1825.
An unknown sections value, a malformed domain, an IP literal, a non-standard port, or a hostname that resolves to a private network all return 400 before any work happens. Nothing is reserved and nothing is charged.

The response

{
  "ok": true,
  "dossier": {
    "id": "…", "domain": "stripe.com", "status": "succeeded",

    "name": "Stripe",
    "name_source": "https://stripe.com/",
    "description": "Stripe is a financial infrastructure platform…",
    "description_source": "https://stripe.com/",
    "description_derived": false,          // false = the site's own meta description
    "industry": "payments infrastructure",
    "industry_evidence": { "quote": "…", "source": "https://stripe.com/" },

    "size_signals": {
      "headcount_hints": [ { "text": "…", "source": "https://…/about" } ],
      "careers_open_roles": 214,           // null when we could not tell
      "careers_source": "https://…/jobs"
    },
    "socials": { "linkedin": "…", "x": "…", "github": "…" },
    "tech_stack": [
      { "name": "Cloudflare", "category": "CDN",
        "evidence": "server: cloudflare", "kind": "header",
        "source": "https://stripe.com/" }
    ],
    "funding_mentions": [
      { "title": "…", "url": "https://…", "date": "2025-06-10", "quote": "…" }
    ],
    "key_pages": [ { "path": "/", "url": "https://…", "title": "…", "words": 1420 } ],
    "contact_surface": {
      "emails":    [ { "value": "…", "source": "https://…" } ],
      "phones":    [ { "value": "…", "source": "https://…" } ],
      "addresses": [ { "value": "…", "source": "https://…" } ]
    },

    "confidence": 0.85,      // how much RESOLVED, not how likely it is right
    "signals": 8,            // of nine signal groups
    "pages_fetched": 5,
    "dropped_claims": 1,     // model claims deleted for lacking a source
    "thin": false,
    "credits_spent": 12
  }
}
  • An absent field is null or an empty array. It is never filled with a plausible value. Treat it as “not published”.
  • careers_open_roles is null, not zero, when we could not tell. Zero would be a claim we cannot support.
  • confidence measures coverage. It is the weighted share of the nine signal groups that resolved — a deterministic function of what was found, not a probability that the dossier is correct.

The sourcing contract

This is the part worth reading before you trust the output. The dossier is built two different ways, and the difference matters.

Produced byFieldsGuarantee
reademails, phones, socials, tech stack, live job links, key pagesRead out of the fetched pages with regular expressions and header inspection. Each value is a substring of something we downloaded, or the literal header line that produced it. No model is involved.
modelname, description, industry, headcount phrasing, postal addressesProduced by a model from the fetched pages only, then source-checked: each claim must arrive with a verbatim quote, and that quote must be found in the pages. A claim that fails is DELETED and counted in dropped_claims.
The tech stack deliberately ignores the Content-Security-Policy header. A CSP lists every host a site is permitted to contact, not one it uses — mining it yields a long, confident stack for tools the company has never touched.

Sections and what each contains: IdentityName, one-line description and industry, each traced to the page it was read from. Size signalsHeadcount phrasing the company published about itself, plus a count of live job links. Tech stackTechnologies inferred from response headers and the assets the page actually loads. Funding & newsFunding and acquisition mentions from published articles, each with a dated quote. Contact surfaceEmails, phones, postal addresses and social profiles found on the pages fetched.

Thin results & refunds

A dossier is thin when no page rendered at all, or when fewer than two of the nine signal groups resolved. A parked domain, a holding splash, a name registered and never used.

  • On the credit rails, a thin dossier settles at 0 and the whole reserve is refunded to the exact pools it came from. The row is stored with status: "refunded" so you can still see what was attempted.
  • On x402, a thin dossier returns 402 thin_result and the payment is never settled. An on-chain payment has no refund path, so the check happens before the money moves.
  • A very SPARSE dossier is not thin. A local business with a name, a phone number and a stack is a real answer about a real company, and it bills.

Reading past dossiers

Free forever — these are reads of work you already paid for.

GET /api/dossiers?limit=20&domain=stripe.com
GET /api/dossiers/<id>
GET /api/credits                 # your spendable Ounie credits
GET /api/pricing                 # public: price, sections, x402 endpoint

MCP

A Streamable HTTP MCP server, plus legacy SSE. Works in Claude, Cursor, ChatGPT, the AI SDK and the Ounie AI Team.

Endpoint  https://company.ounie.com/api/mcp
Legacy    https://company.ounie.com/api/sse
Auth      Authorization: Bearer cin_live_…
          …or ?api_key=cin_live_…  for hosts that can't set headers
ToolCostWhat it does
build_company_dossier12 crResearch a company from its domain. Thin refunds in full.
get_dossierfreeRe-read one you already built, by id.
list_dossiersfreeYour history, newest first, filterable by domain.
get_dossier_schemafree, publicThe sections and the sourcing rules the output obeys.
get_credit_balancefreeSpendable Ounie credits.
get_pricingfree, publicCredit price and the x402 endpoint.
whoamifreeThe authenticated key's owner and key id.

x402 — keyless, pay per call

No account, no key. Pay $0.144 in USDC on Base. Two refusal gates protect the caller, and the order is deliberate.

POST https://company.ounie.com/api/x402/dossier
{"domain":"stripe.com"}

# Gate 1 — a request we can never serve is refused for FREE, before a quote:
#   400 invalid_request       malformed domain, IP literal, port, private network
#   400 domain_unresolvable   the name does not resolve
#   400 invalid_section       unknown value in sections[]

# Otherwise: 402 with the terms
{ "x402Version": 1,
  "accepts": [{ "scheme": "exact", "network": "base",
                "maxAmountRequired": "144000",
                "payTo": "0x…", "asset": "0x833589fCD…",
                "extra": { "name": "USD Coin", "version": "2" } }] }

# Sign an EIP-3009 authorization and retry:
POST https://company.ounie.com/api/x402/dossier
X-Payment: <base64 payload>

# Gate 2 — verified, run, and only THEN settled. Nothing to sell:
#   402 thin_result           your payment was NOT settled
The network is the bare name base, not eip155:8453 — under x402 the naming scheme selects the protocol version, and this is a v1 offer. The extra block states the USDC EIP-712 domain so your signature does not revert on chain after the money is committed.

Errors

StatusErrorMeaning
400domain_requiredNo domain or url in the body.
400invalid_requestMalformed host, IP literal, non-standard port, credentials in the URL, or a host that resolves to a private network.
400domain_unresolvableThe hostname does not resolve. Refused for free.
400invalid_sectionUnknown value in sections[].
401unauthorizedNo usable cookie or bearer key.
402insufficient_creditsCarries required_credits, balance_credits and buy_credits_url. Nothing was reserved.
402thin_resultx402 only: nothing usable resolved, so the payment was not settled.
429too_many_runningMore than 5 dossiers in flight for one account.
502dossier_failedAn upstream broke. You were refunded and not charged.
503service_unavailableResearch is temporarily unavailable. Nothing was charged.

Limits

LimitValue
Price12 credits per dossier · $0.144 USDC over x402
Pages fetched5 per dossier (homepage + four candidates)
Concurrent dossiers5 per account
Active API keys5 per account
Recency window1825 days
Free foreverReading, listing and exporting dossiers you already paid for

Credits are shared across every Ounie app and bought at ounie.com.