diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 3471f4f88..790c1ab0b 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -10,13 +10,7 @@ "ghcr.io/devcontainers/features/node:1": {} }, "onCreateCommand": "./.devcontainer/on-create.sh", - "forwardPorts": [ - 3000, - 54320, - 9000, - 2500, - 1100 - ], + "forwardPorts": [3000, 54320, 9000, 2500, 1100], "customizations": { "vscode": { "extensions": [ @@ -35,4 +29,4 @@ ] } } -} \ No newline at end of file +} diff --git a/.env.example b/.env.example index 559684160..80c11413c 100644 --- a/.env.example +++ b/.env.example @@ -139,3 +139,6 @@ E2E_TEST_AUTHENTICATE_USER_PASSWORD="test_Password123" # [[REDIS]] NEXT_PRIVATE_REDIS_URL= NEXT_PRIVATE_REDIS_TOKEN= + +# [[LOGGER]] +NEXT_PRIVATE_LOGGER_HONEY_BADGER_API_KEY= diff --git a/.github/actions/cache-build/action.yml b/.github/actions/cache-build/action.yml index 056b9a193..878eb27d2 100644 --- a/.github/actions/cache-build/action.yml +++ b/.github/actions/cache-build/action.yml @@ -13,7 +13,6 @@ runs: with: path: | ${{ github.workspace }}/apps/web/.next - ${{ github.workspace }}/apps/marketing/.next **/.turbo/** **/dist/** diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 9a20ae923..77415918f 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -11,16 +11,6 @@ updates: - 'ci' open-pull-requests-limit: 0 - - package-ecosystem: 'npm' - directory: '/apps/marketing' - schedule: - interval: 'weekly' - target-branch: 'main' - labels: - - 'npm dependencies' - - 'frontend' - open-pull-requests-limit: 0 - - package-ecosystem: 'npm' directory: '/apps/web' schedule: diff --git a/.github/labeler.yml b/.github/labeler.yml index e6ad018a3..2fe8be5e2 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -1,6 +1,3 @@ -'apps: marketing': - - apps/marketing/** - 'apps: web': - apps/web/** diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b948e560d..88692396f 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -10,7 +10,7 @@ on: jobs: analyze: name: Analyze - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 permissions: actions: read contents: read diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index baa4c1f07..4673dfca1 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -8,7 +8,7 @@ jobs: e2e_tests: name: 'E2E Tests' timeout-minutes: 60 - runs-on: ubuntu-latest + runs-on: warp-ubuntu-2204-x64-16x steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 5515b37a6..a2fb4ddf2 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -90,7 +90,7 @@ jobs: GIT_SHA="$(git rev-parse HEAD)" # Check if the version is stable (no rc or beta in the version) - if [[ "$APP_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + if [[ "$APP_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then docker manifest create \ documenso/documenso:latest \ --amend documenso/documenso-amd64:latest \ @@ -99,7 +99,7 @@ jobs: docker manifest push documenso/documenso:latest fi - if [[ "$APP_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$ ]]; then + if [[ "$APP_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$ ]]; then docker manifest create \ documenso/documenso:rc \ --amend documenso/documenso-amd64:rc \ @@ -127,7 +127,7 @@ jobs: GIT_SHA="$(git rev-parse HEAD)" # Check if the version is stable (no rc or beta in the version) - if [[ "$APP_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + if [[ "$APP_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then docker manifest create \ ghcr.io/documenso/documenso:latest \ --amend ghcr.io/documenso/documenso-amd64:latest \ @@ -136,7 +136,7 @@ jobs: docker manifest push ghcr.io/documenso/documenso:latest fi - if [[ "$APP_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$ ]]; then + if [[ "$APP_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$ ]]; then docker manifest create \ ghcr.io/documenso/documenso:rc \ --amend ghcr.io/documenso/documenso-amd64:rc \ diff --git a/.husky/pre-commit b/.husky/pre-commit index 3d805e3cf..17f372598 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -11,6 +11,5 @@ echo "Copying .well-known/ contents" node "$MONOREPO_ROOT/scripts/copy-wellknown.cjs" git add "$MONOREPO_ROOT/apps/web/public/" -git add "$MONOREPO_ROOT/apps/marketing/public/" npx lint-staged diff --git a/README.md b/README.md index 178b1f0cf..5239c79d0 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +> 🚨 We are live on Product Hunt 🎉 Check out our latest launch: The Platform Plan! + +Documenso Platform Plan - Whitelabeled signing flows in your product | Product Hunt + Documenso Logo

