Public HTTPS · No private SDK

Formation HTTP quickstart for outside agents

Discover the live catalog and formation OpenAPI, POST one qualification from operator-supplied conditions, stop on terminal outcomes, optionally prepare a provisional case, then hand the claim/review link to a human. Agents never claim, pay, or invent credentials.

Demonstrated case-qualified route: $399 plus state filing fees. EIN support can take 2–3 business days for qualifying cases; timing depends on the case and is not a universal guarantee. Not every business needs a US entity or EIN. Direct IRS EIN resources remain available.

Human surfaces (not SDKs): formation assessment · partner decision. This page invents no private package or unpublished npm client.

01 · Discover

Public catalog and formation OpenAPI

  • Service catalog (read-only GET): https://ein.llc/api/v1/service-catalog
  • Formation HTTP OpenAPI (assess, prepare, claim, review, grants, status): https://ein.llc/api/agent/v1/openapi.json
  • Catalog-only OpenAPI (does not describe formation mutations): https://ein.llc/openapi.json
ORIGIN=https://ein.llc
curl --fail-with-body -sS --max-time 15 "$ORIGIN/api/v1/service-catalog"
curl --fail-with-body -sS --max-time 15 "$ORIGIN/api/agent/v1/openapi.json"
const ORIGIN = process.env.ORIGIN || "https://ein.llc";
const ctrl = new AbortController();
const t = setTimeout(() => ctrl.abort(), 15_000);
const openapi = await fetch(`${ORIGIN}/api/agent/v1/openapi.json`, {
  signal: ctrl.signal,
});
clearTimeout(t);
if (!openapi.ok) throw new Error(`OpenAPI request failed: ${openapi.status}`);
console.log(openapi.status, await openapi.json());

02 · Qualify once

POST assessment from operator-supplied conditions

Anonymous POST /api/agent/v1/assessments accepts AssessmentInput fields only (non-sensitive): goal, hasUsEntity, hasEin, jurisdictionKnown, selectedState, providerRequiresUsEntity, providerRequiresEin, foreignOwnedCaution. Tri-state fields use yes / no / unknown. Never creates checkout.

Positive path (required_for_selected_path · offer llc-ein-399):

ORIGIN=https://ein.llc
curl --fail-with-body -sS --max-time 15 -X POST "$ORIGIN/api/agent/v1/assessments" \
  -H "content-type: application/json" \
  -d '{
    "goal": "Accept Stripe for a SaaS product",
    "hasUsEntity": "no",
    "hasEin": "no",
    "providerRequiresUsEntity": "yes",
    "providerRequiresEin": "yes",
    "selectedState": "Wyoming",
    "foreignOwnedCaution": false
  }'
const ORIGIN = process.env.ORIGIN || "https://ein.llc";
const ctrl = new AbortController();
const t = setTimeout(() => ctrl.abort(), 15_000);
const res = await fetch(`${ORIGIN}/api/agent/v1/assessments`, {
  method: "POST",
  headers: { "content-type": "application/json" },
  signal: ctrl.signal,
  body: JSON.stringify({
    goal: "Accept Stripe for a SaaS product",
    hasUsEntity: "no",
    hasEin: "no",
    providerRequiresUsEntity: "yes",
    providerRequiresEin: "yes",
    selectedState: "Wyoming",
    foreignOwnedCaution: false,
  }),
});
clearTimeout(t);
if (!res.ok) throw new Error(`Assessment request failed: ${res.status}`);
const body = await res.json();
console.log(res.status, body.assessment?.outcome, body.assessment?.offer?.serviceId);

Already satisfied (terminal — do not prepare):

ORIGIN=https://ein.llc
curl --fail-with-body -sS --max-time 15 -X POST "$ORIGIN/api/agent/v1/assessments" \
  -H "content-type: application/json" \
  -d '{
    "goal": "Continue an existing US business",
    "hasUsEntity": "yes",
    "hasEin": "yes"
  }'
const ORIGIN = process.env.ORIGIN || "https://ein.llc";
const ctrl = new AbortController();
const t = setTimeout(() => ctrl.abort(), 15_000);
const res = await fetch(`${ORIGIN}/api/agent/v1/assessments`, {
  method: "POST",
  headers: { "content-type": "application/json" },
  signal: ctrl.signal,
  body: JSON.stringify({
    goal: "Continue an existing US business",
    hasUsEntity: "yes",
    hasEin: "yes",
  }),
});
clearTimeout(t);
if (!res.ok) throw new Error(`Assessment request failed: ${res.status}`);
const body = await res.json();
console.log(res.status, body.assessment?.outcome, body.assessment?.offer);

03 · Stop outcomes

Terminal results — do not prepare

  • already_satisfied — entity and EIN already reported.
  • not_needed_now — existing capability covers the path.
  • insufficient_information — gather non-sensitive facts; uncertain stays uncertain.

The API refuses prepare for already_satisfied and not_needed_now. Treat all three as stops for agent automation.

04 · Optional provisional preparation

POST applications only when qualification continues

POST /api/agent/v1/applications creates a non-sensitive provisional case. No idempotency key — each call creates a new case. Supply intendedEmail for a claimable handoff. Missing or invalid email returns complete: false without a claim token. Preparation never approves or pays.

# WARNING: each successful call creates a NEW application. Prefer disposable ORIGIN.
ORIGIN=https://ein.llc
curl --fail-with-body -sS --max-time 15 -X POST "$ORIGIN/api/agent/v1/applications" \
  -H "content-type: application/json" \
  -d '{
    "intendedEmail": "owner@example.com",
    "preparation": {
      "goal": "Accept Stripe for a SaaS product",
      "jurisdiction": "Wyoming",
      "existingEntityStatus": "none",
      "assessmentOutcome": "required_for_selected_path",
      "providerPath": "stripe"
    }
  }'

05 · Human claim and review

Exact link shapes — humans claim; agents do not

  • reviewUrl: https://ein.llc/review/{applicationId} (path shape /review/{applicationId})
  • claimUrl: https://ein.llc/review/{applicationId}?claim={claimToken}
  • Partner decision (human confirm scope): https://ein.llc/agents/partner-decision

The intended human signs in with a verified Firebase email matching intendedEmail, claims if needed, completes confidential intake, and pays only through existing merchant checkout after review. Agents do not claim.

06 · Scoped status after a human grant

GET status only with Bearer AgentGrant

After the human issues a revocable status grant (POST .../grants with Firebase auth), the agent may call GET /api/agent/v1/applications/{applicationId}/status with Authorization: Bearer <AgentGrant>. Status is redacted: no passport, SSN, EIN digits, or document URLs. Payment is not EIN issued.

ORIGIN=https://ein.llc
APPLICATION_ID=app_example
AGENT_GRANT=replace-with-human-issued-grant
curl --fail-with-body -sS --max-time 15 \
  -H "Authorization: Bearer $AGENT_GRANT" \
  "$ORIGIN/api/agent/v1/applications/$APPLICATION_ID/status"

Boundaries

  • No private repo paths, no private activation-client packages, and no unpublished npm client.
  • No new auth mechanism on this page — use the published OpenAPI security schemes.
  • Do not create production prepare/claim/pay traffic as QA; use a disposable local origin for mutate examples.
  • Offer id when present: llc-ein-399 · $399 + state filing fees · 2–3-business-day EIN route for qualifying cases.