Skip to main content
The Caplia Venture Form Widget is a single block of HTML you paste into your existing application form. Entrants pick a PDF, the widget uploads it directly to Caplia, and writes the resulting job ID into a hidden form field that flows on to your CRM (HubSpot, Salesforce, anywhere). No backend changes on your side, no API key in the browser. Built for any public form where the entrant uploads a pitch deck.

Who it’s for

Venture funds

Your fund’s public “submit your deck” form. Cold inbound lands in Caplia pre-scored, sorted by CRI quality and thesis fit, ready for partner review.

Accelerators

Cohort application forms. Every submitted deck is scored on arrival; selection committees see a ranked shortlist instead of a Google Drive folder.

Awards programmes

Innovation award entries, pitch competitions, founder prizes. Judges work from CRI scores and per-category thesis fit instead of reading every deck cold.

Corporate development

Partnership intake forms. Inbound startup approaches are scored against your strategic thesis automatically before a BD lead picks them up.

How it works

1

Entrant picks a PDF

The widget renders a styled “Choose pitch deck” button inside your existing form. It enforces PDF-only, 50 MB max, client-side and server-side.
2

Widget mints a one-shot upload token

A POST /v1/uploads/sign call returns a cap_upload_<jwt> token — 5-minute TTL, single-use, signed server-side. No long-lived API key in the browser.
3

Widget uploads the PDF to Caplia

The PDF posts to POST /v1/uploads/decks with the token. Caplia queues the deck for scoring (CRI quality score + thesis-fit) and returns a job_id.
4

The job ID flows on to your CRM

The widget writes the job_id into a hidden input named caplia_job_id. When the entrant submits the rest of the form, that ID lands in HubSpot (or wherever) alongside their other fields.
5

Scoring lands in your Caplia dashboard

The deck is processed asynchronously. Once scored, the entry appears in your Caplia pipeline with CRI score, per-thesis fit, and is queryable by the application ID you supplied.

Onboarding

Before pasting the widget, get a form_id from your Caplia contact (Connor, or paul@caplia.ai). It’s an opaque string like acme-2026 or fund-x-inbound that maps to your team and the user submissions land under. We allowlist it server-side in the same step.

The snippet

Paste this whole block into a single Webflow Embed element (or any HTML container that allows inline <script>) placed inside your application form, where your “deck URL” field used to be.

Configuration

Three data attributes on the root <div>:

Fields the widget writes

Make sure your form has two corresponding fields (they can be hidden — the widget creates them if missing in pure HTML, but in Webflow you’ll want to declare them so HubSpot can map them):

Webflow setup

1

Add an Embed element to your form

In the Webflow designer, drop a Code Embed component inside the Form block, where your old “deck URL” field used to be.
2

Paste the widget

Paste the snippet above into the Embed. Replace REPLACE_WITH_FORM_ID with the form_id Caplia gave you.
3

Set the application-id field name

Change data-application-id-field="application_number" to whatever the name of your existing Application Number / Candidate ID field is. (Right-click the field in Webflow → Settings → Name.)
4

Add hidden form fields for the widget's outputs

Add two Form components inside the same form, type “Text”, with names caplia_job_id and caplia_deck_filename. Set them to hidden in the Webflow designer (or via custom CSS). HubSpot will receive their values on form submit.
5

Map the new fields in HubSpot

In your existing Webflow → HubSpot mapping, add the two new fields. caplia_job_id is the important one — store it as a contact (or deal) property so you can cross-reference back to Caplia later.
6

Test on the staging Webflow domain

Set data-api-base="https://api-sandbox.venture.caplia.ai" and use the sandbox form_id we provision for you. Submit a test entry, confirm the caplia_job_id lands in HubSpot, then flip to production by removing the data-api-base override.

Endpoints used

The widget calls two endpoints. Both are public — no API key required from the browser.

POST /v1/uploads/sign

Issues a short-lived cap_upload_<jwt> token bound to one upload. The form_id must be allowlisted server-side.
The properties array is the form team’s live custom-property config — render it as dropdowns (an awards programme’s category picker, a fund’s source tag) and the form stays current when the team renames or adds options inside Caplia. Pass selections on the upload call below.

POST /v1/uploads/decks

Accepts the PDF using the upload token.

Pulling scoring data back into your CRM

Once you have the job_id on the CRM side, your back-office tooling can fetch results with the regular Caplia REST API using a cap_inv_live_* key — see Authentication.
A scheduled HubSpot workflow (or Salesforce flow) that pings /v1/jobs/{job_id} every few minutes and writes scoring data back onto the contact is the simplest production pattern.

Security model

Long-lived cap_inv_live_* keys must never ship to a browser — anyone could view-source the page and use the key to push decks into your pipeline, or read your data. The two-step token flow (/v1/uploads/signcap_upload_<jwt>) is the same pattern AWS uses for S3 presigned POSTs: server-side authorisation, short-lived, single-use, scoped to one operation.
Two gates. First, only form_ids that have been explicitly allowlisted on the Caplia side can mint tokens — random form_id strings return 404. Second, each token has a 5-minute TTL and is bound to a single upload. We add per-IP rate limits and optional Cloudflare Turnstile challenges on top once a programme grows beyond a small expected entrant pool.
Encrypted Caplia storage, scoped to your team. Only members of your Caplia team can access entries. The deck never touches Webflow’s or HubSpot’s storage.
Entrants’ decks are processed on the basis of the consent they give in your application form. We provide tooling to bulk-export or bulk-delete a form’s entries when a programme concludes — talk to Connor about retention windows.

Limitations

  • PDF only. Other file types are rejected by both the widget (client-side) and the API (server-side).
  • 50 MB maximum. Server-enforced; tokens carry the limit in their signed claims.
  • No upload progress bar yet. The widget shows “Uploading…” but not byte-level progress; fetch() doesn’t expose that without falling back to XMLHttpRequest. We’ll add a progress bar in v2 if customer feedback warrants it.
  • One widget instance per form. Multiple instances on the same page are supported (each is initialised independently), but two instances inside the same <form> would clobber each other’s hidden inputs.

Need help?