Skip to main content

Developer guide

API and MCP

Read your cap table, your documents, and your own holdings from a script, or from an AI assistant. One personal key authenticates both the REST API and the MCP server. Every surface is read only.

A key carries your own access and nothing more. In each organization it gets the role you already hold. It also reads your own holder portfolio. No key can record a transaction, change a setting, read the audit log, or open the diligence bundle.

Create a key

Authentication

Create a key on the personal API keys page. We show the key once. Copy it, then store it in a password manager or a secret manager. We keep only the SHA-256 hash of the key, so we cannot show it again.

Send the key in the Authorization header on every request:

curl -H "Authorization: Bearer cdu_..." \
  https://capdaddy.cc/api/v1/me

Revoke a key at any time on the same page. Revocation takes effect on the next request. Your role is resolved again on every request, so a role change applies immediately.

Endpoints

Replace {org} with the organization id from /api/v1/orgs. The role column is the role you need in that organization.

EndpointRoleWhat it returns
GET /api/v1/meAny keyYour identity, your organizations, and your holder organizations.
GET /api/v1/orgsAny keyThe organizations this key can read, each with your role.
GET /api/v1/orgs/{org}/captableViewerThe cap table as of a date, by class and by stakeholder.
GET /api/v1/orgs/{org}/stakeholdersViewerThe stakeholder directory.
GET /api/v1/orgs/{org}/stakeholders/{id}ViewerOne stakeholder with their holdings.
GET /api/v1/orgs/{org}/securitiesViewerEvery security with its resolved totals.
GET /api/v1/orgs/{org}/securities/{id}ViewerOne security with its vesting and lifecycle detail.
GET /api/v1/orgs/{org}/registerViewerThe securities register: every security ever issued, with its consideration and disposition.
GET /api/v1/orgs/{org}/eventsViewerThe ledger event feed, oldest first. Bound it with from and to, then page with cursor. Convertible instrument events and organization-level override events need the admin role, and convertible instrument events also need the SAFEs and notes feature.
GET /api/v1/orgs/{org}/documentsViewerThe document index. Filter it with stakeholderId.
GET /api/v1/orgs/{org}/documents/{id}/downloadViewerThe bytes of one document.
GET /api/v1/orgs/{org}/consentsViewerBoard and stockholder consents with their status.
GET /api/v1/orgs/{org}/meetingsViewerBoard meetings with their minutes status.
GET /api/v1/orgs/{org}/convertiblesAdminEvery SAFE and convertible note, with live accrual on the outstanding ones. The asOf date sets the date interest is accrued to and hides an instrument issued after it, the status always describes the instrument today, and a date in the future answers 422.
GET /api/v1/orgs/{org}/roundsAdminThe fundraising rounds, with their terms and the capital each close banked.
GET /api/v1/orgs/{org}/complianceAdminThe compliance calendar: 409A, Rule 701, 83(b), exercise windows, and open tasks.
GET /api/v1/orgs/{org}/valuationsAdminThe 409A and fair market value history, newest effective date first.
GET /api/v1/orgs/{org}/searchViewerSearch people, securities, consents, and documents. Send q.
GET /api/v1/orgs/{org}/board/membersOwnerThe directors of record.
GET /api/v1/orgs/{org}/exports/{kind}ViewerOne export artifact. See the export kinds below.
GET /api/v1/portfolioHolderYour own holdings across every issuer, by your email.
GET /api/v1/portfolio/statementHolderYour own consolidated holder statement, as a PDF.

An organization manager can switch the member API off for their organization. The organization then disappears from your list, and its endpoints answer 404. Your own holder portfolio is not affected.

Parameters

NameValuesWhat it does
asOfYYYY-MM-DDThe legal as-of date, in America/New_York. It defaults to today. Cap table, securities, documents, compliance, convertibles, and exports accept it. The convertibles surface refuses a date in the future, because it reports interest accrued to that date.
modeeffective | recordedHow the ledger is replayed. "effective" uses legal dates. "recorded" uses recording times. It defaults to effective.
basisfullyDiluted | outstandingThe cap table basis. It defaults to fullyDiluted.
qtextThe search query. Send at least 2 characters. Longer queries are cut at 200 characters.
stakeholderIduuidLimits the document index to one stakeholder.
fromYYYY-MM-DDThe first effective date the event feed reports. Events on this date are included.
toYYYY-MM-DDThe last effective date the event feed reports. Events on this date are included.
kindscomma-separated listLimits the event feed to these event kinds. Send the values as one list, or repeat the parameter. An unknown kind answers 422, and the message names every kind the feed accepts. A kind your role or your plan does not cover also answers 422, and the message names what it needs.
limit1 to 1000How many events one page of the feed returns. It defaults to 200. A larger value is cut to 1000.
cursoropaque textThe next page of the event feed. Send back the nextCursor value from the previous reply. The reply sets truncated to true while pages remain.
curl -H "Authorization: Bearer cdu_..." \
  "https://capdaddy.cc/api/v1/orgs/<org>/captable?asOf=2026-06-30&basis=outstanding"

