Quickstart

Last updated on

Create your first form in minutes

Let's build a simple purchase agreement to grasp the basics of Paradoc. We'll define the agreement, populate it with data, validate it, and render the output.

Install the Packages

Let's make a new project and install the SDK and filesystem resolver. The SDK includes the default renderer.

mkdir quickstart && cd quickstart
npm init -y
npm install @paradoc/sdk @paradoc/resolvers

The examples use ES modules and top-level await. Set "type": "module" in package.json, put the code from each step in one index.ts file, and run it with npx tsx index.ts.

Define the Form

Let's define a simple purchase agreement with 2 parties and 3 fields. It will have a single layer that is a Markdown file.

The markdown layer is file-backed, so its bytes come from a resolver. Bind one when you build the form — every instance you derive from it later (fill, render, and so on) carries it.

import { p } from '@paradoc/sdk'
import { createFsResolver } from '@paradoc/resolvers/fs'

const resolver = createFsResolver({ root: process.cwd() })

const purchaseAgreement = p
  .form()
  .name('purchase-agreement') // required
  .title('Purchase Agreement')
  .version('1.0.0')
  .parties({
    buyer: p.party().label('Buyer').partyType('person').signature({ required: true }),
    seller: p.party().label('Seller').partyType('person').signature({ required: true }),
  })
  .fields({
    quantity: p.field.number().label('Quantity').required(),
    price: p.field.money().label('Price').required(),
    date: p.field.date().label('Date').required(),
  })
  .layers({
    markdown: p.layer().file().mimeType('text/markdown').path('purchase-agreement.md'),
  })
  .defaultLayer('markdown')
  .build({ resolver })

In this Quickstart, we're using the fluent builder pattern to define the form. You can also use the object pattern if you prefer.

Create the Layer

Next, let's create the layer. Paradoc's deterministic template syntax maps the form parties and fields into the layer.

purchase-agreement.md
# Purchase Agreement

{{parties.buyer.name}} agrees to purchase {{fields.quantity}} units at {{fields.price}} each.
{{parties.seller.name}} agrees to deliver by {{fields.date}}.

Paradoc is agnostic to the rendering engine and file format you choose. You can use any rendering engine and file format you want.

Populate

Let's populate the form with data by using the .fill() method.

const draft = purchaseAgreement.fill({
  fields: {
    quantity: 100,
    price: { amount: 25, currency: 'USD' },
    date: '2025-03-01',
  },
  parties: {
    buyer: { name: 'Alice Johnson' },
    seller: { name: 'Bob Smith' },
  },
})

Validate

Next, let's check that the data is valid by using the .isValid() method.

if (draft.isValid()) {
  console.log('Purchase agreement is valid')
} else {
  console.log('Errors:', draft.validate().errors)
}

Render

Let's render the purchase agreement with the data using the .render() method. The resolver we bound when building the form travels with draft, so we don't pass it again.

const output = await draft.render({ layer: 'markdown' })

console.log(output)
// # Purchase Agreement
//
// Alice Johnson agrees to purchase 100 units at $25.00 each.
// Bob Smith agrees to deliver by Mar 1, 2025.

Save Artifact

If we want to save our form for future use, we can either save it as a typescript file, or we can serialize it to JSON/YAML for future loading.

import { writeFileSync } from 'node:fs'

writeFileSync('purchase-agreement.json', JSON.stringify(purchaseAgreement.toJSON(), null, 2))
{
  "$schema": "https://schema.paradoc.dev/2026-10-02.json",
  "name": "purchase-agreement",
  "version": "1.0.0",
  "title": "Purchase Agreement",
  "metadata": {},
  "kind": "form",
  "fields": {
    "quantity": {
      "label": "Quantity",
      "required": true,
      "type": "number"
    },
    "price": {
      "label": "Price",
      "required": true,
      "type": "money"
    },
    "date": {
      "label": "Date",
      "required": true,
      "type": "date"
    }
  },
  "layers": {
    "markdown": {
      "mimeType": "text/markdown",
      "kind": "file",
      "path": "purchase-agreement.md"
    }
  },
  "defaultLayer": "markdown",
  "parties": {
    "buyer": {
      "label": "Buyer",
      "partyType": "person",
      "signature": {
        "required": true
      }
    },
    "seller": {
      "label": "Seller",
      "partyType": "person",
      "signature": {
        "required": true
      }
    }
  }
}

That's it! You've created a basic form that shows how Paradoc works at design time (defining the schema) and runtime (filling and rendering). As a next step, explore the concepts section or jump into the guides to learn more.

Next Steps

  • Concepts — learn about the core concepts
  • Guides — step-by-step tutorials

On this page