Developers

API reference

Deterministic startup-equity math over HTTP: convert SAFEs, model rounds, compute dilution and run exit waterfalls. Single API key, structured JSON errors, idempotent retries. This page is written to be a complete onboarding for a developer or an AI agent — no other docs required.

Base URL: https://foundily.com/api/v1Content-Type: application/json

Authentication

Every request (except the discovery index and OpenAPI manifest) requires a single API key, sent as a bearer token. Create one from /dashboard/api-keys.

text
Authorization: Bearer fd_live_...

A missing or invalid key returns 401 authentication_error. Keys are prefixed fd_live_... or fd_test_... — see “Safe by default” below.

Making a request

Every endpoint is a POST that accepts a JSON body and returns { data, request_id } on success. Every response — success or error — carries an x-request-id header you can use to reference a specific call in support requests.

cURL
curl -X POST https://foundily.com/api/v1/safe/convert \
  -H "Authorization: Bearer fd_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 3f1c2e9a-..." \
  -d '{
    "safe":  { "investment": 200000, "valuationCap": 4000000 },
    "round": { "preMoney": 16000000, "investment": 4000000 }
  }'
JavaScript (fetch)
const res = await fetch("https://foundily.com/api/v1/safe/convert", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.FOUNDILY_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: JSON.stringify({
    safe: { investment: 200_000, valuationCap: 4_000_000 },
    round: { preMoney: 16_000_000, investment: 4_000_000 },
  }),
});
const { data, request_id } = await res.json();

Endpoints

POST/safe/convert

Convert a single SAFE (or convertible note) at a priced round.

ParamTypeDescription
safe*SafeThe SAFE terms — investment, valuationCap, discount, type.
round*PricedRoundThe priced round the SAFE converts at — preMoney, investment.
preRoundFullyDilutedSharesnumberCompany's pre-round FD share count. Defaults to 10,000,000.
existingPoolSharesnumberShares already reserved in the option pool before the round.
Request
curl -X POST https://foundily.com/api/v1/safe/convert \
  -H "Authorization: Bearer fd_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "safe":  { "investment": 200000, "valuationCap": 4000000, "type": "post" },
    "round": { "preMoney": 16000000, "investment": 4000000 },
    "preRoundFullyDilutedShares": 8000000
  }'
Response — 200 OK
{
  "data": {
    "shares": 421053,
    "ownership": 0.04,
    "pricePerShare": 1.9,
    "method": "cap",
    "effectiveValuation": 4000000,
    "roundPricePerShare": 1.9,
    "capTable": { "rows": [ /* full post-round cap table */ ], "totalShares": 10526316 }
  },
  "request_id": "req_9Xn2kP..."
}
POST/rounds/model

Model a priced round: SAFE/note conversion plus an option-pool top-up.

ParamTypeDescription
founders*Holder[]Pre-round common holders — name + shares.
optionPoolSharesnumberExisting option-pool shares before the round. Default 0.
safesSafe[]SAFEs/notes converting alongside the round. Default [].
round*PricedRoundpreMoney, investment, targetOptionPool, and preferred terms.
Request
curl -X POST https://foundily.com/api/v1/rounds/model \
  -H "Authorization: Bearer fd_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "founders": [{ "name": "Founders", "shares": 9000000 }],
    "optionPoolShares": 0,
    "safes": [],
    "round": {
      "name": "Series Seed", "preMoney": 8000000, "investment": 2000000,
      "targetOptionPool": 0.10
    }
  }'
Response — 200 OK
{
  "data": {
    "rows": [
      { "name": "Founders", "security": "common", "shares": 9000000, "ownership": 0.70 },
      { "name": "Option Pool", "security": "option", "shares": 1285714, "ownership": 0.10 },
      { "name": "Series Seed", "security": "preferred", "shares": 2571429, "ownership": 0.20,
        "pricePerShare": 0.7778, "invested": 2000000 }
    ],
    "totalShares": 12857143,
    "pricePerShare": 0.7778,
    "optionPoolShares": 1285714,
    "newInvestorShares": 2571429
  },
  "request_id": "req_9Xn2kP..."
}
POST/dilution

Run a multi-round dilution scenario across SAFEs and priced rounds.

