Build your first FundOS app

A cross-module workflow: create a deal, attach a VDR room, register a webhook, upload a document, and receive the notification.

~15 minutes end-to-end

This quickstart uses three modules: CRM (the deal), VDR (the data room), and Webhooks (the notification). By the end you'll have a working pipeline that fires a webhook every time someone uploads a document to your deal room — the building block of any diligence automation.

1

Get an API key

Every request needs a Bearer token. Register once, reuse the key forever.

Visit kela.com/developers/register and create an account. Your key (starts with vdr_) appears on the dashboard — copy it now, it shows only once.

export FUNDOS_API_KEY=vdr_your_key_here

Add it to your shell profile (~/.zshenv for non-interactive shells) so it persists.

2

Create a deal in the CRM

The deal is the anchor. Every VDR room, transaction, and pricing model traces back to it.

Dry-run first (zero DB writes)

curl -X POST "https://kela.com/api/v1/fundos/crm/deals?ephemeral=true" \
  -H "Authorization: Bearer $FUNDOS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Acme Series B", "stage": "sourcing", "asset_class": "equity"}'

# → {"success": true, "data": {"id": null, "name": "Acme Series B", "stage": "sourcing"}}

Create for real

curl -X POST https://kela.com/api/v1/fundos/crm/deals \
  -H "Authorization: Bearer $FUNDOS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Acme Series B", "stage": "sourcing", "asset_class": "equity"}'

# → {"success": true, "data": {"id": 42, "name": "Acme Series B", "stage": "sourcing"}}

DEAL_ID=42
Tip: ?ephemeral=true validates your request body and returns the shape without writing anything. Always dry-run first.
3

Create a VDR room and link it to the deal

VDR rooms are how counterparties share documents. A deal gets its room via a Transaction — not a direct field.

Create the data room

curl -X POST https://kela.com/api/v1/rooms \
  -H "Authorization: Bearer $FUNDOS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Acme DD Room", "room_type": "company_investment"}'

# → {"success": true, "data": {"id": 12, "name": "Acme DD Room"}}

ROOM_ID=12

Create a Transaction to link them

curl -X POST https://kela.com/api/v1/fundos/transactions \
  -H "Authorization: Bearer $FUNDOS_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"name\": \"Acme Series B Closing\", \"deal_id\": $DEAL_ID}"

# Note the transaction id, then link the room:
TX_ID=9

curl -X PATCH "https://kela.com/api/v1/fundos/transactions/$TX_ID" \
  -H "Authorization: Bearer $FUNDOS_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"linked_room_id\": $ROOM_ID}"
Why a Transaction? A Deal has no direct room_id. The canonical join is Transaction.linked_room_id. Use GET /api/v1/fundos/transactions?deal_id={id} to find the room from a deal later.
4

Register a webhook for document.uploaded

Instead of polling every 5 minutes, let FundOS push to you the instant someone uploads a document.

For testing, use webhook.site — it gives you a free HTTPS endpoint that logs incoming requests. Copy your unique URL.

HOOK_URL="https://webhook.site/your-unique-id-here"

curl -X POST https://kela.com/api/v1/webhooks/ \
  -H "Authorization: Bearer $FUNDOS_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"url\": \"$HOOK_URL\",
    \"name\": \"Document alerts\",
    \"event_types\": [\"document.uploaded\"]
  }"

# → {"id": 1, "secret": "abc123...", "event_types": ["document.uploaded"]}
# Save the secret — verify signatures in production with HMAC-SHA256
Save the secret. It's returned only at registration time. In production, verify every incoming webhook: sha256=hmac(secret, raw_body) matches X-FundOS-Signature.
5

Upload a document to the room

This is the action that triggers the webhook. In production, counterparties upload via the FundOS UI — your app gets notified automatically.

# Create a test file
echo "Pitch deck placeholder" > pitch_deck.pdf

# Upload it
curl -X POST "https://kela.com/api/v1/rooms/$ROOM_ID/documents" \
  -H "Authorization: Bearer $FUNDOS_API_KEY" \
  -F "file=@pitch_deck.pdf"

# → {"success": true, "data": {"id": 88, "original_filename": "pitch_deck.pdf"}}
6

Receive the webhook notification

Switch to webhook.site — you'll see the payload arrive within ~2 seconds.

Open webhook.site in your browser. After uploading in Step 5, you should see a new request with this shape:

{
  "event": "document.uploaded",
  "version": "1.0",
  "delivery_id": "550e8400-e29b-41d4-a716-446655440000",
  "timestamp": "2026-06-12T10:00:00.000Z",
  "data": {
    "room_id": 12,
    "document_id": 88,
    "filename": "pitch_deck.pdf",
    "uploader_id": 1
  }
}

Use delivery_id to deduplicate retries. FundOS retries up to 6 times with exponential backoff if your endpoint doesn't respond 200.

You're done. You've connected 3 modules (CRM → Transaction → VDR) and built an event-driven pipeline in under 15 minutes.

What to build next

Now that you have the foundation, extend it:

Module guides


Module contract JSON  |  API Changelog  |  Developer Hub