Numbers are strings

Every share count and every money amount crosses the wire as an exact decimal STRING. We never send a floating point number, because a float cannot hold a cent or a share exactly. Parse these values with a decimal library, or keep them as strings. Do not call parseFloat on them.

{
  "outstanding": "1750000",
  "fullyDiluted": "2431250",
  "pricePerShare": "1.2500000000"
}

Reading the values

Seven rules cover the fields that are easy to misread. Follow each one before you put a number in front of an investor.

Percentages are percent units
Every percentage is a decimal string in percent units, to six decimal places. The value"51.282051" means 51.282051 percent. It does not mean 0.51282051. Do not multiply it by 100 again.
Each holder carries two ownership percentages
pctOfBasisTotal divides by the total on the basis you asked for, so its numerator and its denominator always describe the same basis. pctOfAsConvertedFullyDiluted divides by the as-converted fully diluted total. Use the as-converted figure to compare holders across classes that convert at different ratios.
As-converted values are not share counts
asConvertedFullyDiluted restates a position in common-equivalent shares. It multiplies each class by that class conversion ratio, so the result can be fractional. Sum this column over every holder and you get the as-converted total exactly.
A null class term is not a zero
Each share class carries its economic terms: authorized shares, original issue price, conversion ratio, liquidation preference multiple, participation and its cap, dividend rate and type, anti-dilution method, seniority rank, and votes per share. A term the record does not hold comes back as null. Read a null as "not recorded". Never read it as zero.
A class with zero shares is still a class
The cap table lists every share class on the charter, including one the company has authorized but issued no shares of. That class reports zero for each quantity and carries its real terms. Report it as authorized and unissued. Never report it as a class that does not exist.
Derived consideration is not cash invested
The securities register reports the consideration for each security with a kind. A kind of derived means a transfer or a conversion minted the shares, so the holder paid the company nothing. Never add a derived amount into cash invested.
A SAFE accrues nothing
A SAFE has no maturity date and no interest, so its accrued interest is always "0". A note accrues interest, and the reply gives the interest to the report date plus the current balance. An instrument that already converted or was repaid reports null for both, because accrual stopped at that event.

Errors

StatusBodyWhat it means
200The JSON payload, or the file bytesThe read succeeded. Your reads are written to the organization audit log, with you as the actor and the key as the subject. The log records one entry for each hour in which you read a surface. It does not record one entry for each request. A file download and an export always record one entry for each access.
401{"error":"invalid_token"}The MCP server refused the request. Two causes give the same answer. First, the key is wrong, revoked, or expired. Second, too many MCP requests came from your address: the budget is 600 requests per hour, and over it the server answers 401, not 429. Check the key. If the key is good, wait, then retry. The REST endpoints are not affected: they answer 404 for a bad key and 429 over their own budget.
404{"error":"not_found"}One opaque answer for every miss: no key, a bad key, a revoked key, an expired key, an organization you are not a member of, a role below the endpoint, an organization that switched member API access off, a suspended organization, or an unknown record. The response never says which.
402{"error":"feature_locked","feature":"..."}You proved your membership, and the organization plan does not include this surface. Upgrade the plan, then retry.
422{"error":"<code>","message":"..."}The request was authorized, and the artifact could not be built. The code names the reason, for example OCF_NOT_CONFORMANT.
429{"error":"rate_limited"}Too many requests from your address. JSON reads allow 600 per hour. Exports allow 60 per hour. Each MCP tool call counts as one JSON read. Wait, then retry.

Export kinds

Request an export at /api/v1/orgs/{org}/exports/{kind}. The response is the file itself. Some kinds need a paid plan, and an unentitled request answers 402.

KindWhat it contains
cap-table.csvCap table totals by class and by stakeholder.
securities-ledger.csvEvery security with its per-instrument totals.
stakeholders.csvThe stakeholder directory.
securities-register.csvThe stock register, as CSV.
securities-register.pdfThe stock register, as a printable PDF.
captable-pdfA point-in-time cap table snapshot.
captable-xlsxThe cap table in the lawyer workbook format.
ledgers-xlsxThe securities, plan, and pool transaction ledgers.
ocfThe Open Cap Format package, validated against the official schemas.
backupThe full backup: documents, ledgers, OCF, and the cap table.
409a-package.zipThe 409A valuation data package.
minute-book.zipThe indexed corporate minute book.

The audit log and the diligence bundle are not on this list. Both need a fresh confirmation in the product, so no long lived key can reach them.

MCP server