ParamTypeDescription
founders*Holder[]Initial common holders.
optionPoolSharesnumberInitial option-pool shares. Default 0.
events*ScenarioEvent[]Ordered list of { kind: "safe", safe } or { kind: "round", round } events.
Request
curl -X POST https://foundily.com/api/v1/dilution \
  -H "Authorization: Bearer fd_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "founders": [{ "name": "Founders", "shares": 8000000 }],
    "events": [
      { "kind": "safe", "safe": { "name": "Pre-seed SAFE", "investment": 200000, "valuationCap": 4000000 } },
      { "kind": "round", "round": { "name": "Series A", "preMoney": 16000000, "investment": 4000000 } }
    ]
  }'
Response — 200 OK
{
  "data": {
    "stages": [ { "label": "Series A", "capTable": { /* cap table */ }, "pricePerShare": 1.9 } ],
    "final": { "rows": [ /* final cap table rows */ ], "totalShares": 10526316 },
    "founderTrail": [ { "label": "Series A", "ownership": 0.76 } ]
  },
  "request_id": "req_9Xn2kP..."
}
POST/waterfall

Compute an exit / liquidation waterfall across preferred series.

ParamTypeDescription
exitValue*numberTotal exit / sale proceeds.
commonShares*numberCommon shares outstanding.
optionSharesnumberOption-pool shares participating in the residual.
series*WaterfallSeries[]Preferred series — invested, shares, liquidationMultiple, participating, participationCap, seniority.
Request
curl -X POST https://foundily.com/api/v1/waterfall \
  -H "Authorization: Bearer fd_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "exitValue": 40000000,
    "commonShares": 6000000,
    "series": [
      { "name": "Series A", "invested": 3000000, "shares": 2000000,
        "liquidationMultiple": 1, "participating": false, "seniority": 1 },
      { "name": "Series B", "invested": 5000000, "shares": 3000000,
        "liquidationMultiple": 1, "participating": true, "seniority": 2 }
    ]
  }'
Response — 200 OK
{
  "data": {
    "payouts": [
      { "name": "Common", "security": "common", "proceeds": 19090909, "shares": 6000000 },
      { "name": "Series A", "security": "preferred", "converted": true,
        "proceeds": 6363636, "multiple": 2.12, "shares": 2000000 },
      { "name": "Series B", "security": "preferred", "converted": false,
        "proceeds": 14545455, "multiple": 2.91, "shares": 3000000 }
    ],
    "exitValue": 40000000,
    "totalDistributed": 40000000
  },
  "request_id": "req_9Xn2kP..."
}

Errors

Errors are structured JSON with a stable, machine-parseable error.type — never scrape the human-readable message.

Error shape
{
  "error": {
    "type": "invalid_request",
    "message": "Expected number, received string",
    "param": "safe.investment",
    "docs": "/docs/api#errors"
  },
  "request_id": "req_9Xn2kP..."
}
error.typeHTTP statusWhen it happens
invalid_request400The request body failed validation — check the error's `param` field for which one.
authentication_error401Missing, malformed, or revoked API key.
not_found404The requested resource doesn't exist.
rate_limit_exceeded429Monthly request quota reached (free tier hard-caps; Pro overages bill per call instead).
server_error500Something failed on our end. Safe to retry with the same Idempotency-Key.

Rate limits & quotas

Every response carries x-ratelimit-limit and x-ratelimit-remaining, reflecting your plan's monthly quota. Free hard-caps at quota (429 rate_limit_exceeded); Pro continues past its included quota at $0.01/call.

PlanIncluded / monthOver quota
Free100Hard cap — 429 until next month
Pro10,000$0.01/call, billed monthly

Idempotency

Send an Idempotency-Key header (any unique string — a UUID works well) to make retries safe. If you retry the same request with the same key, Foundily replays the original response instead of recomputing it, and marks it with an idempotent-replayed: true response header. Since every calculation here is deterministic, replays cost nothing extra against your quota.

Discovery for agents

Three machine-readable entry points, so an agent can self-onboard without a human reading this page:

  • GET https://foundily.com/api/v1 — API index: endpoints, auth, and machine-readable pricing.
  • GET https://foundily.com/api/v1/openapi.json — full OpenAPI 3.1 manifest.
  • GET https://foundily.com/llms.txt — plain-text onboarding for LLMs.
  • MCP servernpx @foundily/mcp, four tools, zero HTTP code required.

Safe by default

Every key is prefixed fd_live_... or fd_test_...— visible at a glance in your dashboard, your logs, and this page's samples — so a key pasted into an agent prompt or a shared snippet is never ambiguous about which environment it belongs to. Every endpoint is a pure function over its input: there is no destructive action to gate behind confirmation, and the same request with the same body always produces the same numbers, live or test.