Idempotency keys
Pass Idempotency-Key on any POST and we guarantee exactly-once semantics — no duplicate agreements, ever.
Built for developers
REST API, idempotency keys, signed webhooks, predictable JSON. SDKs for Node, Python, and Ruby. What you would build if you had two months — without the two months.
curl https://api.ndakit.com/v1/agreements \
-H "Authorization: Bearer ndak_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"type": "proposal",
"party_b_name": "Acme Corp",
"party_b_email": "ceo@acme.com",
"amount_cents": 750000,
"deposit_cents": 250000
}'Built for startups + small businesses
Big tools were built for enterprise procurement. We were built for engineers shipping product. No per-seat tax. No envelope caps. No 9-month sales cycles. Just the agreement layer your business needs, drop-in, in 5 minutes.
Embed-first
Drop the embed script into any page. Agreements render inline, on your domain, in your typography. Recipients never leave your brand.
<!-- One line. Drop it anywhere in your site. -->
<script src="https://js.ndakit.com/v1/embed.js"
data-publishable-key="ndak_pk_live_xxx"
data-agreement-type="proposal"
data-on-signed="window.onAgreementSigned"
></script>Webhooks
HMAC-SHA256-signed payloads, exponential-backoff retries (1m → 1h → 6h → 24h), and idempotency keys to prevent duplicate handling. Every event below fires from production.
import { verifyWebhook } from '@ndakit/sdk';
app.post('/webhooks/ndakit', async (req) => {
const event = await verifyWebhook(req, {
secret: process.env.NDAKIT_WEBHOOK_SECRET,
});
switch (event.type) {
case 'agreement.signed':
await db.deals.markSigned(event.data.id);
break;
case 'payment.captured':
await db.deals.markPaid(event.data.id);
break;
}
return res.status(200).send('ok');
});agreement.createdDocument drafted via API or dashboardagreement.sentDelivered to recipient via email or embedagreement.viewedRecipient opened the sign pageagreement.signedCounterparty signature captured + sealedagreement.declinedRecipient declined to signagreement.expiredTTL elapsed before signaturepayment.capturedStripe / PayPal deposit successfulpayment.failedCharge failed — retry or escalateBuilding blocks
Pass Idempotency-Key on any POST and we guarantee exactly-once semantics — no duplicate agreements, ever.
Official SDKs for Node, Python, Ruby. Auto-typed responses, webhook verification helpers, retry logic baked in.
snake_case fields, ISO-8601 timestamps, errors with stable codes. No envelope wrapping, no surprise nesting.
API runs on Cloudflare Workers — sub-50ms p95 globally. Sign pages serve from edge cache for instant first paint.
Integration recipes
Mandate an NDA before a freelancer can see proprietary briefs. POST /v1/agreements with type=nda; on agreement.signed webhook, unlock the brief feed.
Trigger a mutual NDA the moment a deal moves to "Discovery". The agreement renders inline in the deal record; nda.signed advances the stage.
Send a proposal with a Stripe deposit attached. Agreement signature and payment capture happen in the same recipient session.
Send contractor agreement + NDA + IP assignment as a bundle when an offer is accepted. State-specific overlays apply automatically.
Pricing snapshot
Get a free API key, paste a curl command, see a signed PDF in your inbox. No legal team required.