diff --git a/apps/documentation/README.md b/apps/documentation/README.md index adf7cb8a7..66280ee92 100644 --- a/apps/documentation/README.md +++ b/apps/documentation/README.md @@ -1,36 +1 @@ -This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). - -## Getting Started - -First, run the development server: - -```bash -npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev -``` - -Open [http://localhost:3002](http://localhost:3002) with your browser to see the result. - -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. - -This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. - -## Learn More - -To learn more about Next.js, take a look at the following resources: - -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. - -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! - -## Deploy on Vercel - -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. - -Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. +# @documenso/documentation diff --git a/apps/documentation/package.json b/apps/documentation/package.json index 7ab519307..fc06f6547 100644 --- a/apps/documentation/package.json +++ b/apps/documentation/package.json @@ -27,9 +27,6 @@ "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", - "autoprefixer": "^10.0.1", - "postcss": "^8", - "tailwindcss": "^3.3.0", - "typescript": "^5" + "typescript": "5.6.2" } } \ No newline at end of file diff --git a/apps/documentation/pages/_app.mdx b/apps/documentation/pages/_app.mdx index 2fc1af5a7..d0e1523cb 100644 --- a/apps/documentation/pages/_app.mdx +++ b/apps/documentation/pages/_app.mdx @@ -4,7 +4,7 @@ import '../styles.css'; export default function App({ Component, pageProps }) { return ( - ; + ); } diff --git a/apps/documentation/pages/developers/contributing/contributing-translations.mdx b/apps/documentation/pages/developers/contributing/contributing-translations.mdx index b944aa858..e313a4dc1 100644 --- a/apps/documentation/pages/developers/contributing/contributing-translations.mdx +++ b/apps/documentation/pages/developers/contributing/contributing-translations.mdx @@ -20,11 +20,7 @@ If you are looking for development notes on translations, you can find them [her We store our translations in PO files, which are located in our GitHub repository [here](https://github.com/documenso/documenso/tree/main/packages/lib/translations). -The translation files are organized into folders represented by their respective language codes (`en` for English, `de` for German, etc). Each language folder contains three PO files: - -1. `web.po`: Translations for the web application -2. `marketing.po`: Translations for the marketing application -3. `common.po`: Shared translations between web and marketing +The translation files are organized into folders represented by their respective language codes (`en` for English, `de` for German, etc). Each PO file contains translations which look like this: @@ -46,11 +42,10 @@ msgstr "Möchten Sie auffällige Signatur-Links wie diesen senden? <0>Überprüf ### Updating Existing Translations 1. Fork the repository. -2. Navigate to the appropriate language folder. -3. Open the PO file you want to update (web.po, marketing.po, or common.po). -4. Make your changes, ensuring you follow the PO file format. -5. Commit your changes with a message such as `chore: update German translations` -6. Create a Pull Request. +2. Navigate to the appropriate language folder and open the PO file you want to update. +3. Make your changes, ensuring you follow the PO file format. +4. Commit your changes with a message such as `chore: update German translations` +5. Create a Pull Request. ### Adding a New Language diff --git a/apps/documentation/pages/developers/embedding/_meta.json b/apps/documentation/pages/developers/embedding/_meta.json new file mode 100644 index 000000000..96806de3e --- /dev/null +++ b/apps/documentation/pages/developers/embedding/_meta.json @@ -0,0 +1,10 @@ +{ + "index": "Get Started", + "react": "React Integration", + "vue": "Vue Integration", + "svelte": "Svelte Integration", + "solid": "Solid Integration", + "preact": "Preact Integration", + "angular": "Angular Integration", + "css-variables": "CSS Variables" +} diff --git a/apps/documentation/pages/developers/embedding/angular.mdx b/apps/documentation/pages/developers/embedding/angular.mdx new file mode 100644 index 000000000..5bd169b20 --- /dev/null +++ b/apps/documentation/pages/developers/embedding/angular.mdx @@ -0,0 +1,90 @@ +--- +title: Angular Integration +description: Learn how to use our embedding SDK within your Angular application. +--- + +# Angular Integration + +Our Angular SDK provides a simple way to embed a signing experience within your Angular application. It supports both direct link templates and signing tokens. + +## Installation + +To install the SDK, run the following command: + +```bash +npm install @documenso/embed-angular +``` + +## Usage + +To embed a signing experience, you'll need to provide the token for the document you want to embed. This can be done in a few different ways, depending on your use case. + +### Direct Link Template + +If you have a direct link template, you can simply provide the token for the template to the `EmbedDirectTemplate` component. + +```typescript +import { Component } from '@angular/core'; +import { EmbedDirectTemplate } from '@documenso/embed-angular'; + +@Component({ + selector: 'app-embedding', + template: ` + + `, + standalone: true, + imports: [EmbedDirectTemplate], +}) +export class EmbeddingComponent { + token = 'YOUR_TOKEN_HERE'; // Replace with the actual token +} +``` + +#### Props + +| Prop | Type | Description | +| ------------------- | ------------------- | ------------------------------------------------------------------------------------------ | +| token | string | The token for the document you want to embed | +| host | string (optional) | The host to be used for the signing experience, relevant for self-hosters | +| name | string (optional) | The name the signer that will be used by default for signing | +| lockName | boolean (optional) | Whether or not the name field should be locked disallowing modifications | +| email | string (optional) | The email the signer that will be used by default for signing | +| lockEmail | boolean (optional) | Whether or not the email field should be locked disallowing modifications | +| onDocumentReady | function (optional) | A callback function that will be called when the document is loaded and ready to be signed | +| onDocumentCompleted | function (optional) | A callback function that will be called when the document has been completed | +| onDocumentError | function (optional) | A callback function that will be called when an error occurs with the document | +| onFieldSigned | function (optional) | A callback function that will be called when a field is signed | +| onFieldUnsigned | function (optional) | A callback function that will be called when a field is unsigned | + +### Signing Token + +If you have a signing token, you can provide it to the `EmbedSignDocument` component. + +```typescript +import { Component } from '@angular/core'; +import { EmbedSignDocument } from '@documenso/embed-angular'; + +@Component({ + selector: 'app-embedding', + template: ` + + `, + standalone: true, + imports: [EmbedSignDocument], +}) +export class EmbeddingComponent { + token = 'YOUR_TOKEN_HERE'; // Replace with the actual token +} +``` + +#### Props + +| Prop | Type | Description | +| ------------------- | ------------------- | ------------------------------------------------------------------------------------------ | +| token | string | The token for the document you want to embed | +| host | string (optional) | The host to be used for the signing experience, relevant for self-hosters | +| name | string (optional) | The name the signer that will be used by default for signing | +| lockName | boolean (optional) | Whether or not the name field should be locked disallowing modifications | +| onDocumentReady | function (optional) | A callback function that will be called when the document is loaded and ready to be signed | +| onDocumentCompleted | function (optional) | A callback function that will be called when the document has been completed | +| onDocumentError | function (optional) | A callback function that will be called when an error occurs with the document | diff --git a/apps/documentation/pages/developers/embedding/css-variables.mdx b/apps/documentation/pages/developers/embedding/css-variables.mdx new file mode 100644 index 000000000..d9259545e --- /dev/null +++ b/apps/documentation/pages/developers/embedding/css-variables.mdx @@ -0,0 +1,197 @@ +--- +title: CSS Variables +description: Learn about all available CSS variables for customizing your embedded signing experience +--- + +# CSS Variables + +Platform customers have access to a comprehensive set of CSS variables that can be used to customize the appearance of the embedded signing experience. These variables control everything from colors to spacing and can be used to match your application's design system. + +## Available Variables + +### Colors + +| Variable | Description | Default | +| ----------------------- | ---------------------------------- | -------------- | +| `background` | Base background color | System default | +| `foreground` | Base text color | System default | +| `muted` | Muted/subtle background color | System default | +| `mutedForeground` | Muted/subtle text color | System default | +| `popover` | Popover/dropdown background color | System default | +| `popoverForeground` | Popover/dropdown text color | System default | +| `card` | Card background color | System default | +| `cardBorder` | Card border color | System default | +| `cardBorderTint` | Card border tint/highlight color | System default | +| `cardForeground` | Card text color | System default | +| `fieldCard` | Field card background color | System default | +| `fieldCardBorder` | Field card border color | System default | +| `fieldCardForeground` | Field card text color | System default | +| `widget` | Widget background color | System default | +| `widgetForeground` | Widget text color | System default | +| `border` | Default border color | System default | +| `input` | Input field border color | System default | +| `primary` | Primary action/button color | System default | +| `primaryForeground` | Primary action/button text color | System default | +| `secondary` | Secondary action/button color | System default | +| `secondaryForeground` | Secondary action/button text color | System default | +| `accent` | Accent/highlight color | System default | +| `accentForeground` | Accent/highlight text color | System default | +| `destructive` | Destructive/danger action color | System default | +| `destructiveForeground` | Destructive/danger text color | System default | +| `ring` | Focus ring color | System default | +| `warning` | Warning/alert color | System default | + +### Spacing and Layout + +| Variable | Description | Default | +| -------- | ------------------------------- | -------------- | +| `radius` | Border radius size in REM units | System default | + +## Usage Example + +Here's how to use these variables in your embedding implementation: + +```jsx +const cssVars = { + // Colors + background: '#ffffff', + foreground: '#000000', + primary: '#0000ff', + primaryForeground: '#ffffff', + accent: '#4f46e5', + destructive: '#ef4444', + + // Spacing + radius: '0.5rem' +}; + +// React/Preact + + +// Vue + + +// Svelte + + +// Solid + +``` + +## Color Format + +Colors can be specified in any valid CSS color format: + +- Hexadecimal: `#ff0000` +- RGB: `rgb(255, 0, 0)` +- HSL: `hsl(0, 100%, 50%)` +- Named colors: `red` + +The colors will be automatically converted to the appropriate format internally. + +## Best Practices + +1. **Maintain Contrast**: When customizing colors, ensure there's sufficient contrast between background and foreground colors for accessibility. + +2. **Test Dark Mode**: If you haven't disabled dark mode, test your color variables in both light and dark modes. + +3. **Use Your Brand Colors**: Align the primary and accent colors with your brand's color scheme for a cohesive look. + +4. **Consistent Radius**: Use a consistent border radius value that matches your application's design system. + +## CSS Class Targets + +In addition to CSS variables, specific components in the embedded experience can be targeted using CSS classes for more granular styling: + +### Component Classes + +| Class Name | Description | +| --------------------------------- | ----------------------------------------------------------------------- | +| `.embed--Root` | Main container for the embedded signing experience | +| `.embed--DocumentContainer` | Container for the document and signing widget | +| `.embed--DocumentViewer` | Container for the document viewer | +| `.embed--DocumentWidget` | The signing widget container | +| `.embed--DocumentWidgetContainer` | Outer container for the signing widget, handles positioning | +| `.embed--DocumentWidgetHeader` | Header section of the signing widget | +| `.embed--DocumentWidgetContent` | Main content area of the signing widget | +| `.embed--DocumentWidgetForm` | Form section within the signing widget | +| `.embed--DocumentWidgetFooter` | Footer section of the signing widget | +| `.embed--WaitingForTurn` | Container for the waiting screen when it's not the user's turn to sign | +| `.embed--DocumentCompleted` | Container for the completion screen after signing | +| `.field--FieldRootContainer` | Base container for document fields (signatures, text, checkboxes, etc.) | + +Field components also expose several data attributes that can be used for styling different states: + +| Data Attribute | Values | Description | +| ------------------- | ---------------------------------------------- | ------------------------------------ | +| `[data-field-type]` | `SIGNATURE`, `TEXT`, `CHECKBOX`, `RADIO`, etc. | The type of field | +| `[data-inserted]` | `true`, `false` | Whether the field has been filled | +| `[data-validate]` | `true`, `false` | Whether the field is being validated | + +### Field Styling Example + +```css +/* Style all field containers */ +.field--FieldRootContainer { + transition: all 200ms ease; +} + +/* Style specific field types */ +.field--FieldRootContainer[data-field-type='SIGNATURE'] { + background-color: rgba(0, 0, 0, 0.02); +} + +/* Style inserted fields */ +.field--FieldRootContainer[data-inserted='true'] { + background-color: var(--primary); + opacity: 0.2; +} + +/* Style fields being validated */ +.field--FieldRootContainer[data-validate='true'] { + border-color: orange; +} +``` + +### Example Usage + +```css +/* Custom styles for the document widget */ +.embed--DocumentWidget { + background-color: #ffffff; + box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1); +} + +/* Custom styles for the waiting screen */ +.embed--WaitingForTurn { + background-color: #f9fafb; + padding: 2rem; +} + +/* Responsive adjustments for the document container */ +@media (min-width: 768px) { + .embed--DocumentContainer { + gap: 2rem; + } +} +``` + +## Related + +- [React Integration](/developers/embedding/react) +- [Vue Integration](/developers/embedding/vue) +- [Svelte Integration](/developers/embedding/svelte) +- [Solid Integration](/developers/embedding/solid) +- [Preact Integration](/developers/embedding/preact) diff --git a/apps/documentation/pages/developers/embedding/index.mdx b/apps/documentation/pages/developers/embedding/index.mdx index 383c9beb3..27d6f6f8f 100644 --- a/apps/documentation/pages/developers/embedding/index.mdx +++ b/apps/documentation/pages/developers/embedding/index.mdx @@ -5,13 +5,17 @@ description: Learn how to use embedding to bring signing to your own website or # Embedding -Our embedding feature lets you integrate our document signing experience into your own application or website. Whether you're building with React, Preact, Vue, Svelte, Solid, or using generalized web components, this guide will help you get started with embedding Documenso. +Our embedding feature lets you integrate our document signing experience into your own application or website. Whether you're building with React, Preact, Vue, Svelte, Solid, Angular, or using generalized web components, this guide will help you get started with embedding Documenso. ## Availability Embedding is currently available for all users on a **Teams Plan** and above, as well as **Early Adopter's** within a team (Early Adopters can create a team for free). -In the future, we will roll out a **Platform Plan** that will offer additional enhancements for embedding, including the option to remove Documenso branding for a more customized experience. +Our **Platform Plan** offers enhanced customization features including: + +- Custom CSS and styling variables +- Dark mode controls +- The removal of Documenso branding from the embedding experience ## How Embedding Works @@ -22,17 +26,61 @@ Embedding with Documenso allows you to handle document signing in two main ways: _For most use-cases we recommend using direct templates, however if you have a need for a more advanced integration, we are happy to help you get started._ +## Customization Options + +### Styling and Theming + +Platform customers have access to advanced styling options to customize the embedding experience: + +1. **Custom CSS**: You can provide custom CSS to style the embedded component: + +```jsx + +``` + +2. **CSS Variables**: Fine-tune the appearance using CSS variables for colors, spacing, and more: + +```jsx + +``` + +For a complete list of available CSS variables and their usage, see our [CSS Variables](/developers/embedding/css-variables) documentation. + +3. **Dark Mode Control**: Disable dark mode if it doesn't match your application's theme: + +```jsx + +``` + +These customization options are available for both Direct Templates and Signing Token embeds. + ## Supported Frameworks We support embedding across a range of popular JavaScript frameworks, including: -| Framework | Package | -| --------- | -------------------------------------------------------------------------------- | -| React | [@documenso/embed-react](https://www.npmjs.com/package/@documenso/embed-react) | -| Preact | [@documenso/embed-preact](https://www.npmjs.com/package/@documenso/embed-preact) | -| Vue | [@documenso/embed-vue](https://www.npmjs.com/package/@documenso/embed-vue) | -| Svelte | [@documenso/embed-svelte](https://www.npmjs.com/package/@documenso/embed-svelte) | -| Solid | [@documenso/embed-solid](https://www.npmjs.com/package/@documenso/embed-solid) | +| Framework | Package | +| --------- | ---------------------------------------------------------------------------------- | +| React | [@documenso/embed-react](https://www.npmjs.com/package/@documenso/embed-react) | +| Preact | [@documenso/embed-preact](https://www.npmjs.com/package/@documenso/embed-preact) | +| Vue | [@documenso/embed-vue](https://www.npmjs.com/package/@documenso/embed-vue) | +| Svelte | [@documenso/embed-svelte](https://www.npmjs.com/package/@documenso/embed-svelte) | +| Solid | [@documenso/embed-solid](https://www.npmjs.com/package/@documenso/embed-solid) | +| Angular | [@documenso/embed-angular](https://www.npmjs.com/package/@documenso/embed-angular) | Additionally, we provide **web components** for more generalized use. However, please note that web components are still in their early stages and haven't been extensively tested. @@ -80,7 +128,7 @@ This will show a dialog which will ask you to configure which recipient should b ## Embedding with Signing Tokens -To embed the signing process for an ordinary document, you’ll need a **document signing token** for the recipient. This token provides the necessary access to load the document and facilitate the signing process securely. +To embed the signing process for an ordinary document, you'll need a **document signing token** for the recipient. This token provides the necessary access to load the document and facilitate the signing process securely. #### Instructions @@ -117,15 +165,16 @@ Once you've obtained the appropriate tokens, you can integrate the signing exper - [Vue](/developers/embedding/vue) - [Svelte](/developers/embedding/svelte) - [Solid](/developers/embedding/solid) +- [Angular](/developers/embedding/angular) If you're using **web components**, the integration process is slightly different. Keep in mind that web components are currently less tested but can still provide flexibility for general use cases. -## Stay Tuned for the Platform Plan +## Related -While embedding is already a powerful tool, we're working on a **Platform Plan** that will introduce even more functionality. This plan will offer: - -- Additional customization options -- The ability to remove Documenso branding -- Additional controls for the signing experience - -More details will be shared as we approach the release. +- [React Integration](/developers/embedding/react) +- [Vue Integration](/developers/embedding/vue) +- [Svelte Integration](/developers/embedding/svelte) +- [Solid Integration](/developers/embedding/solid) +- [Preact Integration](/developers/embedding/preact) +- [Angular Integration](/developers/embedding/angular) +- [CSS Variables](/developers/embedding/css-variables) diff --git a/apps/documentation/pages/developers/embedding/preact.mdx b/apps/documentation/pages/developers/embedding/preact.mdx index 808b3aa49..91176723f 100644 --- a/apps/documentation/pages/developers/embedding/preact.mdx +++ b/apps/documentation/pages/developers/embedding/preact.mdx @@ -44,6 +44,9 @@ const MyEmbeddingComponent = () => { | email | string (optional) | The email the signer that will be used by default for signing | | lockEmail | boolean (optional) | Whether or not the email field should be locked disallowing modifications | | externalId | string (optional) | The external ID to be used for the document that will be created upon completion | +| css | string (optional) | Custom CSS to style the embedded component (Platform Plan only) | +| cssVars | object (optional) | CSS variables for customizing colors, spacing, etc. (Platform Plan only) | +| darkModeDisabled | boolean (optional) | Disable dark mode functionality (Platform Plan only) | | onDocumentReady | function (optional) | A callback function that will be called when the document is loaded and ready to be signed | | onDocumentCompleted | function (optional) | A callback function that will be called when the document has been completed | | onDocumentError | function (optional) | A callback function that will be called when an error occurs with the document | @@ -75,3 +78,30 @@ const MyEmbeddingComponent = () => { | onDocumentReady | function (optional) | A callback function that will be called when the document is loaded and ready to be signed | | onDocumentCompleted | function (optional) | A callback function that will be called when the document has been completed | | onDocumentError | function (optional) | A callback function that will be called when an error occurs with the document | + +### Styling and Theming (Platform Plan) + +Platform customers have access to advanced styling options: + +```jsx +import { EmbedDirectTemplate } from '@documenso/embed-preact'; + +const MyEmbeddingComponent = () => { + const token = 'your-token'; + const customCss = ` + .documenso-embed { + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + } + `; + const cssVars = { + colorPrimary: '#0000FF', + colorBackground: '#F5F5F5', + borderRadius: '8px', + }; + + return ( + + ); +}; +``` diff --git a/apps/documentation/pages/developers/embedding/react.mdx b/apps/documentation/pages/developers/embedding/react.mdx index 7ba19474f..05dc3a8aa 100644 --- a/apps/documentation/pages/developers/embedding/react.mdx +++ b/apps/documentation/pages/developers/embedding/react.mdx @@ -44,6 +44,9 @@ const MyEmbeddingComponent = () => { | email | string (optional) | The email the signer that will be used by default for signing | | lockEmail | boolean (optional) | Whether or not the email field should be locked disallowing modifications | | externalId | string (optional) | The external ID to be used for the document that will be created upon completion | +| css | string (optional) | Custom CSS to style the embedded component (Platform Plan only) | +| cssVars | object (optional) | CSS variables for customizing colors, spacing, etc. (Platform Plan only) | +| darkModeDisabled | boolean (optional) | Disable dark mode functionality (Platform Plan only) | | onDocumentReady | function (optional) | A callback function that will be called when the document is loaded and ready to be signed | | onDocumentCompleted | function (optional) | A callback function that will be called when the document has been completed | | onDocumentError | function (optional) | A callback function that will be called when an error occurs with the document | @@ -75,3 +78,34 @@ const MyEmbeddingComponent = () => { | onDocumentReady | function (optional) | A callback function that will be called when the document is loaded and ready to be signed | | onDocumentCompleted | function (optional) | A callback function that will be called when the document has been completed | | onDocumentError | function (optional) | A callback function that will be called when an error occurs with the document | + +### Styling and Theming (Platform Plan) + +Platform customers have access to advanced styling options: + +```jsx +import { EmbedDirectTemplate } from '@documenso/embed-react'; + +const MyEmbeddingComponent = () => { + return ( + + ); +}; +``` diff --git a/apps/documentation/pages/developers/embedding/solid.mdx b/apps/documentation/pages/developers/embedding/solid.mdx index 7feab2034..e19007a43 100644 --- a/apps/documentation/pages/developers/embedding/solid.mdx +++ b/apps/documentation/pages/developers/embedding/solid.mdx @@ -44,6 +44,9 @@ const MyEmbeddingComponent = () => { | email | string (optional) | The email the signer that will be used by default for signing | | lockEmail | boolean (optional) | Whether or not the email field should be locked disallowing modifications | | externalId | string (optional) | The external ID to be used for the document that will be created upon completion | +| css | string (optional) | Custom CSS to style the embedded component (Platform Plan only) | +| cssVars | object (optional) | CSS variables for customizing colors, spacing, etc. (Platform Plan only) | +| darkModeDisabled | boolean (optional) | Disable dark mode functionality (Platform Plan only) | | onDocumentReady | function (optional) | A callback function that will be called when the document is loaded and ready to be signed | | onDocumentCompleted | function (optional) | A callback function that will be called when the document has been completed | | onDocumentError | function (optional) | A callback function that will be called when an error occurs with the document | @@ -75,3 +78,30 @@ const MyEmbeddingComponent = () => { | onDocumentReady | function (optional) | A callback function that will be called when the document is loaded and ready to be signed | | onDocumentCompleted | function (optional) | A callback function that will be called when the document has been completed | | onDocumentError | function (optional) | A callback function that will be called when an error occurs with the document | + +### Styling and Theming (Platform Plan) + +Platform customers have access to advanced styling options: + +```jsx +import { EmbedDirectTemplate } from '@documenso/embed-solid'; + +const MyEmbeddingComponent = () => { + const token = 'your-token'; + const customCss = ` + .documenso-embed { + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + } + `; + const cssVars = { + colorPrimary: '#0000FF', + colorBackground: '#F5F5F5', + borderRadius: '8px', + }; + + return ( + + ); +}; +``` diff --git a/apps/documentation/pages/developers/embedding/svelte.mdx b/apps/documentation/pages/developers/embedding/svelte.mdx index d6a9abcf6..46ec69c63 100644 --- a/apps/documentation/pages/developers/embedding/svelte.mdx +++ b/apps/documentation/pages/developers/embedding/svelte.mdx @@ -46,6 +46,9 @@ If you have a direct link template, you can simply provide the token for the tem | email | string (optional) | The email the signer that will be used by default for signing | | lockEmail | boolean (optional) | Whether or not the email field should be locked disallowing modifications | | externalId | string (optional) | The external ID to be used for the document that will be created upon completion | +| css | string (optional) | Custom CSS to style the embedded component (Platform Plan only) | +| cssVars | object (optional) | CSS variables for customizing colors, spacing, etc. (Platform Plan only) | +| darkModeDisabled | boolean (optional) | Disable dark mode functionality (Platform Plan only) | | onDocumentReady | function (optional) | A callback function that will be called when the document is loaded and ready to be signed | | onDocumentCompleted | function (optional) | A callback function that will be called when the document has been completed | | onDocumentError | function (optional) | A callback function that will be called when an error occurs with the document | @@ -77,3 +80,28 @@ const MyEmbeddingComponent = () => { | onDocumentReady | function (optional) | A callback function that will be called when the document is loaded and ready to be signed | | onDocumentCompleted | function (optional) | A callback function that will be called when the document has been completed | | onDocumentError | function (optional) | A callback function that will be called when an error occurs with the document | + +### Styling and Theming (Platform Plan) + +Platform customers have access to advanced styling options: + +```html + + + +``` diff --git a/apps/documentation/pages/developers/embedding/vue.mdx b/apps/documentation/pages/developers/embedding/vue.mdx index 588de28b0..8051dbe35 100644 --- a/apps/documentation/pages/developers/embedding/vue.mdx +++ b/apps/documentation/pages/developers/embedding/vue.mdx @@ -46,6 +46,9 @@ If you have a direct link template, you can simply provide the token for the tem | email | string (optional) | The email the signer that will be used by default for signing | | lockEmail | boolean (optional) | Whether or not the email field should be locked disallowing modifications | | externalId | string (optional) | The external ID to be used for the document that will be created upon completion | +| css | string (optional) | Custom CSS to style the embedded component (Platform Plan only) | +| cssVars | object (optional) | CSS variables for customizing colors, spacing, etc. (Platform Plan only) | +| darkModeDisabled | boolean (optional) | Disable dark mode functionality (Platform Plan only) | | onDocumentReady | function (optional) | A callback function that will be called when the document is loaded and ready to be signed | | onDocumentCompleted | function (optional) | A callback function that will be called when the document has been completed | | onDocumentError | function (optional) | A callback function that will be called when an error occurs with the document | @@ -77,3 +80,35 @@ const MyEmbeddingComponent = () => { | onDocumentReady | function (optional) | A callback function that will be called when the document is loaded and ready to be signed | | onDocumentCompleted | function (optional) | A callback function that will be called when the document has been completed | | onDocumentError | function (optional) | A callback function that will be called when an error occurs with the document | + +### Styling and Theming (Platform Plan) + +Platform customers have access to advanced styling options: + +```html + + + +``` diff --git a/apps/documentation/pages/developers/public-api/index.mdx b/apps/documentation/pages/developers/public-api/index.mdx index 94b728b53..f2745ee82 100644 --- a/apps/documentation/pages/developers/public-api/index.mdx +++ b/apps/documentation/pages/developers/public-api/index.mdx @@ -3,6 +3,8 @@ title: Public API description: Learn how to interact with your documents programmatically using the Documenso public API. --- +import { Callout, Steps } from 'nextra/components'; + # Public API Documenso provides a public REST API enabling you to interact with your documents programmatically. The API exposes various HTTP endpoints that allow you to perform operations such as: @@ -13,10 +15,24 @@ Documenso provides a public REST API enabling you to interact with your document The documentation walks you through creating API keys and using them to authenticate your API requests. You'll also learn about the available endpoints, request and response formats, and how to use the API. -## Swagger Documentation +## API V1 - Stable -The [Swagger documentation](https://app.documenso.com/api/v1/openapi) also provides information about the API endpoints, request parameters, response formats, and authentication methods. +Check out the [API V1 documentation](https://app.documenso.com/api/v1/openapi) for details about the API endpoints, request parameters, response formats, and authentication methods. + +## API V2 - Beta + +Our new API V2 is currently in Beta. The new API features typed SDKs for TypeScript, Python and Go and example code for many more. + + + NOW IN BETA: [API V2 Documentation](https://documen.so/api-v2-docs) + + +🚀 [V2 Announcement](https://documen.so/sdk-blog) + +💬 [Leave Feedback](https://documen.so/sdk-feedback) + +🔔 [Breaking Changes](https://documen.so/sdk-breaking) ## Availability -The API is available to individual users and teams. +The API is available to individual users, teams and higher plans. [Fair Use](https://documen.so/fair) applies. diff --git a/apps/documentation/pages/developers/public-api/reference.mdx b/apps/documentation/pages/developers/public-api/reference.mdx index 648ee8a34..906b499fd 100644 --- a/apps/documentation/pages/developers/public-api/reference.mdx +++ b/apps/documentation/pages/developers/public-api/reference.mdx @@ -500,8 +500,35 @@ Now you can make a `POST` request to the `/api/v1/documents/{documentId}/fields` value, this is the value that will be used to sign the field. + + It's important to pass the `type` in the `fieldMeta` property for the advanced fields. [Read more + here](#a-note-on-advanced-fields) + + A successful request will return a JSON response with the newly added fields. The image below illustrates the fields added to the document via the API. ![A screenshot of the document in the Documenso editor](/api-reference/fields-added-via-api.webp) + +#### A Note on Advanced Fields + +The advanced fields are: text, checkbox, radio, number, and select. Whenever you append any of these advanced fields to a document, you need to pass the `type` in the `fieldMeta` property: + +```json +... +"fieldMeta": { + "type": "text", +} +... +``` + +Replace the `text` value with the corresponding field type: + +- For the `TEXT` field it should be `text`. +- For the `CHECKBOX` field it should be `checkbox`. +- For the `RADIO` field it should be `radio`. +- For the `NUMBER` field it should be `number`. +- For the `SELECT` field it should be `select`. (check this before merge) + +You must pass this property at all times, even if you don't need to set any other properties. If you don't, the endpoint will throw an error. diff --git a/apps/documentation/pages/developers/webhooks.mdx b/apps/documentation/pages/developers/webhooks.mdx index 024f4e493..1155e32c8 100644 --- a/apps/documentation/pages/developers/webhooks.mdx +++ b/apps/documentation/pages/developers/webhooks.mdx @@ -20,6 +20,8 @@ Documenso supports Webhooks and allows you to subscribe to the following events: - `document.opened` - `document.signed` - `document.completed` +- `document.rejected` +- `document.cancelled` ## Create a webhook subscription @@ -36,7 +38,7 @@ Clicking on the "**Create Webhook**" button opens a modal to create a new webhoo To create a new webhook subscription, you need to provide the following information: - Enter the webhook URL that will receive the event payload. -- Select the event(s) you want to subscribe to: `document.created`, `document.sent`, `document.opened`, `document.signed`, `document.completed`. +- Select the event(s) you want to subscribe to: `document.created`, `document.sent`, `document.opened`, `document.signed`, `document.completed`, `document.rejected`, `document.cancelled`. - Optionally, you can provide a secret key that will be used to sign the payload. This key will be included in the `X-Documenso-Secret` header of the request. ![A screenshot of the Create Webhook modal that shows the URL input field and the event checkboxes](/webhook-images/webhooks-page-create-webhook-modal.webp) @@ -53,45 +55,55 @@ You can edit or delete your webhook subscriptions by clicking the "**Edit**" or The payload sent to the webhook URL contains the following fields: -| Field | Type | Description | -| -------------------------------------------- | --------- | ---------------------------------------------------- | -| `event` | string | The type of event that triggered the webhook. | -| `payload.id` | number | The id of the document. | -| `payload.userId` | number | The id of the user who owns the document. | -| `payload.authOptions` | json? | Authentication options for the document. | -| `payload.formValues` | json? | Form values for the document. | -| `payload.title` | string | The name of the document. | -| `payload.status` | string | The current status of the document. | -| `payload.documentDataId` | string | The identifier for the document data. | -| `payload.createdAt` | datetime | The creation date and time of the document. | -| `payload.updatedAt` | datetime | The last update date and time of the document. | -| `payload.completedAt` | datetime? | The completion date and time of the document. | -| `payload.deletedAt` | datetime? | The deletion date and time of the document. | -| `payload.teamId` | number? | The id of the team. | -| `payload.documentData.id` | string | The id of the document data. | -| `payload.documentData.type` | string | The type of the document data. | -| `payload.documentData.data` | string | The data of the document. | -| `payload.documentData.initialData` | string | The initial data of the document. | -| `payload.Recipient[].id` | number | The id of the recipient. | -| `payload.Recipient[].documentId` | number? | The id the document associated with the recipient. | -| `payload.Recipient[].templateId` | number? | The template identifier for the recipient. | -| `payload.Recipient[].email` | string | The email address of the recipient. | -| `payload.Recipient[].name` | string | The name of the recipient. | -| `payload.Recipient[].token` | string | The token associated with the recipient. | -| `payload.Recipient[].expired` | datetime? | The expiration status of the recipient. | -| `payload.Recipient[].signedAt` | datetime? | The date and time the recipient signed the document. | -| `payload.Recipient[].authOptions.accessAuth` | json? | Access authentication options. | -| `payload.Recipient[].authOptions.actionAuth` | json? | Action authentication options. | -| `payload.Recipient[].role` | string | The role of the recipient. | -| `payload.Recipient[].readStatus` | string | The read status of the document by the recipient. | -| `payload.Recipient[].signingStatus` | string | The signing status of the recipient. | -| `payload.Recipient[].sendStatus` | string | The send status of the document to the recipient. | -| `createdAt` | datetime | The creation date and time of the webhook event. | -| `webhookEndpoint` | string | The endpoint URL where the webhook is sent. | - -## Webhook event payload example - -When an event that you have subscribed to occurs, Documenso will send a POST request to the specified webhook URL with a payload containing information about the event. +| Field | Type | Description | +| -------------------------------------------- | --------- | ----------------------------------------------------- | +| `event` | string | The type of event that triggered the webhook. | +| `payload.id` | number | The id of the document. | +| `payload.externalId` | string? | External identifier for the document. | +| `payload.userId` | number | The id of the user who owns the document. | +| `payload.authOptions` | json? | Authentication options for the document. | +| `payload.formValues` | json? | Form values for the document. | +| `payload.visibility` | string | Document visibility (e.g., EVERYONE). | +| `payload.title` | string | The title of the document. | +| `payload.status` | string | The current status of the document. | +| `payload.documentDataId` | string | The identifier for the document data. | +| `payload.createdAt` | datetime | The creation date and time of the document. | +| `payload.updatedAt` | datetime | The last update date and time of the document. | +| `payload.completedAt` | datetime? | The completion date and time of the document. | +| `payload.deletedAt` | datetime? | The deletion date and time of the document. | +| `payload.teamId` | number? | The id of the team if document belongs to a team. | +| `payload.templateId` | number? | The id of the template if created from template. | +| `payload.source` | string | The source of the document (e.g., DOCUMENT, TEMPLATE) | +| `payload.documentMeta.id` | string | The id of the document metadata. | +| `payload.documentMeta.subject` | string? | The subject of the document. | +| `payload.documentMeta.message` | string? | The message associated with the document. | +| `payload.documentMeta.timezone` | string | The timezone setting for the document. | +| `payload.documentMeta.password` | string? | The password protection if set. | +| `payload.documentMeta.dateFormat` | string | The date format used in the document. | +| `payload.documentMeta.redirectUrl` | string? | The URL to redirect after signing. | +| `payload.documentMeta.signingOrder` | string | The signing order (e.g., PARALLEL, SEQUENTIAL). | +| `payload.documentMeta.typedSignatureEnabled` | boolean | Whether typed signatures are enabled. | +| `payload.documentMeta.language` | string | The language of the document. | +| `payload.documentMeta.distributionMethod` | string | The method of distributing the document. | +| `payload.documentMeta.emailSettings` | json? | Email notification settings. | +| `payload.Recipient[].id` | number | The id of the recipient. | +| `payload.Recipient[].documentId` | number? | The id of the document for this recipient. | +| `payload.Recipient[].templateId` | number? | The template id if from a template. | +| `payload.Recipient[].email` | string | The email address of the recipient. | +| `payload.Recipient[].name` | string | The name of the recipient. | +| `payload.Recipient[].token` | string | The unique token for this recipient. | +| `payload.Recipient[].documentDeletedAt` | datetime? | When the document was deleted for this recipient. | +| `payload.Recipient[].expired` | datetime? | When the recipient's access expired. | +| `payload.Recipient[].signedAt` | datetime? | When the recipient signed the document. | +| `payload.Recipient[].authOptions` | json? | Authentication options for this recipient. | +| `payload.Recipient[].signingOrder` | number? | The order in which this recipient should sign. | +| `payload.Recipient[].rejectionReason` | string? | The reason if the recipient rejected the document. | +| `payload.Recipient[].role` | string | The role of the recipient (e.g., SIGNER, VIEWER). | +| `payload.Recipient[].readStatus` | string | Whether the recipient has read the document. | +| `payload.Recipient[].signingStatus` | string | The signing status of this recipient. | +| `payload.Recipient[].sendStatus` | string | The sending status for this recipient. | +| `createdAt` | datetime | The creation date and time of the webhook event. | +| `webhookEndpoint` | string | The endpoint URL where the webhook is sent. | ## Example payloads @@ -104,9 +116,11 @@ Example payload for the `document.created` event: "event": "DOCUMENT_CREATED", "payload": { "id": 10, + "externalId": null, "userId": 1, "authOptions": null, "formValues": null, + "visibility": "EVERYONE", "title": "documenso.pdf", "status": "DRAFT", "documentDataId": "hs8qz1ktr9204jn7mg6c5dxy0", @@ -114,7 +128,43 @@ Example payload for the `document.created` event: "updatedAt": "2024-04-22T11:44:43.341Z", "completedAt": null, "deletedAt": null, - "teamId": null + "teamId": null, + "templateId": null, + "source": "DOCUMENT", + "documentMeta": { + "id": "doc_meta_123", + "subject": "Please sign this document", + "message": "Hello, please review and sign this document.", + "timezone": "UTC", + "password": null, + "dateFormat": "MM/DD/YYYY", + "redirectUrl": null, + "signingOrder": "PARALLEL", + "typedSignatureEnabled": true, + "language": "en", + "distributionMethod": "EMAIL", + "emailSettings": null + }, + "Recipient": [ + { + "id": 52, + "documentId": 10, + "templateId": null, + "email": "signer@documenso.com", + "name": "John Doe", + "token": "vbT8hi3jKQmrFP_LN1WcS", + "documentDeletedAt": null, + "expired": null, + "signedAt": null, + "authOptions": null, + "signingOrder": 1, + "rejectionReason": null, + "role": "SIGNER", + "readStatus": "NOT_OPENED", + "signingStatus": "NOT_SIGNED", + "sendStatus": "NOT_SENT" + } + ] }, "createdAt": "2024-04-22T11:44:44.779Z", "webhookEndpoint": "https://mywebhooksite.com/mywebhook" @@ -128,9 +178,11 @@ Example payload for the `document.sent` event: "event": "DOCUMENT_SENT", "payload": { "id": 10, + "externalId": null, "userId": 1, "authOptions": null, "formValues": null, + "visibility": "EVERYONE", "title": "documenso.pdf", "status": "PENDING", "documentDataId": "hs8qz1ktr9204jn7mg6c5dxy0", @@ -139,6 +191,22 @@ Example payload for the `document.sent` event: "completedAt": null, "deletedAt": null, "teamId": null, + "templateId": null, + "source": "DOCUMENT", + "documentMeta": { + "id": "doc_meta_123", + "subject": "Please sign this document", + "message": "Hello, please review and sign this document.", + "timezone": "UTC", + "password": null, + "dateFormat": "MM/DD/YYYY", + "redirectUrl": null, + "signingOrder": "PARALLEL", + "typedSignatureEnabled": true, + "language": "en", + "distributionMethod": "EMAIL", + "emailSettings": null + }, "Recipient": [ { "id": 52, @@ -147,12 +215,12 @@ Example payload for the `document.sent` event: "email": "signer2@documenso.com", "name": "Signer 2", "token": "vbT8hi3jKQmrFP_LN1WcS", + "documentDeletedAt": null, "expired": null, "signedAt": null, - "authOptions": { - "accessAuth": null, - "actionAuth": null - }, + "authOptions": null, + "signingOrder": 1, + "rejectionReason": null, "role": "VIEWER", "readStatus": "NOT_OPENED", "signingStatus": "NOT_SIGNED", @@ -165,12 +233,12 @@ Example payload for the `document.sent` event: "email": "signer1@documenso.com", "name": "Signer 1", "token": "HkrptwS42ZBXdRKj1TyUo", + "documentDeletedAt": null, "expired": null, "signedAt": null, - "authOptions": { - "accessAuth": null, - "actionAuth": null - }, + "authOptions": null, + "signingOrder": 2, + "rejectionReason": null, "role": "SIGNER", "readStatus": "NOT_OPENED", "signingStatus": "NOT_SIGNED", @@ -190,9 +258,11 @@ Example payload for the `document.opened` event: "event": "DOCUMENT_OPENED", "payload": { "id": 10, + "externalId": null, "userId": 1, "authOptions": null, "formValues": null, + "visibility": "EVERYONE", "title": "documenso.pdf", "status": "PENDING", "documentDataId": "hs8qz1ktr9204jn7mg6c5dxy0", @@ -201,6 +271,22 @@ Example payload for the `document.opened` event: "completedAt": null, "deletedAt": null, "teamId": null, + "templateId": null, + "source": "DOCUMENT", + "documentMeta": { + "id": "doc_meta_123", + "subject": "Please sign this document", + "message": "Hello, please review and sign this document.", + "timezone": "UTC", + "password": null, + "dateFormat": "MM/DD/YYYY", + "redirectUrl": null, + "signingOrder": "PARALLEL", + "typedSignatureEnabled": true, + "language": "en", + "distributionMethod": "EMAIL", + "emailSettings": null + }, "Recipient": [ { "id": 52, @@ -209,24 +295,18 @@ Example payload for the `document.opened` event: "email": "signer2@documenso.com", "name": "Signer 2", "token": "vbT8hi3jKQmrFP_LN1WcS", + "documentDeletedAt": null, "expired": null, "signedAt": null, - "authOptions": { - "accessAuth": null, - "actionAuth": null - }, + "authOptions": null, + "signingOrder": 1, + "rejectionReason": null, "role": "VIEWER", "readStatus": "OPENED", "signingStatus": "NOT_SIGNED", "sendStatus": "SENT" } - ], - "documentData": { - "id": "hs8qz1ktr9204jn7mg6c5dxy0", - "type": "S3_PATH", - "data": "9753/xzqrshtlpokm/documenso.pdf", - "initialData": "9753/xzqrshtlpokm/documenso.pdf" - } + ] }, "createdAt": "2024-04-22T11:50:26.174Z", "webhookEndpoint": "https://mywebhooksite.com/mywebhook" @@ -240,9 +320,11 @@ Example payload for the `document.signed` event: "event": "DOCUMENT_SIGNED", "payload": { "id": 10, + "externalId": null, "userId": 1, "authOptions": null, "formValues": null, + "visibility": "EVERYONE", "title": "documenso.pdf", "status": "COMPLETED", "documentDataId": "hs8qz1ktr9204jn7mg6c5dxy0", @@ -251,6 +333,22 @@ Example payload for the `document.signed` event: "completedAt": "2024-04-22T11:52:05.707Z", "deletedAt": null, "teamId": null, + "templateId": null, + "source": "DOCUMENT", + "documentMeta": { + "id": "doc_meta_123", + "subject": "Please sign this document", + "message": "Hello, please review and sign this document.", + "timezone": "UTC", + "password": null, + "dateFormat": "MM/DD/YYYY", + "redirectUrl": null, + "signingOrder": "PARALLEL", + "typedSignatureEnabled": true, + "language": "en", + "distributionMethod": "EMAIL", + "emailSettings": null + }, "Recipient": [ { "id": 51, @@ -259,12 +357,15 @@ Example payload for the `document.signed` event: "email": "signer1@documenso.com", "name": "Signer 1", "token": "HkrptwS42ZBXdRKj1TyUo", + "documentDeletedAt": null, "expired": null, "signedAt": "2024-04-22T11:52:05.688Z", "authOptions": { "accessAuth": null, "actionAuth": null }, + "signingOrder": 1, + "rejectionReason": null, "role": "SIGNER", "readStatus": "OPENED", "signingStatus": "SIGNED", @@ -284,9 +385,11 @@ Example payload for the `document.completed` event: "event": "DOCUMENT_COMPLETED", "payload": { "id": 10, + "externalId": null, "userId": 1, "authOptions": null, "formValues": null, + "visibility": "EVERYONE", "title": "documenso.pdf", "status": "COMPLETED", "documentDataId": "hs8qz1ktr9204jn7mg6c5dxy0", @@ -295,11 +398,21 @@ Example payload for the `document.completed` event: "completedAt": "2024-04-22T11:52:05.707Z", "deletedAt": null, "teamId": null, - "documentData": { - "id": "hs8qz1ktr9204jn7mg6c5dxy0", - "type": "S3_PATH", - "data": "bk9p1h7x0s3m/documenso-signed.pdf", - "initialData": "9753/xzqrshtlpokm/documenso.pdf" + "templateId": null, + "source": "DOCUMENT", + "documentMeta": { + "id": "doc_meta_123", + "subject": "Please sign this document", + "message": "Hello, please review and sign this document.", + "timezone": "UTC", + "password": null, + "dateFormat": "MM/DD/YYYY", + "redirectUrl": null, + "signingOrder": "PARALLEL", + "typedSignatureEnabled": true, + "language": "en", + "distributionMethod": "EMAIL", + "emailSettings": null }, "Recipient": [ { @@ -309,12 +422,15 @@ Example payload for the `document.completed` event: "email": "signer2@documenso.com", "name": "Signer 2", "token": "vbT8hi3jKQmrFP_LN1WcS", + "documentDeletedAt": null, "expired": null, "signedAt": "2024-04-22T11:51:10.055Z", "authOptions": { "accessAuth": null, "actionAuth": null }, + "signingOrder": 1, + "rejectionReason": null, "role": "VIEWER", "readStatus": "OPENED", "signingStatus": "SIGNED", @@ -327,12 +443,15 @@ Example payload for the `document.completed` event: "email": "signer1@documenso.com", "name": "Signer 1", "token": "HkrptwS42ZBXdRKj1TyUo", + "documentDeletedAt": null, "expired": null, "signedAt": "2024-04-22T11:52:05.688Z", "authOptions": { "accessAuth": null, "actionAuth": null }, + "signingOrder": 2, + "rejectionReason": null, "role": "SIGNER", "readStatus": "OPENED", "signingStatus": "SIGNED", @@ -345,6 +464,161 @@ Example payload for the `document.completed` event: } ``` +Example payload for the `document.rejected` event: + +```json +{ + "event": "DOCUMENT_REJECTED", + "payload": { + "id": 10, + "externalId": null, + "userId": 1, + "authOptions": null, + "formValues": null, + "visibility": "EVERYONE", + "title": "documenso.pdf", + "status": "PENDING", + "documentDataId": "hs8qz1ktr9204jn7mg6c5dxy0", + "createdAt": "2024-04-22T11:44:43.341Z", + "updatedAt": "2024-04-22T11:48:07.569Z", + "completedAt": null, + "deletedAt": null, + "teamId": null, + "templateId": null, + "source": "DOCUMENT", + "documentMeta": { + "id": "doc_meta_123", + "subject": "Please sign this document", + "message": "Hello, please review and sign this document.", + "timezone": "UTC", + "password": null, + "dateFormat": "MM/DD/YYYY", + "redirectUrl": null, + "signingOrder": "PARALLEL", + "typedSignatureEnabled": true, + "language": "en", + "distributionMethod": "EMAIL", + "emailSettings": null + }, + "Recipient": [ + { + "id": 52, + "documentId": 10, + "templateId": null, + "email": "signer@documenso.com", + "name": "Signer", + "token": "vbT8hi3jKQmrFP_LN1WcS", + "documentDeletedAt": null, + "expired": null, + "signedAt": "2024-04-22T11:48:07.569Z", + "authOptions": { + "accessAuth": null, + "actionAuth": null + }, + "signingOrder": 1, + "rejectionReason": "I do not agree with the terms", + "role": "SIGNER", + "readStatus": "OPENED", + "signingStatus": "REJECTED", + "sendStatus": "SENT" + } + ] + }, + "createdAt": "2024-04-22T11:48:07.945Z", + "webhookEndpoint": "https://mywebhooksite.com/mywebhook" +} +``` + +Example payload for the `document.rejected` event: + +```json +{ + "event": "DOCUMENT_CANCELLED", + "payload": { + "id": 7, + "externalId": null, + "userId": 3, + "authOptions": null, + "formValues": null, + "visibility": "EVERYONE", + "title": "documenso.pdf", + "status": "PENDING", + "documentDataId": "cm6exvn93006hi02ru90a265a", + "createdAt": "2025-01-27T11:02:14.393Z", + "updatedAt": "2025-01-27T11:03:16.387Z", + "completedAt": null, + "deletedAt": null, + "teamId": null, + "templateId": null, + "source": "DOCUMENT", + "documentMeta": { + "id": "cm6exvn96006ji02rqvzjvwoy", + "subject": "", + "message": "", + "timezone": "Etc/UTC", + "password": null, + "dateFormat": "yyyy-MM-dd hh:mm a", + "redirectUrl": "", + "signingOrder": "PARALLEL", + "typedSignatureEnabled": true, + "language": "en", + "distributionMethod": "EMAIL", + "emailSettings": { + "documentDeleted": true, + "documentPending": true, + "recipientSigned": true, + "recipientRemoved": true, + "documentCompleted": true, + "ownerDocumentCompleted": true, + "recipientSigningRequest": true + } + }, + "recipients": [ + { + "id": 7, + "documentId": 7, + "templateId": null, + "email": "mybirihix@mailinator.com", + "name": "Zorita Baird", + "token": "XkKx1HCs6Znm2UBJA2j6o", + "documentDeletedAt": null, + "expired": null, + "signedAt": null, + "authOptions": { "accessAuth": null, "actionAuth": null }, + "signingOrder": 1, + "rejectionReason": null, + "role": "SIGNER", + "readStatus": "NOT_OPENED", + "signingStatus": "NOT_SIGNED", + "sendStatus": "SENT" + } + ], + "Recipient": [ + { + "id": 7, + "documentId": 7, + "templateId": null, + "email": "signer@documenso.com", + "name": "Signer", + "token": "XkKx1HCs6Znm2UBJA2j6o", + "documentDeletedAt": null, + "expired": null, + "signedAt": null, + "authOptions": { "accessAuth": null, "actionAuth": null }, + "signingOrder": 1, + "rejectionReason": null, + "role": "SIGNER", + "readStatus": "NOT_OPENED", + "signingStatus": "NOT_SIGNED", + "sendStatus": "SENT" + } + ] + }, + "createdAt": "2025-01-27T11:03:27.730Z", + "webhookEndpoint": "https://mywebhooksite.com/mywebhook" +} +``` + ## Availability Webhooks are available to individual users and teams. diff --git a/apps/documentation/pages/users/_meta.json b/apps/documentation/pages/users/_meta.json index 53733ea63..335b80eb4 100644 --- a/apps/documentation/pages/users/_meta.json +++ b/apps/documentation/pages/users/_meta.json @@ -10,7 +10,6 @@ "signing-documents": "Signing Documents", "templates": "Templates", "direct-links": "Direct Signing Links", - "document-visibility": "Document Visibility", "teams": "Teams", "-- Legal Overview": { "type": "separator", diff --git a/apps/documentation/pages/users/teams/_meta.json b/apps/documentation/pages/users/teams/_meta.json index b9548a39b..fc849e49d 100644 --- a/apps/documentation/pages/users/teams/_meta.json +++ b/apps/documentation/pages/users/teams/_meta.json @@ -1,5 +1,6 @@ { - "general-settings": "General Settings", + "preferences": "Preferences", "document-visibility": "Document Visibility", - "sender-details": "Email Sender Details" + "sender-details": "Email Sender Details", + "branding-preferences": "Branding Preferences" } diff --git a/apps/documentation/pages/users/teams/branding-preferences.mdx b/apps/documentation/pages/users/teams/branding-preferences.mdx new file mode 100644 index 000000000..15e074af7 --- /dev/null +++ b/apps/documentation/pages/users/teams/branding-preferences.mdx @@ -0,0 +1,16 @@ +--- +title: Branding Preferences +description: Learn how to set the branding preferences for your team account. +--- + +# Branding Preferences + +You can set the branding preferences for your team account by going to the **Branding Preferences** tab in the team's settings dashboard. + +![A screenshot of the team's branding preferences page](/teams/team-branding-preferences.webp) + +On this page, you can: + +- **Upload a Logo** - Upload your team's logo to be displayed instead of the default Documenso logo. +- **Set the Brand Website** - Enter the URL of your team's website to be displayed in the email communications sent by the team. +- **Add Additional Brand Details** - You can add additional information to display at the bottom of the emails sent by the team. This can include contact information, social media links, and other relevant details. diff --git a/apps/documentation/pages/users/teams/document-visibility.mdx b/apps/documentation/pages/users/teams/document-visibility.mdx index 8d2f82266..818c51b47 100644 --- a/apps/documentation/pages/users/teams/document-visibility.mdx +++ b/apps/documentation/pages/users/teams/document-visibility.mdx @@ -13,27 +13,29 @@ The default document visibility option allows you to control who can view and ac - **Managers and above** - The document is visible to team members with the role of _Manager or above_ and _Admin_. - **Admin only** - The document is only visible to the team's admins. -![A screenshot of the document visibility selector from the team's general settings page](/teams/team-general-settings-document-visibility-select.webp) +![A screenshot of the document visibility selector from the team's global preferences page](/teams/team-preferences-document-visibility.webp) -The default document visibility is set to "_EVERYONE_" by default. You can change this setting by going to the [team's general settings page](/users/teams/general-settings) and selecting a different visibility option. - - - If the team member uploading the document has a role lower than the default document visibility, - the document visibility will be set to a lower visibility level matching the team member's role. - +The default document visibility is set to "_EVERYONE_" by default. You can change this setting by going to the [team's general preferences page](/users/teams/preferences) and selecting a different visibility option. Here's how it works: -- If a user with the "_Member_" role creates a document and the default document visibility is set to "_Admin_" or "_Managers and above_", the document's visibility is set to "_Everyone_". -- If a user with the "_Manager_" role creates a document and the default document visibility is set to "_Admin_", the document's visibility is set to "_Managers and above_". -- Otherwise, the document's visibility is set to the default document visibility. +- If a user with the "_Member_" role creates a document and the default document visibility is set to "_Everyone_", the document's visibility is set to "_EVERYONE_". + - The user can't change the visibility of the document in the document editor. +- If a user with the "_Member_" role creates a document and the default document visibility is set to "_Admin_" or "_Managers and above_", the document's visibility is set to the default document visibility ("_Admin_" or "_Managers and above_" in this case). + - The user can't change the visibility of the document in the document editor. +- If a user with the "_Manager_" role creates a document and the default document visibility is set to "_Everyone_" or "_Managers and above_", the document's visibility is set to the default document visibility ("_Everyone_" or "_Managers and above_" in this case). + - The user can change the visibility of the document to any of these options, except "_Admin_", in the document editor. +- If a user with the "_Manager_" role creates a document and the default document visibility is set to "_Admin_", the document's visibility is set to "_Admin_". + - The user can't change the visibility of the document in the document editor. +- If a user with the "_Admin_" role creates a document, and the default document visibility is set to "_Everyone_", "_Managers and above_", or "_Admin_", the document's visibility is set to the default document visibility. + - The user can change the visibility of the document to any of these options in the document editor. You can change the visibility of a document at any time by editing the document and selecting a different visibility option. ![A screenshot of the Documenso's document editor page where you can update the document visibility](/teams/document-visibility-settings.webp) - Updating the default document visibility in the team's general settings will not affect the + Updating the default document visibility in the team's general preferences will not affect the visibility of existing documents. You will need to update the visibility of each document individually. diff --git a/apps/documentation/pages/users/teams/general-settings.mdx b/apps/documentation/pages/users/teams/general-settings.mdx deleted file mode 100644 index e10d379b0..000000000 --- a/apps/documentation/pages/users/teams/general-settings.mdx +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: General Settings -description: Learn how to manage your team's General settings. ---- - -# General Settings - -You can manage your team's general settings by clicking on the **General Settings** tab in the team's settings dashboard. - -![A screenshot of team's General settings page](/teams/team-general-settings.webp) - -The general settings page allows you to update the following settings: - -- **Document Visibility** - Set the default visibility of the documents created by team members. Learn more about [document visibility](/users/teams/document-visibility). -- **Sender Details** - Set whether the sender's name should be included in the emails sent by the team. Learn more about [sender details](/users/teams/sender-details). diff --git a/apps/documentation/pages/users/teams/preferences.mdx b/apps/documentation/pages/users/teams/preferences.mdx new file mode 100644 index 000000000..de0b7ca39 --- /dev/null +++ b/apps/documentation/pages/users/teams/preferences.mdx @@ -0,0 +1,19 @@ +--- +title: Preferences +description: Learn how to manage your team's global preferences. +--- + +# Preferences + +You can manage your team's global preferences by clicking on the **Preferences** tab in the team's settings dashboard. + +![A screenshot of the team's global preferences page](/teams/team-preferences.webp) + +The preferences page allows you to update the following settings: + +- **Document Visibility** - Set the default visibility of the documents created by team members. Learn more about [document visibility](/users/teams/document-visibility). +- **Default Document Language** - This setting allows you to set the default language for the documents uploaded in the team account. The default language is used as the default language in the email communications with the document recipients. You can change the language for individual documents when uploading them. +- **Sender Details** - Set whether the sender's name should be included in the emails sent by the team. Learn more about [sender details](/users/teams/sender-details). +- **Typed Signature** - It controls whether the document recipients can sign the documents with a typed signature or not. If enabled, the recipients can sign the document using either a drawn or a typed signature. If disabled, the recipients can only sign the documents usign a drawn signature. This setting can also be changed for individual documents when uploading them. +- **Include the Signing Certificate** - This setting controls whether the signing certificate should be included in the signed documents. If enabled, the signing certificate is included in the signed documents. If disabled, the signing certificate is not included in the signed documents. Regardless of this setting, the signing certificate is always available in the document's audit log page. +- **Branding Preferences** - Set the branding preferences and defaults for the team account. Learn more about [branding preferences](/users/teams/branding-preferences). diff --git a/apps/documentation/public/teams/team-branding-preferences.webp b/apps/documentation/public/teams/team-branding-preferences.webp new file mode 100644 index 000000000..df8bcc451 Binary files /dev/null and b/apps/documentation/public/teams/team-branding-preferences.webp differ diff --git a/apps/documentation/public/teams/team-general-settings-document-visibility-select.webp b/apps/documentation/public/teams/team-general-settings-document-visibility-select.webp deleted file mode 100644 index ef312eeeb..000000000 Binary files a/apps/documentation/public/teams/team-general-settings-document-visibility-select.webp and /dev/null differ diff --git a/apps/documentation/public/teams/team-general-settings.webp b/apps/documentation/public/teams/team-general-settings.webp deleted file mode 100644 index 3b5607e6a..000000000 Binary files a/apps/documentation/public/teams/team-general-settings.webp and /dev/null differ diff --git a/apps/documentation/public/teams/team-preferences-document-visibility.webp b/apps/documentation/public/teams/team-preferences-document-visibility.webp new file mode 100644 index 000000000..71674db01 Binary files /dev/null and b/apps/documentation/public/teams/team-preferences-document-visibility.webp differ diff --git a/apps/documentation/public/teams/team-preferences.webp b/apps/documentation/public/teams/team-preferences.webp new file mode 100644 index 000000000..efb6f00f7 Binary files /dev/null and b/apps/documentation/public/teams/team-preferences.webp differ diff --git a/apps/marketing/README.md b/apps/marketing/README.md deleted file mode 100644 index 950b58aee..000000000 --- a/apps/marketing/README.md +++ /dev/null @@ -1 +0,0 @@ -# @documenso/marketing diff --git a/apps/marketing/ambient.d.ts b/apps/marketing/ambient.d.ts deleted file mode 100644 index 54b8c1d7c..000000000 --- a/apps/marketing/ambient.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module '@documenso/tailwind-config'; diff --git a/apps/marketing/content/blog/announcing-direct-links.mdx b/apps/marketing/content/blog/announcing-direct-links.mdx deleted file mode 100644 index b52050ede..000000000 --- a/apps/marketing/content/blog/announcing-direct-links.mdx +++ /dev/null @@ -1,63 +0,0 @@ ---- -title: Launching Direct Links -description: Today, we are launching direct links to templates, a new and async way to get documents signed. -authorName: 'Timur Ercan' -authorImage: '/blog/blog-author-timur.jpeg' -authorRole: 'Co-Founder' -date: 2024-06-17 -tags: - - Announcement - - Direct Links - - Profiles ---- - -

