Most products that need a signature send their users somewhere else to get it. An email arrives, a link opens a page that looks nothing like your product, the user signs there and finds their way back, and your system learns that something happened only when someone checks. It works, and it is where every flow breaks. Today that stops being the only option: the GingerDocs API and the embed SDK are live, with the documentation at app.gingerdocs.com/docs and both SDK packages on npm.

This is the short version of what you can build with it, in the order you would build it.

Three steps: mint, mount, act on events

The model is deliberately small. Your server asks our API for an embed session: a short-lived URL tied to one document and one signer, or to one of your users and a workspace. Your page hands that URL to the SDK, which frames the signing experience on our origin and pins the origin and the session id on both ends. Your code then listens for typed events and acts on them.

Your secret key never reaches a browser. That is not a guideline you have to follow; the design makes it unnecessary, because the only thing the page ever sees is the session URL, which expires on its own and can be revoked from your server at any time.

  • Mint a session on your server with a secret key: one POST naming the document and the origin of the page that will frame it.
  • Mount the frame with the SDK: four lines in your page, or one component in React.
  • Act on events: ready, viewed, signed, completed, declined, and the document events of a workspace session. For anything that completes outside the frame, your webhook endpoint or the events API is the source of truth.

The code

On the server, one call creates the session. The response carries the URL for the page and an id you pass along so the SDK accepts messages from that session only.

backend.jsJavaScript
const res = await fetch('https://api.gingerdocs.com/api/v1/embed_sessions', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.GINGERDOCS_SECRET_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    kind: 'signing',
    document_id: documentId,
    host_origin: 'https://app.example.com',
  }),
})
const { id, url } = await res.json()

In the page, the SDK mounts the frame into any element and hands you events. When a session expires, mint a fresh one and reload the frame in place; the signer never loses their spot.

frontend.jsJavaScript
import { mount } from '@gingerdocs/embed'

const embed = mount('#signing', { url, sessionId: id })

embed.on('ready', () => hideLoader())
embed.on('completed', () => showConfirmation())
embed.on('session_expired', async () => {
  const fresh = await refetchSession()
  embed.reload(fresh.url, { sessionId: fresh.id })
})

If you use React, it is one component with one handler for every event, safe to pass inline. React is optional: the core package has no framework dependency, so the four lines above work as they are in Vue, Angular, Svelte or a plain HTML page.

Signing.jsxJSX
import { GingerDocsEmbed } from '@gingerdocs/react'

<GingerDocsEmbed
  url={session.url}
  sessionId={session.id}
  onEvent={event => event.type === 'completed' && showConfirmation()}
/>

Build it free, in test

Developer Mode and test keys are available on every plan, including Free. Everything in this post works in the test environment: no email of any kind leaves our servers, the output PDF is watermarked as not legally binding, and test documents are removed after 90 days. A test endpoint can even simulate the signature, so your CI can assert that a document reaches COMPLETED without a human clicking anything.

Switch to a live key when you are ready. The calls are identical.

Your name on the certificate

Every completed document ends with a Certificate of Completion: the reference number, the verification code, and each signer’s timeline and IP address. When you deliver the signing link yourself, or attest a signer’s identity through an embedded session, the certificate names your legal entity as the verifying party. That is what you accept in the Integrator Terms when you switch on Developer Mode, and it is the honest version of the record: it says who vouched for the signer.

Anyone holding the PDF can still check it against our records on the verification page, no account needed.

Webhooks, and a 90-day event log

Every state change emits an event. Register a webhook endpoint and each one arrives as a signed POST, with retries and a delivery log you can read under Settings → Developer. Miss one anyway, because your endpoint was down for an hour, and it is still there: every event stays readable through the API for 90 days.

The frame reports what happens inside it; your webhook reports what happens anywhere. Build on the second, and use the first for the person in front of the screen.

Open source, two packages

The SDK is small enough to read in one sitting, and that is the point. @gingerdocs/embed is framework-free, under 1.5 KB gzipped, with no dependencies; @gingerdocs/react wraps it in one component. Both are MIT-licensed and live on GitHub at gingerdocs/embed-sdk and gingerdocs/embed-react-sdk, where the issue trackers are open.

A readable SDK is how the security claim above becomes something you can check rather than something you take on trust.

Pricing, and where to start

Build on test keys for free. Go live on the Developer plan: $100 a year for everything in Pro, the same 1,000 document uploads a month, and live API keys. Details are on the pricing page.

Start with the quickstart: from a fresh account to a signed document in four calls, in your terminal, in about ten minutes. The Developers page has the overview, and the API reference is there when you need every field.