The MCP server gives an AI assistant the same read tools, over the same key. Point your client at this URL and send your key in the Authorization header:

https://capdaddy.cc/api/mcp/mcp

Tools

Each tool reads one organization. Pass the organization id from list_orgs. A tool answers the text not_found for every miss, the same way the REST endpoints answer 404.

ToolRoleWhat it returns
whoamiAny keyYour identity, your organizations, and your holder organizations.
list_orgsAny keyThe organizations this key can read, each with your role.
get_cap_tableViewerThe cap table as of a date, by class and by stakeholder.
list_stakeholdersViewerThe stakeholder directory.
get_stakeholderViewerOne stakeholder with their holdings.
list_securitiesViewerEvery security with its resolved totals.
get_securityViewerOne security with its vesting and lifecycle detail.
get_registerViewerThe securities register: every security ever issued, with its consideration and disposition.
list_eventsViewerThe ledger event feed, oldest first. It answers what changed since a date. Convertible instrument events and organization-level override events need the admin role, and convertible instrument events also need the SAFEs and notes feature.
list_documentsViewerThe document index. It returns metadata only, never the file.
list_consentsViewerBoard and stockholder consents with their status.
list_meetingsViewerBoard meetings with their minutes status.
list_export_kindsViewerThe export catalog, with the REST address that serves each file.
searchViewerPeople, securities, consents, and documents that match your text.
list_convertiblesAdminEvery SAFE and convertible note, with live accrual on the outstanding ones. The asOf date sets the date interest is accrued to and hides an instrument issued after it, the status always describes the instrument today, and a date in the future is refused.
list_roundsAdminThe fundraising rounds, with their terms and the capital each close banked.
get_compliance_summaryAdminThe compliance calendar: 409A, Rule 701, 83(b), exercise windows, and open tasks.
list_valuationsAdminThe 409A and fair market value history, newest effective date first.
list_board_membersOwnerThe directors of record.
get_my_portfolioHolderYour own holdings across every issuer, by your email.

The MCP server sends text only. It never sends a file. Call list_export_kinds to learn which export files exist, then fetch the one you want from the REST endpoint with the same key. No tool writes data.

Claude Code

Run one command:

claude mcp add --transport http capdaddy https://capdaddy.cc/api/mcp/mcp \
  --header "Authorization: Bearer cdu_..."

Claude Desktop

Claude Desktop connects to a remote server through mcp-remote. Open Settings, then Developer, then Edit Config. Add this server, then restart Claude Desktop.

{
  "mcpServers": {
    "capdaddy": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://capdaddy.cc/api/mcp/mcp",
        "--header",
        "Authorization:${AUTH_HEADER}"
      ],
      "env": {
        "AUTH_HEADER": "Bearer cdu_..."
      }
    }
  }
}

Put your key in the env block, and leave no space after the colon in the header argument. On Windows, the client does not escape a space inside an argument, and a header written in one piece arrives broken.

Cursor

Add the server to .cursor/mcp.json in your project, or to ~/.cursor/mcp.json for every project.

{
  "mcpServers": {
    "capdaddy": {
      "url": "https://capdaddy.cc/api/mcp/mcp",
      "headers": {
        "Authorization": "Bearer cdu_..."
      }
    }
  }
}

VS Code

Add the server to .vscode/mcp.json, then start it from the editor.

{
  "servers": {
    "capdaddy": {
      "type": "http",
      "url": "https://capdaddy.cc/api/mcp/mcp",
      "headers": {
        "Authorization": "Bearer cdu_..."
      }
    }
  }
}

OpenCode

Add the server to opencode.json in your project, or to ~/.config/opencode/opencode.json for every project.

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "capdaddy": {
      "type": "remote",
      "url": "https://capdaddy.cc/api/mcp/mcp",
      "enabled": true,
      "oauth": false,
      "headers": { "Authorization": "Bearer cdu_..." }
    }
  }
}

Keep oauth set to false. OpenCode tries OAuth first on a remote server, and this server accepts a bearer key only.

OpenAI Codex CLI

Codex reads the key from an environment variable. Add this line to your shell profile, then open a new terminal.

export CAPDADDY_API_KEY="cdu_..."

Then add the server to ~/.codex/config.toml.

[mcp_servers.capdaddy]
url = "https://capdaddy.cc/api/mcp/mcp"
bearer_token_env_var = "CAPDADDY_API_KEY"

The config file holds the name of the variable, never the key itself.

The connectors on claude.ai need OAuth. This server authenticates with a bearer key, so the web connectors cannot use it yet. Use Claude Code, Claude Desktop, Cursor, VS Code, OpenCode, or the OpenAI Codex CLI.

Need a hand?

Tell us what you are building. We answer every message, usually within one business day. The rest of the product documentation lives in the help center.

[email protected]