- - -
Direct Template Links - Async signing, anytime.
-
- -> TLDR; We are launching direct links to templates. With direct links, a document is created from a template every time anyone signs the link. Links can be public. - -## Sync or Async? - -> Quick refresher on Sync vs. Async: Sync means everyone has to wait for me until they can continue their work. Async means everyone can and does their work at the time that fits best. - -Digital signing has become almost as normalized as email when doing business. While not 100% of companies are onboarded on digital signatures yet, hardly anyone is surprised when receiving a link to sign something digitally. As we got used to the user experience of sending emails, we also got used to the experience of sending document signature requests, with all the downsides: - -- I have to become active each time before anything can happen: I need to send a signature request -- My counterpart has to wait for me to send: "Did you send the signing link yet?" -- I need to monitor the requests I started for completion: "I sent you a link yesterday; please check it out." - -## Introducing Direct Links - -Today, we are introducing a new paradigm to signing: Async Direct Signing Links. Direct links are attached to a template and can be used anytime by anyone using the link. You set up the signature experience and flow once using all existing template mechanisms and you are done. You can provide anyone with the link so they can sign whenever they need to. You can even post the link publicly if you want to maximize its reach, i.e. for sales contracts. - - - -## Embrace Async - -So, how does this help anyone? You may still need to send a signature request to people, but in the cases you don't, you are not forced to anymore. Need an NDA? Check out our standing NDA link. A customer needs an updated Form W-9? Just use the company W-9 Link; it always has the most up-to-date form. You can even go as far as publicly posting a link to a software development or design contract any potential customer can sign anytime. Can they talk to you first? Sure, but if they don't need to or already have to, they go straight to the link. The process of actively sending has gotten us used to using a sync paradigm (I send, you receive and sign, and I get the result), whereas an async one (you sign whenever it suits you, and I become active only then, if at all) is way better suited. Adding more approval and signature steps makes sure you still control the outcome, but the process becomes a lot more efficient. For example, you can grab your own copy of the early adopter's pledge here if you missed it: [documen.so/pledge](https://documen.so/pledge). - -> Take a minute to think about every signing request you send and whether they really require you to be part of the transaction. Could they be outsourced to the recipient and only reviewed once their part is done? - -## Coming Soon: Profiles - -The best place to put your public links will be your **Documenso profile**, which is also close to launching. We want to get a feel for how links are used and move on to profiles shortly after. Want to try out direct links? Grab a free account here to get started: [documen.so/free](https://documen.so/free). - -As always, we want to hear from you on [Twitter / X](https://twitter.com/eltimuro) (DMs are open) or [Discord](https://documen.so/discord) if you have any questions, ideas, or comments. - -Best from Hamburg\ -Timur diff --git a/apps/marketing/content/blog/announcing-open-source-docusign-alternative.mdx b/apps/marketing/content/blog/announcing-open-source-docusign-alternative.mdx deleted file mode 100644 index eb318b028..000000000 --- a/apps/marketing/content/blog/announcing-open-source-docusign-alternative.mdx +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: Announcing Documenso -description: Launching an open-source document signing tool because trusted-based products should be built on openness. The first release will be in 2023. Sign up at documenso.com to be on board. -authorName: 'Timur Ercan' -authorImage: '/blog/blog-author-timur.jpeg' -authorRole: 'Co-Founder' -date: 2022-12-29 -tags: - - Announcement ---- - -
- - -
Documenso — The Open Source DocuSign Alternative.
-
- -## TL; DR; - -I'm launching an open source document signing tool because trust-based products should be built on openness. The first release will be in 2023. Sign up at documenso.com and get on board. - -## Let’s build the world’s most trusted document-signing tool. - -Today I'm excited to announce my new project Documenso. Documenso is an open source document signing tool you can host yourself and freely build upon because it's, you know, open source. Before I get more into the details of what and when will be launched I want to take a moment and talk about why. - -## Digital signing is great - -Signing Documents digitally has countless benefits: Less struggle with printing, less wasting paper, faster request delivery, easier changes, easier coordination of people far away, verifiable document integrity, and verifiable signer identity (this is a vast topic, will write more on soon), easier storage and search of signed documents, the list goes on. Digital Signatures take something very old and very trusted like personally signing documents into the digital space, adding the benefits listed above. It also introduces a new party to every signing transaction, the signing tool providers. What was peer to peer transaction before, now goes through an intermediary. While this isn't a problem in itself, it should make us think about how we want these providers of trust to work. - -## How do we build trusted systems? - -While doing research for Documenso I came upon a quote that expresses the current state of document signing pretty well: - -> Document signing is NOT a technical problem. [Editor’s Note: Because it was solved technically a long time ago] It’s a legal acceptance problem — and everyone KNOWS DocuSign and friends and understands how they’re admissible. Anything else would have to compete with that and people would be suspicious of it for a long time. - -While this may sound like a hurdle at first, it immediately gave me a sense of validation for a more open approach to signing. People will and should be suspicious of their tools and demand a high bar when it comes to trust. And the way to earn this trust is by being open. Trusted tools should be the result of thoughtful discussion and reviews. They should be the result of the needs and will of its community. They should be transparent, adaptable, and empowering while using. Open Source embodies these values very well for software, which makes it a perfect fit for this space and creating a high-trust tool. - -## Next Steps - -So, what can you expect from here on out? I've started to build Documenso 0.1 which is scheduled to release in “early” 2023. If you're interested in helping make this happen, let me know via [hi@documenso.com](mailto:hi@documenso.com). Getting working code into the hands of the perspective Documenso community is currently the #1 goal. Other than that I'll be releasing several articles about document signing and what something like Documenso should look like, in my humble opinion. So stay tuned! - -If you think Documenso is worthy of support, please share documenso.com with anyone interested, and sign up to be among the first to try out version 0.1 as soon as it launches. - -Cheers from Hamburg - -Timur diff --git a/apps/marketing/content/blog/announcing-profiles.mdx b/apps/marketing/content/blog/announcing-profiles.mdx deleted file mode 100644 index 1621e4007..000000000 --- a/apps/marketing/content/blog/announcing-profiles.mdx +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: Documenso Profiles Are Here -description: Today, we are launching Documenso Profiles, a new way to let your peers sign your documents. -authorName: 'Timur Ercan' -authorImage: '/blog/blog-author-timur.jpeg' -authorRole: 'Co-Founder' -date: 2024-07-01 -tags: - - Announcement - - Direct Links - - Profiles ---- - -
- - -
Let people sign anytime with Documenso Profiles. Try it [with my profile](https://app.documenso.com/p/timur).
-
- -> TLDR; We are launching a Documenso Profile where you can display your templates for everyone to sign at any time. - -## Introducing Documenso Profiles - -Today, I’m excited to announce that we are launching Documenso Profiles 🎉 While we have been focussing on the conventional signing experience so far, Direct Links and now profiles are our first steps to bring some long-awaited innovation back to digital signatures. - -Documenso Profiles allows you to share any template with a public link in a very easy-to-understand way. Adding templates to your profiles allows everyone to sign your documents just when they need to. Forms, NDAs, Disclaimers, and even contracts are now available anytime they are needed. Profiles turn the classic signing flow on its head by letting the recipient sign first before the document’s owner becomes active. Booking links (e.g., Cal.com) and customer self-service portals (e.g., Stripe Billing Portal) are becoming the norm, so it’s time we did the same for signing. - -## The Best Way to Share Your Singing Links - -With profiles, we want to offer you the best way to share your standing Documenso Template Links in a public place. You can add your Documenso Profile to your social profiles, Email footer, Video Description, or wherever your audience, customers, and partners interact with you. The profile will be a public, trusted place to ensure you know who you are dealing with. - -Looking at the classical social media fake profile problem, we know this is tricky to achieve. We will pay close attention to how profiles are used and how we can help the community use them easily and securely. As a first step towards this direction, we are introducing a trust badge next to your name. There will be 3 levels to start: - -- Free Users: No Badge -- Paid Users: Green Badge -- Early Adopters: Gold Badge - -
- - -
Add and remove templates anytime.
-
- -## An Open Economy built on Documenso - -We see offering profiles as a first step towards creating a full economy on top of the open signing ecosystem we envision. While we want to keep building the product with the community, we also want an economy to grow on the open tech we create. This includes using the tech (profiles) or offering service on top of the tech (hosting and customization). Our ecosystem is still young, and the goal is not to have Documenso Inc. as the only commercial actor but to fill our own niche in a global and thriving open ecosystem. One of our guiding principles is solving things once and for all. While our focus will be on the core signing product, we want to enable others to offer templates for use on profiles or privately. A lot of contracts, forms, and other paperwork have been recreated countless times. Offering high-quality, peer-reviewed templates is a natural extension of the current platform. There will be free templates, offered as marketing for their creators, and paid templates, offered as actual products. - -## What's next - -While an open signing economy is really exciting, we know it will take time to mature. Building out a mature ecosystem for builders and entrepreneurs takes time. While this aspect of Documenso matures, we will be focussing on the core of the platform: Letting you integrate and embed Documenso wherever you want it. - -If you already have a Documenso account, you can [activate your profile here](https://app.documenso.com/settings/public-profile). -Don’t have an account and want to check out profiles? You can do so using our [free plan](https://documen.so/free). - -As always, we want to hear from you on [Twitter / X](https://twitter.com/eltimuro) (DMs are open) or [Discord](https://documen.so/discord) if you have any questions, ideas, or comments. - -Best from Hamburg\ -Timur diff --git a/apps/marketing/content/blog/announcing-vial-21-cfr-part-11.mdx b/apps/marketing/content/blog/announcing-vial-21-cfr-part-11.mdx deleted file mode 100644 index b64953c8c..000000000 --- a/apps/marketing/content/blog/announcing-vial-21-cfr-part-11.mdx +++ /dev/null @@ -1,63 +0,0 @@ ---- -title: 21 CFR Part 11 is here, and so is Vial.com -description: We launched Vial.com with a 21 CFR Part 11 compliant setup. Reach out if 21 CFR Part 11 compliance is among your needs. -authorName: 'Timur Ercan' -authorImage: '/blog/blog-author-timur.jpeg' -authorRole: 'Co-Founder' -date: 2024-07-18 -tags: - - Vial.com - - 21 CFR Part 11 - - Compliance ---- - - -
- Vial.com uses Documenso for 21 CFR Part 11 compliant signing. -
- -> TLDR; We launched Vial.com on Documenso and are open for 21 CFR Part 11 business. - -# What is 21 CFR - -You have never heard of 21 CFR Part 11? You are in good company since most people haven't. If you have, you probably work in an industry regulated by the U.S. Food and Drug Administration (FDA). Title 21 of the Code of Federal Regulations (CFR) is dedicated to detailing FDA-regulated business, and sub-part 11 sets out guidelines for using electronic signatures in this highly regulated field. Hence, 21 CFR Part 11 is highly relevant for regulated industries that aim to employ digital signatures. The guidelines set out in 21 CFR Part 11 aim to provide trustworthy, reliable, and equivalent to paper records and handwritten signatures. All Industries that fall under the FDA's regulation, e.g. pharmaceuticals, biotechnology, medical devices, and biologics, must comply with these rules when choosing or creating systems for electronic signatures. - -Compliance with 21 CFR Part 11 is crucial for companies to use electronic records and signatures in their operations legally. It affects how companies manage documentation, conduct audits, and maintain regulatory submissions. Non-compliance can result in legal penalties, rejected submissions, and delays in product approvals, emphasizing the importance of adhering to these guidelines in FDA-regulated activities. - -# Vial.com - -Vial is a technology company on a mission to advance programs to market through computationally designed therapeutics and cost-effective clinical trials. It is imperative that Vial manages this process securely, effectively, and highly compliant. By leveraging it's modern platform, Vial aims to accelerate drug development and, ultimately, time to market for new therapies. You can learn more about them [here](https://vial.com/about-us). - -[Together](https://documen.so/vial-documenso), Documenso and Vial set out to create the first open-source, 21 CFR Part 11 compliant signing solution. After iterating over the product together, Vial moved their operation from DocuSign, a known legacy signing provider, to a Documenso Enterprise plan. We are very happy to be able to support Vial’s mission by fulfilling our own: bringing open signing and all its innovation to where it's needed. - -# 21 CFR Part 11 on Documenso Highlights - -21 CFR Part 11 is a highly complex statute, and going into the all design rationales and the following implementation details, deserves its own article later. For now, I want to share a few notable highlights. - -## The Full Experience - -We implemented 21 CFR Part 11, keeping the main user experience of Documenso intact. Our 21 CFR module is not separate but natively integrated into all Documenso flows, thus not sacrificing usability for compliance. This also means most (if not all) advanced features we offer are usable in a compliant way. This prevents customers from being trapped in an anti-innovation bubble, not allowing access to new features for fear of non-compliance. - -## Action Reauth Using Passkeys - - -
- Using passkeys (used here via fingerprint scanner) is the smoothest way to re-authenticate. -
- -One of the requirements affecting day-to-day life the most is the requirement to actually reauthenticate every signature placed on a document. While we can't change that, we can help make the reauthentication as painless as possible. To this end, we opted for passkeys. While Documenso supports passkeys to log in, they are also supported to authenticate signing on a per-signature level as part of the Documenso Enterprise Plan. The user still has to authenticate every signature but can now do so from the comfort of their passkey provider, be that 1Password, their browser, or any other provider. - -## Direct Links - -We recently launched [Direct Template Links](https://documen.so/direct-links), a new way to let people sign and fill out forms. Links can be completed anytime, creating a new document in the process. Direct Links are also 21 CFR part 11 compliant, using action reauthentication, audit log, and all other compliance requirements. - -# Documenso Enterprise Plan - -With the successful launch of Vial, we are now open for business. 21 CFR Part 11 compliance is part of the Documenso Enterprise plan, which includes all regulations we currently support and upcoming additions. While the pricing depends heavily on your needs and scale, we offer fixed-price plans for better predictability for both sides. In our experience, volume-based pricing is a legacy headache we want to avoid. - -If you are FDA-regulated and looking for a modern signing solution, we are happy to discuss your requirements in detail. You can write us (hi@documenso.com) or contact [our enterprise team](https://documen.so/21cfr) at any time or stage. - -If you have any questions or comments, please reach out on [Twitter / X](https://twitter.com/eltimuro) (DM open) or [Discord](https://documen.so/discord). - -Best from Hamburg\ -Timur diff --git a/apps/marketing/content/blog/building-documenso-pt1.mdx b/apps/marketing/content/blog/building-documenso-pt1.mdx deleted file mode 100644 index 4675bd9ab..000000000 --- a/apps/marketing/content/blog/building-documenso-pt1.mdx +++ /dev/null @@ -1,98 +0,0 @@ ---- -title: 'Building Documenso — Part 1: Certificates' -description: Let's take a look why you need a signing certificate and how Documenso does it. -authorName: 'Timur Ercan' -authorImage: '/blog/blog-author-timur.jpeg' -authorRole: 'Co-Founder' -date: 2023-06-23 -tags: - - Open Source - - Document Signature - - Certificates - - Signing ---- - -
- - -
- What actually is a signature? -
-
- -> Disclaimer: I’m not a lawyer and this isn’t legal advice. We plan to publish a much more specific framework on the topic of signature validity. - -This is the first installment of the new Building Documenso series, where I describe the challenges and design choices that we make while building the world’s most open signing platform. - -As you may have heard, we launched the community-reviewed version 0.9 of Documenso on GitHub recently and it’s now available through the early adopter’s plan. One of the most fundamental choices we had to make on this first release, was the choice of certificate. While it’s interesting to know what we opted for, this shall also serve as a guide for everyone facing the same choice for self-hosting Documenso. - -> Question: Why do I need a document signing certificate to self-host? -> -> Short Answer: Inserting the images of a signature into the document is only part of the signing process. - -To have an actual digitally signed document you need a document signing certificate that is used to create the digital signature that is inserted into the document, alongside the visible one¹. - -When hosting a signature service yourself, as we do, there are four main choices for handling the certificate: Not using a certificate, creating your own, buying a trusted certificate, and becoming and trusted service provider to issue your own trusted certificate. - -## 1\. No Certificate - -A lot of signing services actually don’t employ actual digital signatures besides the inserted image. The only insert and image of the signatures into the document you sign. This can be done and is legally acceptable in many cases. This option isn’t directly supported by Documenso without changing the code. - -## 2\. Create your own - -Since the cryptography behind certificates is freely available as open source you could generate your own using OpenSSL for example. Since it’s hardly more work than option 1 (using Documenso at least), this would be my minimum effort recommendation. Having a self-created (“self-signed”) certificate doesn’t add much in terms of regulation but it guarantees the document’s integrity, meaning no changes have been made after signing². What this doesn’t give you, is the famous green checkmark in Adobe Acrobat. Why? Because you aren’t on the list of providers Adobe “trusts”.³ - -## 3\. Buy a “trusted” certificate. - -There are Certificate Authorities (CAs) that can sell you a certificate⁴. The service they provide is, that they validate your name (personal certificates) or your organization’s name (corporate certificate) before creating your certificate for you, just like you did in option 2. The difference is, that they are listed on the previously mentioned trust lists (e.g. Adobe’s) and thus the resulting signatures get a nice, green checkmark in Adobe Reader⁵ - -## 4\. Becoming a Trusted Certificate Authority (CA) yourself and create your own certificate - -This option is an incredibly complex endeavour, requiring a lot of effort and skill. It can be done, as there are multiple CAs around the world. Is it worth the effort? That depends a lot on what you’re trying to accomplish. - -
.  .  .
- -## What we did - -Having briefly introduced the options, here is what we did: Since we aim to raise the bar on digital signature proliferation and trust, we opted to buy an “Advanced Personal Certificates for Companies/Organisations” from WiseKey. Thus, documents signed with Documenso’s hosted version look like this: - -
- - -
The famous green checkmark: Signed by hosted Documenso
-
- -There weren’t any deeper reasons we choose WiseKey, other than they offered what we needed and there wasn’t any reason to look much further. While I didn’t map the entire certificate market offering (yet), I’m pretty sure something similar could be found elsewhere. While we opted for option 3, choosing option 2 might be perfectly reasonable considering your use case.⁶ - -> While this is our setup, for now, we have a bigger plan for this topic. While globally trusted SSL Certificates have been available for free, courtesy of Let’s Encrypt, for a while now, there is no such thing as document signing. And there should be. Not having free and trusted infrastructure for signing is blocking a completely new generation of signing products from being created. This is why we’ll start working on option 4 when the time is right. - -Do you have questions or thoughts about this? As always, let me know in the comments, on twitter.com/eltimuro -or directly: documen.so/timur - -Join the self-hoster community here: https://documen.so/discord - -Best from Hamburg - -Timur - -\[1\] There are different approaches to signing a document. For the sake of simplicity, here we talk about a document with X inserted signature images, that is afterward signed once the by signing service, i.e. Documenso. If each visual signature should have its own digital one (e.g. QES — eIDAS Level 3), the case is a bit more complex. - -\[2\] Of course, the signing service provider technically can change and resign the document, especially in the case mentioned in \[1\]. This can be countered by requiring actual digital signatures from each signer, that are bound to their identity/ account. Creating a completely trustless system in the context however is extremely hard to do and not the most pressing business need for the industry at this point, in my opinion. Though, this would be nice. - -\[3\] Adobe, like the EU, has a list of organizations they trust. The Adobe green checkmark is powered by the Adobe trust list, if you want to be trusted by EU standards here: https://ec.europa.eu/digital-building-blocks/DSS/webapp-demo/validation, you need to be on the EU trust list. Getting on each list is possible, though the latter is much more work. - -\[4\] Technically, they sign your certificate creation request (created by you), containing your info with their certificate (which is trusted), making your certificate trusted. This way, everything you sign with your certificate is seen as trusted. They created their certificate just like you, the difference is they are on the lists, mentioned in \[3\] - -\[5\] Why does Adobe get to say, what is trusted? They simply happen to have the most used pdf viewer. And since everyone checks there, whom they consider trusted carries weight. If it should be like this, is a different matter. - -\[6\] Self-Signed signatures, even purely visual signatures, are fully legally binding. Why you use changes mainly your confidence in the signature and the burden of proof. Also, some industries require a certain level of signatures e.g. retail loans (QES/ eIDAS Level 3 in the EU). diff --git a/apps/marketing/content/blog/building-documenso-pt2.mdx b/apps/marketing/content/blog/building-documenso-pt2.mdx deleted file mode 100644 index 6955e856f..000000000 --- a/apps/marketing/content/blog/building-documenso-pt2.mdx +++ /dev/null @@ -1,117 +0,0 @@ ---- -title: 'Building Documenso — Part 2: Signature Validity' -description: Is a signature valid? And what does that mean? It's a surprisingly complex question; let's take a look. -authorName: 'Timur Ercan' -authorImage: '/blog/blog-author-timur.jpeg' -authorRole: 'Co-Founder' -date: 2024-04-05 -tags: - - Document Signature - - Certificates - - Signing ---- - -
- - -
- If a tree does not comply with the EU trust list, does it make a sound when validating?r -
-
- -> TLDR; Signatures can be valid and compliant for different signature levels, even if some validators show higher-level errors. Not all helpful security measures are mandated by law. - -# A valid question - -A few days ago, an early adopter brought up this question in our [Discord](https://documen.so/discord): - -
- - -
- You can check out the validator here: [https://documen.so/eu-validator](https://documen.so/eu-validator) -
-
- -For those unfamiliar with the tool, he used the validator tool of the EU's Digital Signature Service (DSS) Framework to check the signature of a document signed with Documenso. The EU provides this tool to help users and providers check the validity level of their signatures. - -A short refresher from [Building Documenso — Part 1: Certificates](https://documen.so/certs): - -> Documenso inserts all visual signatures into the document and then seals it using the "Documenso Inc." corporate certificate. This makes the resulting PDF document tamper-proof and guarantees it hasn't changed since signing. - -Before we answer if the document was signed correctly, we need to understand what the goal was. - -There are three signature levels in the European eIDAS regulation: - -1. **Simple Electronic Signatures (Level 1/ SES):** This is just a visual signature or even a checkbox on a document. - -2. **Advanded Electronic Signatures (Level 2/ AES)**: An actual crypographic signature (not just a seal on the whole document, but a specific signature), using a certificate linked to the identification data of the signer. - -3. **Qualified Electronic Signatures (Level 3/ QES):** Same as 2. but done by a government-certified entity on certified hardware and after identifying the signer with an official ID document (e.g., passport) - -> 💡 Side Note: Number 2 (AES) is how most people imagine digital signatures. But most of the market uses 1. plus a seal on the whole document under the name of the signing provider (e.g., Documenso). The signer's data is only inserted visually, not in the actual signature. Why? One of the reasons is that it's much easier, and without a readily available open source framework to draw from, it is quite tricky to build. This is something we aim to build (which many have done) and open source (which no one has done). - -From the perspective of eIDAS, Documenso offers Level 1/ SES signatures since it does not adhere to all of the requirements of Level 2/ AES. This means that, technically, there is no legal need to seal the document to achieve this level of validity (at least within eIDAS). We do it anyway since it improves the level of confidence users can have in the signed document. Sealing the document, even though not legally required, is a great example of Documenso's approach to signatures. First, we aim to provide all legal requirements for a given use case. Then, we add any protection that can be added without unwarranted friction to the creation of the signature. - -## Not if valid, but how valid - -**Q: So, is the signature in the image valid?** - -A: Yes, as an eidas Level 1 SES. - -**Q: Then why does it say "Unable to build a certificate chain up to a trusted list"** - -A: The certificate we use to seal the document after inserting the signatures is not on the EU Trust list. - -**Q: Does that mean it is less secure?** - -A: No, it means the provider (Wisekey) is not on a list maintained by the EU. The cryptographic signature is just as strong as any other - -For someone who does not deal with this stuff daily, this can be hard to comprehend. Whether you use a certificate you generated yourself, one generated by a certificate authority (CA) like Wisekey, or one by another on the EU trust list (e.g., Bundesdruckerei), the cryptographic security guaranteeing that the document has not been tampered with is always the same. Many providers like Documenso, DocuSign, PandaDoc, and Digisigner all use this method for their regular plans. That means if you were to run a document signed by them through the validator above, the result would be the same[1]. The interesting question is why? Why do it like this? - -## Certificate Infrastructure is broken - -While there are some actual expenses involved in providing AES and QES, the blunt reality is that it's just good business to charge for them per signature, making it unsuitable for the "standard offerings"; almost no one has the resources to set this up themselves. While this initial process of becoming a QES-certified entity is really expensive, selling the certificates afterward is very lucrative. This leads to less innovation in the space and only big players providing these high-compliance services. Even certificates only used to seal documents without being QES certified are sold for a large range of prices, and they cost almost nothing to produce. - -## Why Though? - -**Q: Why do people buy a certificate for money and not just generate one themselves? Isn't the cryptographic security the same?** - -A: Self-generated certificates are not recognized for higher-level compliance signatures like QES - -**Q: So if you don't need higher-level signatures, you could just generate one yourself?** - -A: Yes, you could. Since eIDAS Level 1 does not require a cert, you could use your own. - -**Q: Why don't more people?** - -A: One reason is that apart from the EU trust list, there are others, like the Adobe trust list. While not legally required, being on that one (like Wisekey) gives you a green checkmark in Adobe PDF, which is how most people check signature validity. - -**Q: Not a question, but all of this sounds weird** - -A: It is. This is one of the reasons why Documenso exists. We plan to make this easier. - -**Q: How?** - -A: By explaining and providing easy-to-use tools and eventually free, highly compliant signature certificates for everyone. - -Eventually, we plan to start a free certificate authority called Let's Sign, named after another instituion that broke the paid certificate paradigm to the benefit of the internet: [Let's Encrypt](https://letsencrypt.org/). - -As always, feel free to connect on [Twitter / X](https://twitter.com/eltimuro) (DM open) or [Discord](https://documen.so/discord) if you have any questions or comments. - -Best from Hamburg\ -Timur -\ -\ -\ -[1] The signature format (e.g. PKCS7-B) will vary. It's the format what the signature inserted into the document looks like. eIDAS itself does not specifically require any given format, but the PAdES defined by the EU is mostly used by european providers. diff --git a/apps/marketing/content/blog/cal.com-chooses-documenso-for-dpa-and-baa-scalability-and-compliance.mdx b/apps/marketing/content/blog/cal.com-chooses-documenso-for-dpa-and-baa-scalability-and-compliance.mdx deleted file mode 100644 index 37e41e7b0..000000000 --- a/apps/marketing/content/blog/cal.com-chooses-documenso-for-dpa-and-baa-scalability-and-compliance.mdx +++ /dev/null @@ -1,82 +0,0 @@ ---- -title: Cal.com Chooses Documenso for DPA and BAA Scalability and Compliance -description: Learn how Cal.com scales their Data Processing Agreement (DPA) and Business Associate Agreement (BAA) processes with Documenso’s open source platform as they grow. -authorName: 'Timur Ercan' -authorImage: '/blog/blog-author-timur.jpeg' -authorRole: 'Co-Founder' -date: 2024-10-11 -tags: - - Customer Story - - Open Startup - - Open Source ---- - -
- - -
- Scheduling Infrastructure for Everyone. -
-
-TL;DR: Cal.com uses Documenso’s template direct links to facilitate low-friction compliance paperwork, enhancing scalability and user experience. - -## Cal.com – The Most Public Private Company - -[Cal.com](Cal.com) is an open source company that needs no introduction. Founded in 2021 by Bailey Pumfleet and Peer Richelsen, it quickly evolved from an open source alternative to the widespread but limited scheduling platform Calendly into the internet’s most beloved scheduling solution. Starting with just two founders, Cal.com has grown into a team of 22, facilitating millions of bookings per year for its ever-growing user and customer base. - -Their commitment to transparency is evident as they follow the [open startup movement](https://cal.com/open), opening up not only their source code but also providing insights into their business operations. Their Commercial Open Source Software (COSS) model, combining a company and an open source project, has inspired a whole cohort of startups joining the space—not least of which is Documenso. - -## The Need - -At this point, Cal.com serves customers of all sizes, from single users to large enterprises. To provide the best product for their customers, they are certified for SOC 2, HIPAA, GDPR, and many other compliance regulations. One challenge that comes with this is the increasing number of waivers that need to be signed when onboarding customers. Business Associate Agreements (BAAs) and Data Processing Agreements (DPAs) are two of the more commonly known examples. To get these signed with minimal effort for both sides, they were looking for a solution to handle these at scale. - -> We love open source. - -— Peer Richelsen, Co-Founder, Cal.com - -Being an open source company, they also prefer open source in their vendors—for both the shared philosophy and the higher level of trust. The goal was to integrate signing into the checkout process as seamlessly as possible. - -## The Solution - -
- - -
- Sign a DPA with Cal by clicking a link anytime. -
-
- -Documenso offers exactly this solution through direct link templates, enabling Cal.com to: - -- Provide Immediate Access: Customers can access and sign necessary compliance documents through direct links at any time. -- Enhance User Experience: Users are immediately forwarded to onboarding after signing. -- Ensure Easy Access: The documents are stored within the company’s team account, allowing easy access for anyone who needs them. - -Direct Link templates can also easily be embedded, using the [Documenso widget](https://documen.so/embedded). Embedding anywhere, pre-Filling the templates and notfiying the compliance team at certain point of the flow are a few of the many option the team now has in continously enhanceing their onboard and compliance UX. - -Read more about our direct link templates here: [Direct Link Signing](https://docs.documenso.com/users/direct-links). - -## The Journey - -Initially, Cal.com’s team approached the new solution with skepticism. As Bailey reflected: - -> We were intrigued but skeptical at first, as we put a lot of thought into compliance and doing things right. Documenso’s documentation and support showcased how their direct link templates could meet our needs while being highly compliant. - -This experience highlights Documenso’s trust philosophy. We strive to be transparent in everything we do and let people judge for themselves. It also shows that we neither want nor get trust by default. Doing things right is a conversation worth having, especially in a space as opaque as digital signatures. It goes without saying that the whole team is hyped to have Cal.com on board and yet another open source company joining the open signing movement 🚀 - -If you have any questions or comments, please reach out on [Twitter / X](https://twitter.com/eltimuro) (DM open) or [Discord](https://documen.so/discord). - -Thinking about switching to a modern signing platform? Reach out anytime: [https://documen.so/sales](https://documen.so/sales) - -Best from Hamburg\ -Timur diff --git a/apps/marketing/content/blog/commodifying-signing.mdx b/apps/marketing/content/blog/commodifying-signing.mdx deleted file mode 100644 index 2bf1b2799..000000000 --- a/apps/marketing/content/blog/commodifying-signing.mdx +++ /dev/null @@ -1,87 +0,0 @@ ---- -title: Commodifying Signing -description: We are creating signing as a public good and are commoditizing it to make it cheaper and better. -authorName: 'Timur Ercan' -authorImage: '/blog/blog-author-timur.jpeg' -authorRole: 'Co-Founder' -date: 2024-01-25 -tags: - - Vision - - Mission - - Open Source ---- - -
- - -
- Lighthouses are often used as an example of a public good; As they benefit all maritime users, but no one can be excluded from using them as a navigational aid. Use by one person neither prevents access by other people, nor does it reduce availability to others. -
-
- -# Commodifying Signing - -> TLDR; We are creating signing as a public good and are commoditizing it to make it cheaper and better. - -While we are in full-on building mode with Documenso, I think a lot about the big picture of what we are attempting to do. One phrase that keeps popping up is, "We are commodifying signing." Let's dig deeper into what that means. - -Let's start with why we are doing this. Documenso's mission is to solve the domain of signing once and for all for everyone. In so many calls, I hear stories about how organizations build their own solution because the existing ones are too expensive or need to be more flexible. That means not hundreds but probably thousands of companies worldwide have done the same. This is simply wasting humanity's time. Since digital signing systems are understood well enough that seemingly "everyone" can build them, given enough pain, It's time to do it once correctly. - -## Is signing already a commodity? - -> In economics, a **commodity** is an economic good, usually a resource, that has explicitly full or substantial fungibility: that is, the market treats instances of the good as equivalent or nearly so with no regard to who produced them. - -That sounds like the signing market today. There is no shortage of signing providers, and you can get similar signing services from many places. So why is this different from what we want, and why does this not satisfy the market? - -- Signing is expensive and painful when you are locked into your vendor, and they charge by signing volume. -- Signing is also expensive and painful when you have to build it yourself since no vendor fits your requirements or you are not allowed to - -To understand why, we need to look at the landscape as it is today: - -- **Commodity**: Signing SaaS -- **Private Goods**: Signing Code Base, Regulatory Know-How -- **Public Goods**: Web Tech, Digital Signature Algorithms and Standards - -What the current players have done is to commodify the listed public goods into commercial products: - -> […]the action and process of transforming goods, services, ideas, nature, personal information, people, or animals into commodities. -> (Let's ignore the end of that list for now and what it says about humanity, yikes) - -While this paradigm brought digital signing to many businesses worldwide, we aim for a different future. To solve signing once and for all, we need to achieve two core points: - -- Making it cheaper so it's profitable for everyone to use -- Making it more accessible so everyone can use it (e.g. regulated industries) and flexible enough (extendable, open). - -To achieve this, we must transform the landscape to look like this: - -- **Commodities**: Enterprise Components, Support, Hosting, Self-Host Licenses -- **Public Goods**: (no longer private): OS (Open Source) Signing Code Base, OS Regulatory Know-How -- **Public Goods**: OS Web Tech, Digital Signature Algorithms and Standards - -## Raising the Bar - -Before creating a commodity, we are raising the bar of what the underlying public good is. Having an open source singing framework you can extend, self-host, and understand makes the resulting solution much more accessible and extendable for everyone. Now for the final feat of making signing cheaper: - -As we have seen, signing has already been commodified. But since it was done by a closed source and, frankly, a very opaque industry, no downward price spiral has ensued. By building Documenso open source with an open culture, we can pierce the veil and trigger what the space has been missing for a long time: Commoditization. If you had to read that again, so did I: - -> In business literature, **commoditization** is defined as the process by which goods that have economic value and are distinguishable in terms of attributes (uniqueness or brand) become simple commodities in the eyes of the market or consumers. - -By only selling what creates value for the customer (hosting a highly available service, keeping it compliant, supporting with technical issues and challenges, preparing industry-specific components), we are commoditizing signing since everyone can do it now: The resources enabling it are public goods, aka. open source. A leveled playing field, as described above, is the perfect environment for a community-first, technology-first, and value-first company like Documenso to flourish. - -## Changing the Game - -In this new world, a company needing signing (literally every company) can decide if the ROI (Return on Investment) of building signing themselves is greater than simply paying for the value-added activities they will need anyway. Pricing our offering not on volume but fixed is a nice additional wedge into the market we intend to use here. - -The market dynamic now changes to who can offer the greatest value added to the public goods, driving the price down as this can be done much more efficiently than locking customers into closed source SaaS. Documenso, being a lean company, which we intend to stay with for a long time, will help kickstart this effect. Open Source capital efficiency is real. Our planned enterprise components, hosting support, and partner ecosystem will all leverage this effect. - -We will grow our community around the public good, the open-source repo, and create an ecosystem around the commodities built on top of it (components, hosting, compliance, support). We will solve signing once and for all, and the world will be better for it. Onwards. - -As always, feel free to connect on [Twitter / X](https://twitter.com/eltimuro) (DM open) or [Discord](https://documen.so/discord) if you have any questions or comments. - -Best from Hamburg\ -Timur diff --git a/apps/marketing/content/blog/creating-an-efficient-statement-of-work-approval-process-with-documenso.mdx b/apps/marketing/content/blog/creating-an-efficient-statement-of-work-approval-process-with-documenso.mdx deleted file mode 100644 index aa20391de..000000000 --- a/apps/marketing/content/blog/creating-an-efficient-statement-of-work-approval-process-with-documenso.mdx +++ /dev/null @@ -1,96 +0,0 @@ ---- -title: Creating an Efficient Statement of Work Approval Process with Documenso -description: Submitting statements of work can be a drag on morale and project efficiency. Let's look at how to create a modern, low-friction workflow for this. -authorName: 'Timur Ercan' -authorImage: '/blog/blog-author-timur.jpeg' -authorRole: 'Co-Founder' -date: 2024-07-23 -tags: - - Freelancer - - Statement of Work - - Productivity ---- - -
- - -
Fine-tune your process using custom role for everyone involved.
-
- -> TLDR; Statements of Work detail what needs to be done. Automate sending and approving them using Documenso and Zapier. - -## What is a Statement of Work - -A statement of work is a detailed document that outlines what needs to be done in a project. It covers the project's scope, objectives, and deliverables, laying out all the tasks, deadlines, and milestones. The statement of work also spells out who’s responsible for what, ensuring everyone’s on the same page. It’s a roadmap that keeps both clients and service providers aligned and ensures the project stays on track from start to finish. - -In the context of freelance work, the statement of work is a document that outlines the details of a project between a freelancer and their client. It's a concrete work to be agreed upon and tracked after completion. The statement of work is created after the [proposal is accepted](https://documen.so/freelance-proposal) and the [contract signed](https://documen.so/freelance-contract). - -## What does a good workflow look like? - -### 1. Create the statement of work - -The team at Zapier created a [excellent guide](https://zapier.com/blog/statement-of-work-template/), which goes into the statement of work. There is a short checklist: - -- Project Context/ Current Scope -- Objectives for this piece of work -- Scope (tasks, activities, and limits) -- Requirements (e.g., technical and regulatory) -- Deliverables to be created -- Roles and Responsibilities - -### 2. Get approval from subject matter experts (optional) - -Since a statements of work can be very technical, having professionals from either side approve it first can be sensible. This can avoid double or unnecessary work and minimize the chances of misunderstandings. If this makes sense, it depends heavily on the scale of the project and the level of insight of the professional providing it. - -### 3. Let the client sign off - -Having the client sign off on the concrete work is the central step of the statement of work workflow. Assuming the document’s content is correct, getting the go-ahead ensures everyone is aligned and clear on what should and will be worked on. - -### 4. Inform other Stakeholders (optional) - -Depending on the scale of the organizations working together, other people may need to be kept in the loop. This could be accounting on either side, project managers, or other interested parties. - -## Fine-Tuning the Flow with Custom Roles - -
- -
- Let's take a look at what it would look like with Documenso. -
-
- -### 1. Creating the Document: Templates vs. Custom Document - -[Creating a template](https://docs.documenso.com/users/templates) can make sense if you submit statements of work regularly. If you create a Documenso Template, you can add [dynamic text and number fields](https://docs.documenso.com/users/signing-documents/fields) to be filled out when using the template. Another approach to this is creating a template on a document service like Google Docs, filling out a new copy, and uploading the custom-created document to Documenso. - -Different parts of this process can be automated using the [Zapier Documenso Integration](https://documen.so/zapier) as desired: - -- Automatically sending out a template to be filled out and signed -- Creating a document in Documenso from a newly created document in Google Docs -- Triggering sending a document created from either template or automation - -### 2. Approvals - -Looping in subject matter experts can easily be done using the approver role. This role allows you to complete a document without blocking the signing. This means the client can sign a document, even if the approval is not yet in place, removing friction. However, having the approval denied will stop the document from being completed and let everyone know there are corrections to be made. A software version of this is possible, having the expert in a viewer role and marking the document as seen without the option to block. - -### 3. Signers - -Looping in the client is done by adding one or more signer roles. Signer roles require recipients to place at least one signature to fulfill their part in the flow.roles - -### 4. BCC - -You can add one or several BCC roles to inform interested parties, e.g., accounting or project managers. As the process finishes, BCC recipients receive a copy of the completed document (assuming it completes and is not blocked). Using BCC roles automates filling in everyone who is only interested in the outcome and wants to avoid involvement in the steps leading up to it. - -### Conclusion - -Streamlining your statement of work approval process with Documenso can significantly improve productivity and ease. Using templates, dynamic fields, and Zapier integrations, you can create a smooth, efficient workflow from start to finish. Adding roles for experts, signers, and BCC recipients tailors the process to fit your project's needs, ensuring everyone stays on the same page. - -An efficient SOW process saves time and improves communication, letting you focus on delivering great work. We're excited to hear your thoughts and experiences—reach out on [Twitter / X](https://twitter.com/eltimuro) (DMs are open) or [Discord](https://documen.so/discord) if you have any questions, ideas, or comments. - -Best from Hamburg\ -Timur diff --git a/apps/marketing/content/blog/customer-story-prisma-4-reasons-prisma-choose-documenso-for-signing.mdx b/apps/marketing/content/blog/customer-story-prisma-4-reasons-prisma-choose-documenso-for-signing.mdx deleted file mode 100644 index 096ae234d..000000000 --- a/apps/marketing/content/blog/customer-story-prisma-4-reasons-prisma-choose-documenso-for-signing.mdx +++ /dev/null @@ -1,85 +0,0 @@ ---- -title: 'Customer Story Prisma: 4 Reasons why Prisma chose Documenso for Signatures' -description: We are happy to welcome Prisma, another OSS company, as a customer. Read here why they choose us. -authorName: 'Timur Ercan' -authorImage: '/blog/blog-author-timur.jpeg' -authorRole: 'Co-Founder' -date: 2024-09-26 -tags: - - Prisma - - Customer Story - - Open Source ---- - -
- - -
- Prisma uses Documenso for collaborative team signing. -
-
- -> TLDR; Prisma is now using Documenso, and [we added visibility scopes](https://docs.documenso.com/users/document-visibility) - -# Prisma - -Prisma is an open-source company known for its modern OSS ORM (Object-Relational Mapping) tools that simplify database interactions for developers. Their flagship product, Prisma ORM, provides a type-safe way to query databases like PostgreSQL, MySQL, and many more. With the addition of Prisma Studio, an intuitive database management interface, Prisma makes it easier and more efficient for developers to work with databases. With their new additions, Prisma Pulse and Accelerate, you can react to real-time database changes and optimize your queries. And they are completely [open source](https://github.com/prisma/prisma)! - -# We choose Prisma too! - -I discovered Prisma when planning the tech stack for the [first version of Documenso](https://github.com/documenso/documenso/releases/tag/0.9-developer-preview). Prisma has felt natural to use since day one and has been the base of our database architecture ever since. It's great to see them develop and grow with us. - -# Why they choose us - -## 1. Signature Flows - -Documenso signing flows are highly configurable, designed to adapt to the needs of any document signing process. Whether you're working with different roles, varying settings, or specific delivery methods, Documenso offers the flexibility to suit your requirements. You can choose to send documents via email, share a manual link, generate a link through the API, or even use a static direct link for quick access—all while ensuring a smooth signing experience. - -Additionally, you can create templates to streamline and reuse common workflows, saving valuable time. Direct link templates enable users to drive the flow themselves, providing a straightforward path for signing. For a seamless experience, Documenso also allows you to embed the signing process directly into your website, ensuring an uninterrupted, integrated workflow tailored to your needs. - -## 2. Modern UX - -
- - -
- We call Documenso's design "Happy Minimalism" -
-
- -We’ve crafted Documenso with a sleek, modern interface that makes it incredibly easy to use. Whether you’re signing documents, managing workflows, or fine-tuning settings, its intuitive design allows you to accomplish tasks quickly and effortlessly. More than just powerful, Documenso is a pleasure to navigate—designed to be accessible to everyone, no matter their level of tech experience. - -## 3. Teams - -### Teamwork Makes the Dream Work - -Documenso makes teamwork a breeze with its team management features. You can easily set up and organize teams, making it simple to share and manage documents and workflows together. This is a lifesaver for larger organizations or teams spread across different departments, ensuring everyone stays in sync and on track. Different visibility scopes ensure private documents stay private and others are shared for easy collaboration. - -### Document Visibility - -Collaboration within a team often demands different levels of access to documents. For instance, the Documenso team at Prisma needed a way to set custom visibility on some documents while keeping others accessible to everyone. To address this need, we introduced role-based visibility scopes. This feature allows teams to manage documents more effectively. They can make certain documents visible only to managers or, in special cases, restricted to admins. This ensures sensitive information stays protected while general documents remain accessible to those who need them. - -Learn more about visibility scopes and [how they can benefit your team here](https://docs.documenso.com/users/document-visibility). - -## 4. OSS! - -As you might know, we are open-source! This means you can peek under the hood, tweak things to your liking, and even contribute to making the platform better. We love the community-driven aspect of open-source, and it aligns perfectly with our goal to keep improving and innovating with input from our users. - -So, whether you're looking to streamline your document workflows or just need a solid, reliable platform, Documenso has got your back. And we're thrilled to serve another OSS company and help make the space more open. - -If you have any questions or comments, please reach out on [Twitter / X](https://twitter.com/eltimuro) (DM open) or [Discord](https://documen.so/discord). - -Thinking about switching to a modern signing platform? Reach out anytime: [https://documen.so/sales](https://documen.so/sales) - -Best from Hamburg\ -Timur diff --git a/apps/marketing/content/blog/deploy-with-vercel-supabase-resend.mdx b/apps/marketing/content/blog/deploy-with-vercel-supabase-resend.mdx deleted file mode 100644 index fb00f40bf..000000000 --- a/apps/marketing/content/blog/deploy-with-vercel-supabase-resend.mdx +++ /dev/null @@ -1,198 +0,0 @@ ---- -title: 'Deploying Documenso with Vercel, Supabase and Resend' -description: This is the first part of the new Building Documenso series, where I describe the challenges and design choices that we make while building the world’s most open signing platform. -authorName: 'Ephraim Atta-Duncan' -authorImage: '/blog/blog-author-duncan.jpeg' -authorRole: 'Software Engineer Intern' -date: 2023-09-08 -tags: - - Open Source - - Self Hosting - - Tutorial ---- - -In this article, we'll walk you through how to deploy and self-host Documenso using Vercel, Supabase, and Resend. - -You'll learn: - -- How to set up a Postgres database using Supabase, -- How to install SMTP with Resend, -- How to deploy your project with Vercel. - -If you don't know what [Documenso](https://documenso.com/) is, it's an open-source alternative to DocuSign, with the mission to create an open signing infrastructure while embracing openness, cooperation, and transparency. - -## Prerequisites - -Before we start, make sure you have a [GitHub](https://github.com/signup) account. You also need [Node.js](https://nodejs.org/en) and [npm](https://www.npmjs.com/) installed on your local machine (note: you also have the option to host it on a cloud environment using Gitpod for example; that would be another post). If you need accounts on Vercel, Supabase, and Resend, create them by visiting the [Vercel](https://vercel.com/), [Supabase](https://supabase.com/), and [Resend](https://resend.com/) websites. - -Checklist: - -- [ ] Have a GitHub account -- [ ] Install Node.js -- [ ] Install npm -- [ ] Have a Vercel account -- [ ] Have a Supabase account -- [ ] Have a Resend account - -## Step-by-Step guide to deploying Documenso with Vercel, Supabase, and Resend - -To deploy Documenso, we'll take the following steps: - -1. Fork the Documenso repository -2. Clone the forked repository and install dependencies -3. Create a new project on Supabase -4. Copy the Supabase Postgres database connection URL -5. Create a `.env` file -6. Run the migration on the Supabase Postgres Database -7. Get your SMTP Keys on Resend -8. Create a new project on Vercel -9. Add Environment Variables to your Vercel project - -So, you're ready? Let’s dive in! - -### Step 1: Fork the Documenso repository - -Start by creating a fork of Documenso on GitHub. You can do this by visiting the [Documenso repository](https://github.com/documenso/documenso) and clicking on the 'Fork' button. (Also, star the repo!) - -![Documenso](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wkcujctpf86p56bju3mq.png) - -Choose your GitHub profile as the owner and click on 'Create fork' to create a fork of the repo. - -![Fork the Documenso repository on GitHub](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xf49r2byu9nnd1465niy.png) - -### Step 2: Clone the forked repository and install dependencies - -Clone the forked repository to your local machine in any directory of your choice. Open your terminal and enter the following commands: - -```bash -# Clone the repo using Github CLI -gh repo clone [your_github_username]/documenso - -# Clone the repo using Git -git clone -``` - -You can now navigate into the directory and install the project’s dependencies: - -```bash -cd documenso -npm install -``` - -### Step 3: Create a new project on Supabase - -Now, let's set up the database. - -If you haven't already, create a new project on Supabase. This will automatically create a new Postgres database for you. - -On your Supabase dashboard, click the '**New project**' button and choose your organization. - -On the '**Create a new project**' page, set a database name of **documenso** and a secure password for your database. Choose a region closer to you, a pricing plan, and click on '**Create new project**' to create your project. - -![Create a new project on Supabase](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w5lqz771iupjyi1ekfdz.png) - -### Step 4: Copy the Supabase Postgres database connection URL - -In your project, click the '**Settings**' icon at the bottom left. - -Under the '**Project Settings**' section, click '**Database**' and scroll down to the '**Connection string**' section. Copy the '**URI**' and update it with the password you chose in the previous step. - -![Copy the Supabase Postgres database connection URL](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y1ldu3qrg9moednbzjij.png) - -### Step 5: Create a `.env` file - -Create a `.env` file in the root of your project by copying the contents of the `.env.example` file. - -Add the connection string you copied from your Supabase dashboard to the `DATABASE_URL` variable in the `.env` file. - -The `.env` should look like this: - -```bash -DATABASE_URL="postgres://postgres:[YOUR-PASSWORD]@db.[YOUR-PROJECT-REF].supabase.co:5432/postgres" -``` - -### Step 6: Run the migration on the Supabase Postgres Database - -Run the migration on the Supabase Postgres Database using the following command: - -```bash -npx prisma migrate deploy -``` - -### Step 7: Get your SMTP Keys on Resend - -So, you've just cloned Documenso, installed dependencies on your local machine, and set your database using Supabase. Now, SMTP is missing. Emails won't go out! Let's fix it with Resend. - -In the **[Resend](https://resend.com/)** dashboard, click 'Add API Key' to create a key for Resend SMTP. - -![Create a key for Resend SMTP](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uh2rztgn09mlvecl34i5.png) - -Next, add and verify your domain in the '**Domains**' section on the sidebar. This will allow you to send emails from any address associated with your domain. - -![Verify your domain on Resend](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nxgie0esz530vq5a494o.png) - -You can update your `.env` file with the following: - -```jsx -SMTP_MAIL_HOST = 'smtp.resend.com'; -SMTP_MAIL_PORT = '25'; -SMTP_MAIL_USER = 'resend'; -SMTP_MAIL_PASSWORD = 'YOUR_RESEND_API_KEY'; -MAIL_FROM = 'noreply@[YOUR_DOMAIN]'; -``` - -### Step 8: Create a new project on Vercel - -You set the database with Supabase and are SMTP-ready with Resend. Almost there! The next step is to deploy the project — we'll use Vercel for that. - -On your Vercel dashboard, create a new project using the forked project from your GitHub repositories. Select the project among the options and click '**Import**' to start running Documenso. - -![Create a new project on Vercel](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gdy97tltpnu7vf4fc11f.png) - -### Step 9: Add Environment Variables to your Vercel project - -In the '**Configure Project**' page, adding the required Environmental Variables is essential to ensure the application deploys without any errors. - -Specifically, for the `NEXT_PUBLIC_WEBAPP_URL` and `NEXTAUTH_URL` variables, you must add `.vercel.app` to your Project Name. This will form the deployment URL, which will be in the format: `https://[project_name].vercel.app`. - -For example, in my case, the deployment URL is `https://documenso-supabase-web.vercel.app`. - -![Add Environment Variables to your Vercel project](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aru33fk1i19h0valffow.png) - -This is a sample `.env` to deploy. Copy and paste it to auto-populate the fields and click ‘**Deploy.’** Now, you only need to wait for your project to deploy. You’re going live — enjoy! - -```bash -DATABASE_URL='postgresql://postgres:typeinastrongpassword@db.njuigobjlbteahssqbtw.supabase.co:5432/postgres' - -NEXT_PUBLIC_WEBAPP_URL='https://documenso-supabase-web.vercel.app' -NEXTAUTH_SECRET='something gibrish to encrypt your jwt tokens' -NEXTAUTH_URL='https://documenso-supabase-web.vercel.app' - -# Get a Sendgrid Api key here: -SENDGRID_API_KEY='' - -# Set SMTP credentials to use SMTP instead of the Sendgrid API. -SMTP_MAIL_HOST='smtp.resend.com' -SMTP_MAIL_PORT='25' -SMTP_MAIL_USER='resend' -SMTP_MAIL_PASSWORD='YOUR_RESEND_API_KEY' -MAIL_FROM='noreply@[YOUR_DOMAIN]' - -NEXT_PUBLIC_ALLOW_SIGNUP=true -``` - -## Wrapping up - -![Deploying Documenso](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/secg29j9j40o4u2oa8o8.png) - -Congratulations! 🎉 You've successfully deployed Documenso using Vercel, Supabase, and Resend. You're now ready to create and sign your own documents with your self-hosted Documenso! - -In this step-by-step guide, you learned how to: - -- set up a Postgres database using Supabase, -- install SMTP with Resend, -- deploy your project with Vercel. - -Over to you! How was the tutorial? If you enjoyed it, [please do share](https://twitter.com/documenso/status/1700141802693480482)! And if you have any questions or comments, please reach out to me on [Twitter / X](https://twitter.com/EphraimDuncan_) (DM open) or [Discord](https://documen.so/discord). - -We're building an open-source alternative to DocuSign and welcome every contribution. Head over to the GitHub repository and [leave us a Star](https://github.com/documenso/documenso)! diff --git a/apps/marketing/content/blog/design-system.mdx b/apps/marketing/content/blog/design-system.mdx deleted file mode 100644 index 24fe774b2..000000000 --- a/apps/marketing/content/blog/design-system.mdx +++ /dev/null @@ -1,49 +0,0 @@ ---- -title: Open Sourcing Documenso's Design -description: It's day 1 of our first launch week. We are kicking it off by open sourcing Documenso's design system! Let's go.. -authorName: 'Timur Ercan' -authorImage: '/blog/blog-author-timur.jpeg' -authorRole: 'Co-Founder' -date: 2023-09-25 -tags: - - Design - - Open Source - - Community ---- - -
- - -
- Documenso's Design System ✨ -
-
- -> TLDR; Our design system is OSS under MIT at [design.documenso.com](https://design.documenso.com) - -Today, we are open sourcing our design system, lovingly crafted by [Thilo](https://twitter.com/thilokonzok). The system is public on Figma and will be available at [design.documenso.com](https://design.documenso.com) from here on out. -We are publishing it under the MIT License so everyone can share, remix, and use it as it helps them most. - -We chose to start our first launch week with a design topic to emphasize the role design will play in Documenso's company and community culture. As it is historically difficult to bring together open-source software with great design, this is our first step towards encouraging a more design-driven COSS (Commercial Open Source) movement. - -## Designers Welcome - -We added a designer role in our Discord to create a space for designers to explore and discuss design-related topics of Documenso and signing in general. In the future, we want to foster more coding contributions and start a design culture around the product. As it is much more difficult to incorporate design contributions, we have yet to find a clear plan of what that will look like. I would like to see contributions around stuff we are NOT working on. Designs in that area can inspire and start discussions without the complexities of implementing them immediately — a free-thinking space around everything Documenso. Having a free mandate to design without restriction can create many exciting ideas. Some Ideas worth exploring: - -## Areas for design contributions - -- Explorations of exciting aspects of signing and document handling: -- What does signing look like when we no longer have skeuomorphic signatures? -- What is signing if we move beyond paper-inspired documents? -- What would the government process look like using Documenso? -- Solutions Concepts for features further down the roadmap, e.g., Widgets in websites - -These are fascinating ideas for explorative design. They won't be built 1:1 but shape how we think about signing and where it can go, which is even more critical. If you are interested in product design, you are invited to join our [Discord](https://documen.so/discord) and discuss the future of signing design or the future of Documenso's design system. Also let me know what you think on [X (formerly Twitter)](https://x.com/eltimuro). - -Best from Hamburg\ -Timur diff --git a/apps/marketing/content/blog/early-adopters.mdx b/apps/marketing/content/blog/early-adopters.mdx deleted file mode 100644 index ddd779fbc..000000000 --- a/apps/marketing/content/blog/early-adopters.mdx +++ /dev/null @@ -1,67 +0,0 @@ ---- -title: The Early Adopters Plan -description: Launch Week Day 4 and we are still early! Early enough for you to get a sweet deal for supporting Documenso's Mission. Join the movement and get a shiny early adopter account in the process. -authorName: 'Timur Ercan' -authorImage: '/blog/blog-author-timur.jpeg' -authorRole: 'Co-Founder' -date: 2023-09-28 -tags: - - Paid Plan - - Metrics - - Open Startup ---- - -
- - -
- "Being early is, uh, good." -Unknown -
-
- -> 🔔 UPDATE: We launched teams and the early adopters plan will be replaced by the new teams pricing as soon as all availible early adopters seats are filled. - -## Community-Driven Development - -As we ramp up hiring and development speed for Documenso, I want to discuss how we plan to build its core version. -As we want to be a highly community-driven product, we want to capture the thoughts and ideas of said community in two ways: - -1. Everything we plan (i.e. documen.so/roadmap) and build (i.e. documen.so/repo) is public and open to comments and suggestions from everyone by design. We plan to have discussions, streams, and articles showcasing what we're up to, encouraging feedback and iterations on our plans. -2. We're looking for 100 die-hard early adopters to get more deep hands-on feedback. If you want to be among the first to use and help shape Documenso, we have a special offer for you: - -## The Early Adopter Plan - -- All first 100 signups are entitled to the early adopter plan. -- The plan includes everything we build in the next 12 months and unlimited1 signatures -- This plan is priced at $30/mo. -- No matter what we add, the price is guaranteed for life as a thank you for supporting Documenso's mission2. And we plan to add a lot. -- This also includes unlimited users3 as part of the upcoming support for teams. -- If you already claimed an early adopter account in the past and canceled, we are happy to reactivate your account with the early adopter pricing. Reach out to support@documenso.com - -## Being an Early Adopter - -Being eligible for the early adopter plan has no formal requirements like giving feedback or being active in the community. In good faith, we assume you sign the Documenso Supporter Pledge to be part of this. And if you want to use the newest version quietly, that's fine, too. Everything the die-hard community brings up will be carefully considered and prioritized 4. Also, there will obviously be limited edition merch available for the first 100. -Documenso currently runs the community reviewed 0.9.1 version. Getting from here to the globally loved and adopted signing tool we all deserve will take a lot of work, and we want you on board to help us create it. Join us in shaping the future of open signing and having fun doing it. [Malfunction Mania](https://documenso.com/blog/malfunction-mania) and releasing 1.0 will go a long way. - -## Extending our open metrics - -As part of our ongoing effort to be open and transparent in our doing, we are adding "Early Adopters" to our [/open page](https://documenso.com/open) page. After we exceed the early adopter slots, this metric will transition to "Customers". When no more early adopter seats can be claimed, the early adopter plan will transition to a standard paid plan. It will still be priced at $30/mo., but will no longer include upcoming features or unlimited seats. - -If you have any questions or comments, please reach out on [Twitter / X](https://twitter.com/eltimuro) (DM open) or [Discord](https://documen.so/discord). - -Best from Hamburg\ -Timur - -\ -[1] Excluding signatures, we have to pay for i.e. third-party QES - -[2] The Documenso Manifest - -[3] Within reason. If you are unsure what that means, feel free to contact hi@documenso.com. But it should be fine if you don't plan to onboard a huge enterprise. - -[4] We won't be able to build everything everyone asks for. But we firmly plan to listen and build in a way everyone's requirements are met as well as possible. diff --git a/apps/marketing/content/blog/email-provider-incident-2024-01-10.mdx b/apps/marketing/content/blog/email-provider-incident-2024-01-10.mdx deleted file mode 100644 index 0f5279d6e..000000000 --- a/apps/marketing/content/blog/email-provider-incident-2024-01-10.mdx +++ /dev/null @@ -1,28 +0,0 @@ ---- -title: Jan 10th Email Provider Security Incident -description: On January 10th, 2022, we were notified by our email provider that they had experienced a security incident. -authorName: 'Lucas Smith' -authorImage: '/blog/blog-author-lucas.png' -authorRole: 'Co-Founder' -date: 2024-01-17 -tags: - - Security ---- - -On January 10th, 2024 we were notified by our email provider that a security incident had occurred. This security incident which had started on January 7th led to a bad actor obtaining access to their database which contains ours and other customer’s data. - -We understand that during this security incident the following has been accessed: - -- Email addresses. -- Metadata on emails sent excluding the email body. - -While the incident is unfortunate we are pleased with the remediation and the processes that our email provider has put in place to help avoid this kind of situation in the future. Since the incident, our provider has rectified the issue and has engaged a security company to conduct an exhaustive investigation and to help improve their security posture moving forward. - -We remain steadfast in our commitment to our current email provider, and will not be taking any further action with relation to changing providers. - -We are now working with our legal counsel to ensure that we provide the appropriate notice to all our customers in each jurisdiction. If you have any further questions on this incident please feel free to contact our support team at [support@documenso.com](mailto:support@documenso.com). - -We appreciate your ongoing support in this matter. - -You can read more on the incident on our providers blog post below: -[https://resend.com/blog/incident-report-for-january-10-2024](https://resend.com/blog/incident-report-for-january-10-2024) diff --git a/apps/marketing/content/blog/go-fork-yourself.mdx b/apps/marketing/content/blog/go-fork-yourself.mdx deleted file mode 100644 index 4512d7be5..000000000 --- a/apps/marketing/content/blog/go-fork-yourself.mdx +++ /dev/null @@ -1,86 +0,0 @@ ---- -title: Go Fork Yourself -description: Curious about our take on open-source and code forking? Discover why we see forking not as a threat but as a vital part of the Open Source ecosystem. -authorName: 'Timur Ercan' -authorImage: '/blog/blog-author-timur.jpeg' -authorRole: 'Co-Founder' -date: 2024-10-03 -tags: - - Culture - - Open Startup - - Open Source ---- - -> TLDR; At Documenso, we see OSS as co-owned by all. Forking—collaborative or not—is part of the open-source spirit. - -## Freedom vs. Ownership - -Recently, there has been a lot of debate on the subject of forks and the usage of OSS IP (Open Source Software Intellectual Property). While I mostly aim to stay out of these controversies (as there is no “winning”), I wanted to take this opportunity to share my views on IP and forking culture here at Documenso. I don’t presume this is the ideal path, but for me, it’s the only path that makes sense. - -What these issues show foremost, in my opinion, is that the concept of Open Source is still evolving. I have heard many say, “Open Source is clearly defined” and that there is no ambiguity anymore. That may be true on the legal side, but there are vast differences in how these rules are interpreted and lived out. Here are a few questions to illustrate the point: - -1. Is it okay to use an open-source project without ever giving back? -2. Is it okay to fork (some might say copy) an OSS product and build something on top of it? -3. Are we morally obliged to fight those who provide different answers to these questions than we do? - -## Embracing Forks and Collaboration - -Since starting Documenso, I’ve thought a lot about what it actually means to be Open Source for us. So far, it has been about openness in working with everyone, from contributors to customers and sharing our work transparently. For this, we have been richly rewarded with attention and reach. This collaborative give-and-take is what people commonly associate with being Open Source, and it seems ideal. - -Yet, there are the questions mentioned above. And while these may be contentious, my take is straightforward: - -1. Yes. -2. Yes. -3. No. - -I say this because, to me, the principles of Open Source are rooted in freedom and collaboration. That means allowing others to use, improve, or even compete with what you’ve built without feeling possessive over the code. The beauty of Open Source lies in its openness—its ability to be forked, reused, and adapted by anyone. - -You may answer these questions differently for your own reasons. One thing I’ve found lacking in the discourse is the fact that Open Source is still being treated as socially proprietary. If it’s under an open-source license, you can fork it and try to improve upon the original, and there’s nothing wrong with that. The same is true for closed-source startups. Yet in Open Source, there’s a notion that it’s somehow “dirty,” even though the license explicitly allows it. - -## Forking in Action: Real-World Examples - -When the team behind **Node.js** disagreed with its governance and pace of development, they forked the project to create **io.js**. This wasn’t seen as dirty but as a necessary push for change. In fact, the fork resulted in positive changes—better community governance and faster development—which eventually led to the merge of the two projects under the Node.js Foundation. It shows that forking can be a catalyst for improvement, not just competition. - -## The Misconception of “Exploitative” Usage - -However, sometimes forks don’t merge back but still bring positive change. A good example is **Jenkins**, which was forked from **Hudson** over disagreements in governance after Oracle acquired Sun Microsystems. Jenkins quickly overtook Hudson in terms of community support, development, and innovation. Rather than being seen as a hostile move, the fork enabled Jenkins to become a thriving project, better aligned with the open-source ethos of collaboration and transparency. It emphasizes that forking isn’t inherently exploitative; it can simply be a way to realize a project’s full potential. - -And then there’s **MariaDB**, a fork of **MySQL**. After Oracle acquired MySQL, many in the community feared the project’s open-source nature could be compromised. The fork preserved its spirit, and MariaDB has since grown to become a popular and thriving database. It’s a reminder that sometimes, forking is not just acceptable—it’s necessary to uphold the values and freedoms of open-source software. - -
- - -
- Funny Meme to drive the point home. -
-
- -My view is that the code is not “your” code, just as Documenso’s code is not “our” code. It’s been co-owned by the world ever since we published the repo under AGPL V3. That is the whole point. It’s finally not owned by anyone (cue the “everyone/no one” meme). Open Source is for everyone, even competitors. Yet, we are still treating the licenses as extensions of the old, proprietary world and defending perceived injustices based on that model. - -> Side Note: Full compliance with all license and other legal rules is a given here. - -## Documenso’s Approach: Co-Ownership and Community - -So, if you want to fork Documenso and build a business on it, you can. Whether that’s a cool thing to do is another matter. Whether you do a better job than us is also another matter (you won’t). But if you do, I’ll be the first to join. But why not join us from the start since you already have the upside? We exist because we believe this to be the best way forward—not because we force it. - -## The Bigger Picture: Open-Source as Progress - -I’ve also thought a lot about question #3. I understand the impulse to fight anyone who doesn’t appreciate this collaborative approach, but there is no part of this model that backs that up. You are free to “exploit” as long as it’s in a way that adds value. The fallacy is in considering someone else using the OSS part for their business as treason, which it’s not. It’s the whole point. - -While some might say this is theoretical and that reality is different, this is the version of Open Source on which we are building Documenso. The point here is that OSS companies must be resilient to handle forking and competition; without this resilience, an open source driven economy can’t thrive. The focus on freedom and collaboration means being prepared for forks and challenges as part of the growth, not as threats. - -Of course, all of this applies to Documenso, the OSS project, not Documenso Inc., the company, which is very much a privately owned, for-profit entity. However, since the goal is to scale Documenso to the entire world, there is plenty of room to see everyone as co-owners of the Open Source project rather than as competitors. In the end, Open Source is about progress through freedom. If you don’t like how we run things, go fork yourself and hold us accountable. We don’t own this; we just happened to start it. - -> Since this article is open source as well, you are free to fork it and change it here: [https://documen.so/repo](https://documen.so/repo) - -If you have any questions or comments, please reach out on [Twitter / X](https://twitter.com/eltimuro) (DM open) or [Discord](https://documen.so/discord). - -Thinking about switching to a modern signing platform? Reach out anytime: [https://documen.so/sales](https://documen.so/sales) - -Best from Hamburg\ -Timur diff --git a/apps/marketing/content/blog/how-documenso-enhances-contract-management-for-freelancers-helping-them-close-more-clients-efficiently.mdx b/apps/marketing/content/blog/how-documenso-enhances-contract-management-for-freelancers-helping-them-close-more-clients-efficiently.mdx deleted file mode 100644 index fc837932a..000000000 --- a/apps/marketing/content/blog/how-documenso-enhances-contract-management-for-freelancers-helping-them-close-more-clients-efficiently.mdx +++ /dev/null @@ -1,103 +0,0 @@ ---- -title: How Documenso Enhances Contract Management for Freelancers, Helping Them Close More Clients Efficiently -description: Making it easy for the customer to sign the contract after they say yes is critical. Let take a look how Documenso can help. -authorName: 'Timur Ercan' -authorImage: '/blog/blog-author-timur.jpeg' -authorRole: 'Co-Founder' -date: 2024-06-20 -tags: - - Freelancer - - Proposal - - Productivity ---- - -## Yes to Yes - -> [Check out Part 1](https://documen.so/freelance-proposal) to learn about signing freelance proposals with Documenso and getting your first yes - -A basic rule of sales is going from "yes to yes”. Outlining the main points of working together in a proposal is a good way to get to your first yes since it reduces details and focuses on the main points of the work at hand. After being on the same page about the work and getting the first yes, it's time to draw up a formal contract. While agreeing to the proposal has some weight as well, the legal contract formalizes the commitments of both sides in an enforceable way. Having clear legal terms on payments, unexpected cases, and even dissolving the partnership helps both parties to feel assured about what to expect. - -### **Digital Signatures for the Win** - -Digitally signing documents accelerates contract closure, enhancing both speed and security. Parties can review and sign documents within minutes, eliminating the days required for manual signatures or even weeks with traditional mail. Beyond these efficiency gains, digital signatures boost trust by making the process secure and auditable. Once signed, digital documents are immutable, and every step is logged. - -Documenso simplifies this process, allowing you to send contracts effortlessly. As an open-source solution, our product's integrity and security are verifiable by anyone, which is why thousands of users rely on Documenso for their signing needs. Discover more at [https://documen.so/open](https://documen.so/open). - -## Preparing the Contract - -As a freelancer, obtaining a contract template ensures you have a standardized and professional agreement ready for new clients, helping to protect your interests and clarify project terms. While there are many good templates out there, be sure to verify that they fit your case since contracts are often very specific to a certain case. Always consider having your contract checked by a legal professional if it's a high-value transaction. - -Here is a quick checklist of what your contract should include: - -### Checklist - -- Names and Addresses of you and your client -- Scope of Work to be performed, deadlines and deliverables -- Payment Terms, Payment Schedules, and Pricing -- A clear timeline -- Provisions for unexpected extra work -- Intellectual Property Rights Provisions -- Confidentiality and Non-Disclosure Agreements, if needed -- Termination Clauses: Condition and terms when the contract can be terminated, including notice period and compensation -- Indemnity and Liability -- Dispute Resolution -- Provisions ensuring changes can only be made in writing -- Completeness Agreement: Both parties state this is the full extent of the agreement -- Severability Clause ensuring minor errors will not endanger the whole contract -- The signees with name, role, and date - -## Getting the Signature - -Once you have your contract ready, you can upload it and add recipients and signature fields. To add a more personal touch, consider adding a personal message to the signature request. - -
- - -
- Copy recipient links to send them for a personal touch manually. -
-
- -You can also copy the link for each recipient after sending it and send it via another channel e.g. WhatsApp with a personal message. To further customize the experience, you can define a redirect when your customer signs the contract to redirect them to a Cal.com Link to get started, a Thank You Page, or a Form. - -
- - -
- Redirect after Signing for a more personal experience. -
-
- -The more you add to the workflow, the more important it is to keep up to date with the process. Using Zapier, you can add a variety of notifications, from email to Discord messages, to keep a good overview and respond quickly. It's not just about getting the signatures; it's about creating the workflow that provides the best experience for you and your customers. - -
- - -
- Trigger any kind of notification with[Zapier](https://documen.so/zapier) -
-
- -### Conclusion - -Sending a contract to clients using Documenso makes the process fast and easy. Seeing if your contract was signed or even read helps you understand where you are in the process. You can use the [Documenso Free Plan](https://app.documenso.com/signup?utm_source=blog-freelancer-contract) to send 5 contracts per month. Digital signing in 2024 is the best practice for professionals seeking the most efficient way to get business done. - -Let us know what you think and what we can improve. Connect with us on [Twitter / X](https://twitter.com/eltimuro) (DM open) or [Discord](https://documen.so/discord) if you have any questions or comments! We're always here and would love to hear from you :) - -Best from Hamburg\ -Timur diff --git a/apps/marketing/content/blog/how-documenso-help-freelancers-close-more-clients-efficiently.mdx b/apps/marketing/content/blog/how-documenso-help-freelancers-close-more-clients-efficiently.mdx deleted file mode 100644 index 7d7265842..000000000 --- a/apps/marketing/content/blog/how-documenso-help-freelancers-close-more-clients-efficiently.mdx +++ /dev/null @@ -1,76 +0,0 @@ ---- -title: How Documenso Helps Freelancers Close More Clients Efficiently -description: Reducing friction when sending proposals is critical to closing new clients. By using Documenso, freelancers can save time, enhance client interactions, and ultimately close more deals efficiently. -authorName: 'Timur Ercan' -authorImage: '/blog/blog-author-timur.jpeg' -authorRole: 'Co-Founder' -date: 2024-06-14 -tags: - - Freelancer - - Proposal - - Productivity ---- - -Getting new clients, or maybe even your first client, to sign with you is at the very core of freelance work. Whether you develop software, create designs, or market products, it all starts with a signature from you and your future customer. Closing a customer usually means agreeing on a proposal first and then signing a formal agreement afterward. Signing proposals and contracts is fast, easy, and painless with Documenso, so let's take a look. - -## Understanding Proposal and Contracts - -### 1. Initial Proposal - -> Agreeing on what needs to be done and terms for payment - -A proposal will include the scope of the work (what does the customer want done?), desired deliverables (documents, code, features, videos, etc.), timelines, payment terms (one-time, monthly, per hour), and prices (e.g. $60/ hour, $5k one-time). A proposal is important for both sides to be clear about the goal and the terms that apply. Customers usually decide based on the proposal if your offer is what they want. - -### 2. Formal Contract - -> After the client signs the proposal, a contract can be signed, formalizing the agreement and adding detailed legal terms. - -Once the terms are agreed upon, a more formal document should specify the terms of working together, especially legal details such as confidentiality, indemnification, governing law, etc. The contract provides clarity on legal details for both sides and formalizes their claims. - -Sending one or even multiple documents to a potential client and having them send them back signed (in the worst case, they send it via actual mail) is time-consuming for both sides. It also introduces friction at a time when making it as easy as possible for your potential client to say yes should be your number one goal. - -### **Digital Signatures for the Win** - -Signing documents digitally makes closing proposals and contracts faster and more secure. Each party can review and sign the documents in minutes instead of days (inserting the signatures manually via PDF editor) or even weeks (using conventional mail). Apart from the efficiency gains, signing digitally also increases trust by making the process more secure and auditable. Digitally signed documents can’t be changed after the fact, and every step of the process is logged. - -Documenso lets you reap these benefits by sending proposals and contracts with minimal effort. Being open source, the whole world can verify our product and how we deliver on these promises, which is why thousands of users already trust Documenso for their signing needs: [https://documen.so/open](https://documen.so/open). - -## Preparing the Proposal - -If you already have a proposal template, create a new version for your client and export it to PDF. If your tool doesn’t support that, your system's “PDF printer” lets you create a PDF from almost any tool by using the print function. If you do not have a template yet, you can find a lot of content and guides on the matter through a quick Google search. Here is a quick checklist of what your proposal should cover: - -- A clear and concise title -- Your contact information -- Date of the proposal/ validity period -- Experience, qualifications, and prior relevant projects -- A summary of the project -- A detailed description of the project -- Goals, outcomes, and deliverables -- Tasks and activities to achieve the goals and outcomes -- A timeline with milestones and deadlines -- Pricing terms and payment schedule -- Summary of major terms for the coming contract - -## Sending the Proposal - -If you don’t have a Documenso Account yet, you can [create one for free](https://documen.so/signup?utm_source=blog-freelancer-proposal). Once you sign up, you can upload your proposal PDF by simply dragging it into the upload area. Add your potential client as a recipient, add a signature field, and you are done! You can track the status of your proposal simply by clicking the Document in the overview. Documenso will also notify you once the proposal is signed. - - - -### Conclusion - -Sending a proposal to potential clients using Documenso makes getting to the first “yes” fast and easy. Seeing if your proposal was signed or even read helps you to get a feel for where you are in the process. You can use the [Documenso Free Plan](https://app.documenso.com/signup?utm_source=blog-freelancer-proposal) to send 5 proposals per month. Digital Signing in 2024 is the best practice for all professionals looking for the most efficient way to get business done. - -> [Check out Part 2](https://documen.so/freelance-contract) to learn about signing freelance contracts with Documenso. - -Let us know what you think and what we can improve. Which field types are you missing? Connect with us on [Twitter / X](https://twitter.com/eltimuro) (DM open) or [Discord](https://documen.so/discord) if you have any questions or comments! We're always here and would love to hear from you :) - -Best from Hamburg\ -Timur diff --git a/apps/marketing/content/blog/introducing-advanced-signing-fields.mdx b/apps/marketing/content/blog/introducing-advanced-signing-fields.mdx deleted file mode 100644 index 8e873c120..000000000 --- a/apps/marketing/content/blog/introducing-advanced-signing-fields.mdx +++ /dev/null @@ -1,599 +0,0 @@ ---- -title: 'Enhancing Document Signing: Introducing 5 New Advanced Fields' -description: "Explore Documenso's new advanced signing fields, including improved text fields, numbers, radio buttons, checkboxes, and dropdowns. Learn about the development challenges we overcame and how these additions provide greater flexibility for document signing." -authorName: 'Catalin Pit' -authorImage: '/blog/blog-author-catalin.webp' -authorRole: 'I like to code and write' -date: 2024-08-09 -tags: - - Signing fields - - Development ---- - -Until recently, Documenso provided a set of 5 fields for document signing: signature, email, name, date, and a text field for additional information. While these fields covered the basic requirements for document signing, we recognized the need for more flexibility and variety. - -As a result, we've decided to introduce several additional fields, such as: - -- _(an improved)_ Text field -- Number field -- Radio field -- Checkbox field -- Dropdown/Select field - -These new fields bring more flexibility and variety to Documenso. As the document owner, they allow you to gather more specific or extra information from the signers. - -## New Fields Introduction - -Let's take a closer look at each new field type. - -### Text Field - -While the text field was previously available, it could not be configured. It was a simple input box where signers could enter a single line of text. - -The image illustrates the old text field in the document editor. - -![Old text signing field in the Documenso document editor](/blog/advanced-fields/old-text-field.jpeg) - -The revamped text field now offers a range of configuration options, allowing you to: - -- Add a label, placeholder, default text, and character limit -- Set the field as required or read-only - -![The advanced settings tab for the text field in the Documenso document editor](/blog/advanced-fields/text-field-advanced-settings.webp) - -On the signing side, the field remained mostly the same visually. The only thing that changed is the functionality, which needs to take into consideration the validation rules. For example, if the field is required, the signer must enter a value to sign it. Or, if the field has a character limit, the value entered by the signer shouldn't exceed the limit. - -The image below illustrates four different text fields with various configurations. - -![The text signing field on the Documenso signing page](/blog/advanced-fields/text-field-signing.webp) - -The first text field has no default value ("Add text") or configuration. You can sign the field by entering any text. - -![The first text field input](/blog/advanced-fields/first-text-field-input.webp) - -The second text field, "label-1"/"text-1", has the following configurations: - -- Label -- Placeholder -- Default text -- Character limit - -Since there is a default value, the field auto-signs with that value. However, you can re-sign the field with a new value that doesn't exceed the character limit. - -![The second text field input](/blog/advanced-fields/second-text-field-input.webp) - -The third field, "label-2"/"text-2", has the same configurations as the second one, with one addition - the `required` option is checked. When the field is marked as `required`, you must sign it before completing the document. - -Apart from that, it works like the second field. - -![The third text field input](/blog/advanced-fields/third-text-field-input.webp) - -The fourth field, "label-3"/"text-3", has the same configurations as the second one, with one addition—`read-only` is checked. That means the field auto-signs with the default value, and you cannot modify it. - -#### Unsigned Fields - -You can unsign a field to change the value and sign it again. The unsigned state of the field varies depending on its configuration: - -- If the field has a label, it displays it instead of "Add text" when unsigned. -- If the field has a default value, the default value will be shown when unsigned. -- If the field has both a label and a default value, the label will take precedence and be displayed when unsigned. - -The image below shows the unsigned state of the text fields. - -![A screenshot illustrating the various text fields unsigned](/blog/advanced-fields/unsigned-text-fields.webp) - -The only exception is the fourth, read-only field, which cannot be unsigned or modified. - -### Number Field - -We also introduced a new "Number" field for inserting and signing documents with numeric values. This field helps collect quantities, measurements, and other data best represented as numbers. - -![The advanced settings tab for the number field on the Documenso document editor page](/blog/advanced-fields/number-field-advanced-settings.webp) - -The "Number" field offers a range of configuration options, which allows you to: - -- Set a label, placeholder and default value -- Specify the number format -- Mark the field as _required_ or _read-only_ -- Specify minimum and maximum values - -The Number field looks and works similarly to the Text field. The difference is that it accepts only numeric values and has 2 additional configurations: the number format and the minimum and maximum values. - -### Radio Field - -Radio buttons allow signers to select a single option from a pre-defined list the document owner sets. - -Before sending the document for signing, you must add at least one radio option, which can contain a string or an empty value and can be checked or unchecked. However, it's important to note that only one option can be checked at a time. - -When it comes to field configuration, you can mark the field as _required_ or _read-only_. - -![The advanced settings tab for the radio field in the Documenso document editor](/blog/advanced-fields/radio-field-advanced-settings.webp) - -The image below shows what the signer sees after the document is sent for signing. - -![The radio signing field on the Documenso signing page](/blog/advanced-fields/radio-field-sign-page.webp) - -Note: The image is modified to display both the unsigned and signed states of the field. - -Since the field has a preselected option (option `radio-val-2-checked`), it will automatically sign with that value and appear like the field marked with the number 1. - -If the field is not read-only, the signer can: - -- Unsign the field and choose another option by clicking on it. -- Re-sign with the default value by refreshing the page when the field is unsigned. - -However, if the field is marked as read-only, the signer cannot modify the preselected value. - -### Dropdown/Select Field - -We have also introduced a new "Dropdown/Select" field that allows signers to pick an option from a pre-defined list of choices. This field type is ideal for scenarios with limited valid options, such as selecting a country, state, or category. - -When setting up a "Dropdown/Select" field, you can: - -- Add multiple options -- Mark the field as _required_ or _read-only_ -- Pick a default option from the list of choices - -![The advanced settings tab for the select field in the Documenso document editor](/blog/advanced-fields/select-field-advanced-settings.webp) - -On the signing page, the "Dropdown/Select" field appears as shown below: - -![The select field on the Documenso document signing page](/blog/advanced-fields/select-field-sign-page.webp) - -Here's how the "Dropdown/Select" field works: - -- If no default value is set, the field will not auto-sign. The signer must click on the field and select an option from the dropdown list to sign it. -- After signing, the field displays the selected value, similar to a signed text field. -- If the field is marked as required, signers must select a value before completing the signing process. -- If the field is marked as read-only, signers can view the selected value but cannot modify it. - -### Checkbox Field - -The last field introduced is the "Checkbox" field, which allows signers to select multiple options from a pre-defined list. This field is helpful for scenarios where signers need to choose multiple items or agree to several terms and conditions, for example. - -Before sending the document for signing, you must add at least one checkbox option. This option can contain a string or an empty value and can be checked or unchecked. Unlike the "Radio" field, the "Checkbox" field can have multiple checked options. - -Like other fields, you can mark the "Checkbox" as _required_ or _read-only_. In addition to that, it also has a validation field, and you can specify how many checkboxes the signer should sign: - -- Select at least X _(a number from 1 to 10)_ -- Select at most X _(a number from 1 to 10)_ -- Select exactly X _(a number from 1 to 10)_ - -![The advanced settings tab for the checkbox field in the Documenso document editor](/blog/advanced-fields/checkbox-field-advanced-settings.webp) - -When a signer receives the document, they will see the "Checkbox" field as shown below: - -![The checkbox field on the Documenso document signing page](/blog/advanced-fields/checkbox-sign-page.webp) - -The image illustrates both field states - signed and un-signed. In this example, the 'Checkbox' field has two options checked by default, so it auto-signs. - -The field marked '1' appears when the signer visits the page for the first time or when the user refreshes the page and no option is selected. The field marked '2' displays the cleared state, where all choices have been deselected. This shows how the field looks when a user clears all selections. - -In this example, no validation rule has been set, allowing the signer to select any options. However, when a validation rule is applied, signers must meet the specified criteria to complete the signing process. - -## Development Challenges - -The introduction of these new fields wasn't without its challenges. The main challenges were: - -- Deciding how to store the new information for the fields in the database -- Differentiation of recipients using colours -- Storing the advanced settings for the local fields on the frontend -- Implementing the Checkbox and Radio fields - -### 1st Challenge: Store New Field Information - -The first challenge was deciding how to store the extra information for each new field in the database. Each field has unique properties, with only `required` and `read-only` shared by all the advanced fields. - -The existing `Field` model in the database looks like this: - -```js -model Field { - id Int @id @default(autoincrement()) - secondaryId String @unique @default(cuid()) - documentId Int? - templateId Int? - recipientId Int - type FieldType - page Int - positionX Decimal @default(0) - positionY Decimal @default(0) - width Decimal @default(-1) - height Decimal @default(-1) - customText String - inserted Boolean - Document Document? @relation(fields: [documentId], references: [id], onDelete: Cascade) - Template Template? @relation(fields: [templateId], references: [id], onDelete: Cascade) - Recipient Recipient @relation(fields: [recipientId], references: [id], onDelete: Cascade) - Signature Signature? - - @@index([documentId]) - @@index([templateId]) - @@index([recipientId]) -} -``` - -Initially, we considered creating a new `FieldMeta` table with columns for each field property. However, this approach has 2 issues. - -First, the advanced fields only share two common properties: `required` and `read-only`. Since all the other properties are unique to each field type, this would result in many nullable columns in the `FieldMeta` model. - -Secondly, creating a new database table with columns for each field property and the associated relationships would increase the database complexity. - -As a result, we decided to look for another solution that would better work with our use case. - -### Solution: JSONB Field - -Since the advanced settings data is unique to each field, we decided to store it as JSON using PostgreSQL's `JSONB` data type. We added a new optional `fieldMeta` property of type `JSONB` to the Field model: - -```js -model Field { - id Int @id @default(autoincrement()) - secondaryId String @unique @default(cuid()) - documentId Int? - templateId Int? - recipientId Int - type FieldType - page Int - positionX Decimal @default(0) - positionY Decimal @default(0) - width Decimal @default(-1) - height Decimal @default(-1) - customText String - inserted Boolean - Document Document? @relation(fields: [documentId], references: [id], onDelete: Cascade) - Template Template? @relation(fields: [templateId], references: [id], onDelete: Cascade) - Recipient Recipient @relation(fields: [recipientId], references: [id], onDelete: Cascade) - Signature Signature? - fieldMeta Json? <<<<<----- added this - - @@index([documentId]) - @@index([templateId]) - @@index([recipientId]) -} -``` - -This approach allows us to store each field's settings as a JSON object. We use Zod schemas to parse and validate the field metadata when reading from or writing to the database to ensure data integrity. - -This approach has several benefits: - -- **Consistency**: The application uses the same Zod schema to retrieve and insert data into the database. That means the data is consistent throughout the app. -- **Type safety**: By parsing the data with Zod, we can guarantee that the data matches the expected types and structure. We can also use Zod's `infer` utility to enable strong typing and autocompletion. -- **Better error handling**: Zod provides thorough error messages indicating which part of the data is invalid. That makes it easier & faster to debug and fix issues. -- **Maintainability**: Reusing the same Zod schema for retrieving and inserting data into the database makes the data structure easier to maintain. - -However, using `JSONB` also has drawbacks like data querying. Since the data is stored as JSON (more specifically, in binary format), complex queries can be less efficient compared to querying normalized relational data. On top of that, querying data requires specific operators and functions, such as `->`, `->>`, `@>`, and `?`. This makes the querying more verbose and less intuitive, and hence, it requires more finesse. - -Another drawback is the storage overhead. `JSONB` data is stored in a binary format, which can result in some storage overhead compared to normalized relational data. In cases where the JSON data is large or contains a lot of redundant information, the storage overhead can be significant. - -Despite these drawbacks, the `JSONB` type suits our use case, as the field meta information is relatively small and doesn't require complex querying. The flexibility of `JSONB` matches the dynamic nature of the fieldMeta field. - -> Postgres provides 2 fields for storing JSON data — `json` and `jsonb`. For more information, you can [check out the documentation](https://www.postgresql.org/docs/current/datatype-json.html). - -### 2nd Challenge: Storing Fields' Advanced Settings on Frontend - -The next challenge was finding the best way to store the advanced field settings entered by users. - -Currently, the app only saves the fields and associated settings to the database when the user moves to the next step. - -![Documenso advanced field signing](/blog/advanced-fields/documenso-advanced-fields-signing.webp) - -The fields are stored locally until the user proceeds to the next step. This means all fields and their settings are lost when the user: - -- Closes the advanced settings tab -- Refreshes the page -- Closes the tab -- Navigates to the previous step - -In the future, we plan to improve this flow and save the fields on blur, preserving user data even if they navigate away. However, until then, we needed a solution to save the advanced settings when the user closes the settings tab. - -### Solution: Local Storage - -Our temporary solution is to store the advanced settings in local storage, as the fields are only available locally. If the fields were saved in the database, we could store the advanced settings alongside them. - -![Documenso field advanced settings](/blog/advanced-fields/documenso-field-advanced-settings.webp) - -Since the fields are not saved in the database, we must persist the data until the user moves to the next step, at which point the data is saved to the database. Storing the data in local storage allows users to open, close, and configure various fields in the advanced settings tab without losing information. - -When the user proceeds to the next step, the fields and their advanced settings are saved into the database, and the local storage is cleared. - -We also recognized the dangers of saving data to local storage, as users could modify it and break the application. As a result, we have implemented extensive checks on both the backend and frontend, in addition to parsing and validating data with Zod. - -However, this solution has limitations. The data is still lost when the user: - -- Refreshes the page -- Navigates to the previous step -- Closes the browser - -In these cases, the fields are wiped from the document. A future improvement to save fields to the database on blur will solve this issue. - -### 3rd Challenge: Radio and Checkbox Fields - -Implementing the Radio and Checkbox fields was challenging from both logical and design perspectives. Both fields can contain empty and non-empty values, and the Checkbox field allows users to select multiple empty/non-empty values. - -![The radio and checkbox signing fields on the Documenso document signing page](/blog/advanced-fields/radio-and-checkbox-fields.webp) - -The image above shows the Radio and Checkbox fields in the document editor. The Radio field on the left-hand side has 4 options, 1 of which is checked. The Checkbox field on the right-hand side has 4 options, 2 of which are checked. - -The Radio field was easier to implement because users can only select one option, resulting in simpler logic. The signer clicks on an option to choose it, and the field auto-signs with that value. To change the selection, the user clicks another option, un-signing the field and re-signing it with the new value. - -The Checkbox field was more challenging because: - -- Signers can select multiple options simultaneously, resulting in the field containing multiple values. -- It can have validation rules (e.g., selecting at least, at most, or exactly X options). -- Users can check/uncheck options by clicking them or clear the field with a button. - -These factors make the Checkbox field more complex and challenging to implement correctly. - -### Solution - -Instead of focusing on a specific solution, we'll discuss the general implementation and its most challenging aspects. I'll include a link to the complete implementation for each field so you can check it out. - -**Radio Field** - -The way signing works for the Radio field is to pull the data from the database and display the available options. If the field has a default value set by the document sender, it auto-signs with that value. - -```ts -... - const values = parsedFieldMeta.values?.map((item) => ({ - ...item, - value: item.value.length > 0 ? item.value : `empty-value-${item.id}`, - })); -... - const shouldAutoSignField = - (!field.inserted && selectedOption) || - (!field.inserted && defaultValue) || - (!field.inserted && parsedFieldMeta.readOnly && defaultValue); -... - - useEffect(() => { - if (shouldAutoSignField) { - void executeActionAuthProcedure({ - onReauthFormSubmit: async (authOptions) => await onSign(authOptions), - actionTarget: field.type, - }); - } - }, [selectedOption, field]); -``` - -> You can see the complete implementation of the radio field in the [radio-field.tsx]() file. - -If the field is not read-only and the user clicks on another option, the field un-signs and re-signs with the new value. Read-only fields cannot be modified. - -The value is saved in the database whenever the field is signed, whether by auto-signing or user. Similarly, the value is removed from the database when the field is unsigned. - -Since the Radio field can contain empty values, we map over the values and replace the empty ones with a unique string `empty-value-${item.id}`. This is because the empty string is not a valid value for the field, and we need to differentiate between empty and non-empty values. - -**Checkbox Field** - -The Checkbox field implementation is similar to the Radio field, with the main differences being: - -- Checkbox fields can contain multiple values. -- Checkbox fields have validation rules that need to be enforced. - -```ts -... - const values = parsedFieldMeta.values?.map((item) => ({ - ...item, - value: item.value.length > 0 ? item.value : `empty-value-${item.id}`, - })); - - const [checkedValues, setCheckedValues] = useState( - values - ?.map((item) => - item.checked ? (item.value.length > 0 ? item.value : `empty-value-${item.id}`) : '', - ) - .filter(Boolean) || [], - ); -... -``` - -As with the Radio field, we map over the values and replace empty ones with a unique string. We also keep track of the checked values to display the field correctly and validate them against the validation rules. - -```ts -... - const values = parsedFieldMeta.values?.map((item) => ({ - ...item, - value: item.value.length > 0 ? item.value : `empty-value-${item.id}`, - })); - - const [checkedValues, setCheckedValues] = useState( - values - ?.map((item) => - item.checked ? (item.value.length > 0 ? item.value : `empty-value-${item.id}`) : '', - ) - .filter(Boolean) || [], - ); - - const checkboxValidationRule = parsedFieldMeta.validationRule; - const checkboxValidationLength = parsedFieldMeta.validationLength; - const validationSign = checkboxValidationSigns.find( - (sign) => sign.label === checkboxValidationRule, - ); -... -``` - -Then, we retrieve the validation rule and length from the database and find the corresponding validation sign (e.g., ">=", "=", "\<=") based on the rule label. The `checkboxValidationSigns` array maps rule labels to their corresponding signs. - -```ts -export const checkboxValidationSigns = [ - { - label: 'Select at least', - value: '>=', - }, - { - label: 'Select exactly', - value: '=', - }, - { - label: 'Select at most', - value: '<=', - }, -]; -``` - -We then check if the length condition is met based on the validation rule, sign, and length. If met, the user can proceed with signing the field. Otherwise, they need to select the correct number of options. - -```ts -... - const values = parsedFieldMeta.values?.map((item) => ({ - ...item, - value: item.value.length > 0 ? item.value : `empty-value-${item.id}`, - })); - - const [checkedValues, setCheckedValues] = useState( - values - ?.map((item) => - item.checked ? (item.value.length > 0 ? item.value : `empty-value-${item.id}`) : '', - ) - .filter(Boolean) || [], - ); - - const checkboxValidationRule = parsedFieldMeta.validationRule; - const checkboxValidationLength = parsedFieldMeta.validationLength; - const validationSign = checkboxValidationSigns.find( - (sign) => sign.label === checkboxValidationRule, - ); - - const isLengthConditionMet = useMemo(() => { - if (!validationSign) return true; - return ( - (validationSign.value === '>=' && checkedValues.length >= (checkboxValidationLength || 0)) || - (validationSign.value === '=' && checkedValues.length === (checkboxValidationLength || 0)) || - (validationSign.value === '<=' && checkedValues.length <= (checkboxValidationLength || 0)) - ); - }, [checkedValues, validationSign, checkboxValidationLength]); -... -``` - -In summary, the Checkbox field allows signers to select multiple options, with the field automatically signing based on these selections. Signers can un-sign the field by deselecting options or clearing all selections. The system enforces validation rules throughout this process, ensuring signers select the required number of options to sign the field successfully. - -> You can see the complete implementation of the checkbox field in the [checkbox-field.tsx]() file. - -### 4th Challenge: Recipients' Colors - -Another challenge we faced was using colours to differentiate recipients. We needed to dynamically generate and reuse the same Tailwind classes across several components. However, TailwindCSS only includes the CSS classes used in the project, discarding unused ones from the final build. This resulted in colours not being applied to the components, as the classes were not used in the code. - -The images below illustrate the recipients' colours in 2 different states. - -In the first image, the "Signature" field on the right is in the active state (blue), triggered when the user clicks the field to drag it onto the document. The signature field on the left, placed on the document, is in the normal state. - -The first image illustrates the "Signature" field in the active state, triggered when the user clicks on it. - -![Screenshot illustrating the active state for a field on the Documenso document editor page](/blog/advanced-fields/field-active-state.webp) - -The second image shows the "Signature" field in the normal state. - -![Screenshot illustrating the fields for a signer on the Documenso document editor page](/blog/advanced-fields/recipient-colours.webp) - -The document editor consists of various components (fields, recipients, etc.), meaning the same colours and code are reused across multiple components. - -```ts -export const combinedStyles = { - 'orange-500': { - ringColor: 'ring-orange-500/30 ring-offset-orange-500', - borderWithHover: 'border-orange-500 hover:border-orange-500', - ..., - }, - 'green-500': { - ringColor: 'ring-green-500/30 ring-offset-green-500', - borderWithHover: 'border-green-500 hover:border-green-500', - ..., - }, - 'blue-500': { - ringColor: 'ring-blue-500/30 ring-offset-blue-500', - borderWithHover: 'border-blue-500 hover:border-blue-500', - ..., - 'gray-500': { - ringColor: 'ring-gray-500/30 ring-offset-gray-500', - borderWithHover: 'border-gray-500 hover:border-gray-500', - ..., - }, - ..., -}; - -export const MyComponent = () => { - const selectedSignerStyles = useSelectedSignerStyles(selectedSigner, combinedStyles); - - return ( -
-

Hello

-
- ); -}; -``` - -The code above shows a naive solution using a `combinedStyles` object containing TailwindCSS classes for various component styles (ring, border, hover, etc.). - -Components would use custom hooks to apply appropriate styles based on the selected recipient. For example, recipient 1 would use `green-500` styles, turning all related elements green. - -![Screenshot illustrating the recipient colour on the Documenso document editor page](/blog/advanced-fields/recipient-colour-example.webp) - -The problem with this approach is that we can't import the `combinedStyles` object into other components because TailwindCSS will remove the unused classes. That means we had to copy and paste the same object into multiple files. As a result, it pollutes the codebase with duplicated code, which makes it harder to maintain and scale the code. As the application grows, the `combinedStyles` object will become larger and more complex. Moreover, it's not very flexible, as it doesn't allow for easy customization of the colours. - -While this approach works, there is a more efficient and scalable solution. - -### Solution: Modularise the Logic and Use CSS Variables - -To address the challenge of reusing colours across components, we moved the colours and associated hooks to a separate file, defining styles only in this file and accessing them from components through custom hooks. - -```ts -export const SIGNER_COLOR_STYLES = { - green: { - default: { - background: 'bg-[hsl(var(--signer-green))]', - base: 'rounded-lg shadow-[0_0_0_5px_hsl(var(--signer-green)/10%),0_0_0_2px_hsl(var(--signer-green)/60%),0_0_0_0.5px_hsl(var(--signer-green))]', - fieldItem: - 'group/field-item p-2 border-none ring-none hover:bg-gradient-to-r hover:from-[hsl(var(--signer-green))]/10 hover:to-[hsl(var(--signer-green))]/10', - fieldItemInitials: - 'opacity-0 transition duration-200 group-hover/field-item:opacity-100 group-hover/field-item:bg-[hsl(var(--signer-green))]', - comboxBoxItem: 'hover:bg-[hsl(var(--signer-green)/15%)] active:bg-[hsl(var(--signer-green)/15%)]', - }, - }, - - ... -}; - -export type CombinedStylesKey = keyof typeof SIGNER_COLOR_STYLES; - -export const AVAILABLE_SIGNER_COLORS = [ - 'green', - 'blue', - 'purple', - 'orange', - 'yellow', - 'pink', -] as const satisfies CombinedStylesKey[]; - -export const useSignerColors = (index: number) => { - const key = AVAILABLE_SIGNER_COLORS[index % AVAILABLE_SIGNER_COLORS.length]; - - return SIGNER_COLOR_STYLES[key]; -}; - -export const getSignerColorStyles = (index: number) => { - return useSignerColors(index); -}; -``` - -> The file was truncated for readability. You can see the complete code in the [signer-colors.ts](https://github.com/documenso/documenso/blob/main/packages/ui/lib/signer-colors.ts) file from the Documenso repository. - -The `SIGNER_COLOR_STYLES` object contains the styles for each colour, such as the background, border, and hover colours. Based on the signer's index, the `useSignerColors` hook gets the styles for a specific colour. The `getSignerColorStyles` function is a helper function that returns the styles for a particular signer. - -Now, the components can access the colours and styles using custom hooks. For example, to get the styles for a specific signer, the component can call the `useSignerColors` hook with the signer's index. - -```ts -const signerStyles = useSignerColors(recipientIndex); -``` - -The hook will return the styles for that signer, which can then be applied to the component. For example, you can access the signer's background colour using `signerStyles.default.background`. - -This approach makes managing the colours and styles easier, as they are defined in a single file. Changing or adding colours can be done in one place, making the code more modular and reusable. - -We also opted for CSS variables to define colours, allowing more flexibility and consistency in styling. A single CSS variable for each colour can cover a wide range of states without relying on multiple TailwindCSS classes. For example, you can easily set the opacity and lightness of colour without using multiple classes. CSS variables help align colours with our brand guidelines while simplifying the overall styling process. - -## The End - -We're happy to see the new advanced fields released because they offer our users more flexibility, variety, and customization options. Implementing the new fields came with its challenges, but we overcame them and learned from them. We're excited to continue enhancing Documenso and providing our users with the best document signing experience. diff --git a/apps/marketing/content/blog/introducing-embedding.mdx b/apps/marketing/content/blog/introducing-embedding.mdx deleted file mode 100644 index 45a04aec2..000000000 --- a/apps/marketing/content/blog/introducing-embedding.mdx +++ /dev/null @@ -1,72 +0,0 @@ ---- -title: 'Introducing Embedding Support for Documenso' -description: 'Embedding is now here! Learn how we built it and how it can be used to bring e-signing to your own applications.' -authorName: 'Lucas Smith' -authorImage: '/blog/blog-author-lucas.png' -authorRole: 'Co-Founder' -date: 2024-09-06 -tags: - - Development ---- - -When we first launched Documenso, one of the most requested features was embedding. We knew it was important and aligned with our desire to not just be a e-signing application but to instead provide the e-signature infrastructure for the web and beyond. - -With that said, we decided to hold off initially so we could focus on building a solid, well-featured core application. Looking back, this was definitely the right call. Embedding is only as good as the features behind it, and we didn't want to release something that wasn't ready to meet user and developer expectations. - -Over the past year, we've been busy adding tons of new features and reaching new levels of compliance, like 21 CFR Part 11. We've also introduced [new fields](/blog/introducing-advanced-signing-fields), [built out an API](/blog/public-api), [added webhooks, integrations with Zapier](/blog/launch-week-2-day-4), and a lot more. - -Now that we've laid a solid foundation, it's finally time to focus on embedding, the top-requested feature from both our users and those self-hosting our platform. - -## Why Embedding Took Time - -In previous projects, I’ve often seen embedding built by bundling components for use in a client’s website or app. This method gives users maximum flexibility for styling and behavior, while avoiding certain cross-origin issues. However, it can also introduce problems like code conflicts or performance bottlenecks. For example, third-party tools such as Google Tag Manager (GTM) or other marketing scripts can interfere with your SDK. Additionally, the SDK must remain lightweight to avoid slowing down the client’s page. - -For Documenso, we decided to explore a different approach. After carefully researching our options, we opted for an iframe-based solution. While iframes are typically less flexible—especially when it comes to theming or passing pre-filled data containing personally identifiable information (PII)—we identified ways to mitigate these concerns. - -One of the biggest challenges was ensuring that we could pass sensitive data, like emails for pre-filling forms, without exposing PII to our server. To solve this, we used [fragment identifiers](https://developer.mozilla.org/en-US/docs/Web/API/URL/hash) in the URL, which are processed client-side and never sent in network requests. This method ensures that PII is protected and not logged by our server or any intermediate web services. - -### Using the PostMessage API for Communication - -To maintain a high level of interactivity, our iframes communicate with the parent window using the [postMessage API](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage). This allows us to notify the parent app when specific events occur inside the iframe, creating a more dynamic user experience and bridging the gap between our iframe-based solution and typical fat SDKs. - -Additionally, props are passed into the iframe via the [fragment identifier](https://developer.mozilla.org/en-US/docs/Web/API/URL/hash) of the URL. This avoids the need for complex two-way data synchronization between the parent and child frames, making the system stable and more reliable. - -### Building the Embeds with Mitosis - -Given that our iframe solution is quite lightweight, we saw this as a great opportunity to experiment with [Mitosis](https://mitosis.builder.io/) which would let us do something truly special. For those unfamiliar, Mitosis is a project by Builder.io that lets you write components once and then transpile them into a variety of frameworks like React, Vue, and Svelte. - -We used Mitosis to build two key components: a direct template embed and a document signing embed. The direct template allows users to use a template as if it were an evergreen document—meaning that, when someone completes the template, a new document is automatically generated. This is the use case we expect most users to adopt for embedding. For more advanced workflows, we also offer a document signing embed, which can handle multi-recipient workflows and other complex scenarios intended for use in deeper, rich integrations. - -Mitosis allowed us to quickly target several popular frameworks, including [React](https://www.npmjs.com/package/@documenso/embed-react), [Preact](https://www.npmjs.com/package/@documenso/embed-preact), [Vue](https://www.npmjs.com/package/@documenso/embed-vue), [Svelte](https://www.npmjs.com/package/@documenso/embed-svelte), and [SolidJS](https://www.npmjs.com/package/@documenso/embed-solid). - -I had also hoped to include Angular, but while Mitosis makes it really easy to transpile component, we still have to take care of bundling and packaging the resulting component ourselves. While the above frameworks can all be bundled using Vite.js, Angular still has it's own set of tooling that we would need to learn and use. Given this constraint we opted to put Angular on hold for now while we wait for the newer Vite.js support to mature. - -### Challenges and Lessons with Mitosis and more - -While our experience with Mitosis was largely positive, there were some challenges along the way. For instance, certain state properties with the same names as props caused issues during the transpilation process, leading to type errors and unexpected transpilation results with some targets. - -This was also a challenge since our initial implementation of the two components had some minor separation of concerns which also resulted in some transpilation issues with some targets. We addressed this by removing the separation of concerns for now since it was mostly for show rather than out of necessity. - -On top of that, packaging and publishing the embeds posed its own set of challenges, particularly given the growing complexity of JavaScript package management. Tools like [Publint](https://www.npmjs.com/package/publint) helped streamline the process by ensuring we followed best practices for both CommonJS and ESM formats. - -### To the Future, The Documenso Platform - -With the embedding feature now in place, we're excited to continue expanding Documenso's capabilities. Embeds are just the beginning of what we're calling the Documenso platform. Through our user research, we've learned that while many businesses appreciate having a flexible e-signature solution, they're even more interested in using our tools to build signing functionality directly into their own apps—without worrying about the technical complexities of compliance and security that come with e-signing. - -Over the coming months, we'll be working on enhancing our API, strengthening integrations with tools like Zapier, and improving our webhook system. Our goal is to give users the ability to embed e-signatures and document management wherever they need it, whether that's through self-hosting or by using Documenso as a platform. We can't wait to see how our users and self-hosters leverage these new capabilities! - -### Ready to Get Started? - -If you're ready to embed document signing into your own app or website, check out our [Embedding Documentation](https://docs.documenso.com/developers/embedding?utm_source=blog&utm_campaign=introducing-embedding) to see how easy it is to get started. You'll find everything you need to get started today! - -