API

Built for the integration.

REST + JSON over HTTPS, per-workspace bearer-token auth, webhooks for every state transition. It's the signing layer underneath your product, not a separate destination.

Quick overview

Authentication is a per-workspace bearer token you issue in settings. A full send is three calls at most: create the envelope with its documents, recipients and field placements, send it, then read state (or wait for the webhook). Nobody has to open our editor for that path.

Base URL

https://vg-sign.com/api/v1

The base path used to be /api/v1/internal. That prefix still answers, and will keep answering — nothing built against it needs changing. It was never accurate: every endpoint below takes an ordinary workspace token.

A machine-readable description of everything on this page lives at /api/v1/openapi.json (OpenAPI 3.1). Point a client generator at it, or import it into Postman or Insomnia.

Authentication

Issue a workspace API token in Settings → Integrations, then call the API with Authorization: Bearer vgs_live_…. Tokens are scoped to your workspace, hashed at rest, and revocable at any time.

Signing an agent in from a CRM is a separate, higher privilege. The single-use SSO hand-off at /oauth/authorize, the On-Behalf-Of header and entitlement revocation are only answered for a workspace we have enabled as a CRM service account, and only for people who are already in that workspace. An ordinary workspace token gets 403 not_a_service_account on those three; everything else on this page works with any token. Ask us at info@vg-realestate.ca to have a workspace enabled.

Core endpoints

  • POST /envelopes: create an envelope from one or more uploaded PDFs (multipart/form-data: a metadata JSON part plus one files part per document). Recipients, signing order and — optionally — field placements are all in the same payload. Returns 201 with the envelope id, status: "draft", and fields_required, which is false once you have placed the fields yourself.
  • POST /envelopes/:id/send: send a draft for signature. Emails the signers, rotates their signing links, and records the send in the audit trail.
  • GET /envelopes: list the workspace’s envelopes, newest first. Filters: status, external_ref; paging: limit (max 100), offset.
  • GET /envelopes/:id: read envelope state, recipient progress and the audit trail.
  • GET /envelopes/:id/final: fetch the signed, flattened PDF(s).
  • GET /envelopes/:id/certificate: fetch the certificate of completion.
  • POST /envelopes/:id/remind: re-send the signing notification to pending recipients.
  • POST /envelopes/:id/void: void an in-flight envelope.
  • POST /envelopes/from-refs: create an envelope from documents already uploaded through /uploads/init, by reference.
  • POST /webhooks · GET /webhooks · DELETE /webhooks/:id: manage lifecycle-event subscriptions.

Recipients

GET /envelopes/:id/recipients returns the people on an envelope and where each of them stands. On a draft, POST /envelopes/:id/recipients adds someone, PATCH /envelopes/:id/recipients/:rid edits them (name, email, phone, label, signer or copy-only, position in the signing order) and DELETE removes them — the delete is refused while that person still owns placed fields, since removing them would take those fields too; pass ?force=true to accept it.

After a send, the same PATCHhandles the mistyped-address case: name and email only, and only for someone who has not yet signed or declined. Changing the email retires the link that went to the wrong address and issues a new one, emailed to the corrected address when it is that person’s turn. The deadline carries over rather than restarting, and the substitution is recorded in the audit trail. POST /envelopes/:id/recipients/:rid/remind nudges one named person, where the envelope-level reminder chases whoever is currently holding things up.

Templates

A template carries the documents, the field layout and the signing roles, so a recurring pack is one call rather than an upload plus a field layout plus a send. GET /templates lists them; GET /templates/:id returns the roles you have to fill; POST /templates/:id/envelopes binds a real person to each role and creates the envelope. Add "send": true to have it go out in the same request.

POST /templates/8f3c…/envelopes
{
  "assignments": [
    { "signing_order": 1, "full_name": "Dana Reyes", "email": "dana@example.com" }
  ],
  "external_ref": "deal-4417",
  "send": true
}

Placing fields

Each entry in fields[] is one box on one page, assigned to one recipient. Coordinates are fractions of the page — 0 to 1, measured from the top-left corner — so they hold for any page size. document names a file from documents[] and can be omitted when the envelope has a single signable document.

{
  "recipient_email": "buyer@example.com",
  "document": "contract.pdf",
  "type": "signature",
  "page": 1,
  "x": 0.12, "y": 0.60,
  "width": 0.30, "height": 0.07,
  "required": true
}

Types: signature, initials, full_name, text, date, time, checkbox, strikethrough. Text fields also take placeholder, max_length and validation (email · number · phone); dates take date_format, times take time_format and time_mode, checkboxes take checkbox_style. A rejected placement comes back as a 400 naming the entry, e.g. fields[2].page is 9 but "contract.pdf" has 4 page(s).

Skip fields[] and the response carries fields_required: true plus an editor_url: the envelope waits as a draft until somebody places the fields in the VG·Sign editor. Every signer needs at least one required field, or the send is refused.

Webhook events

Every state change emits a webhook with a signed payload. The events an integration usually subscribes to: envelope.created, envelope.sent, envelope.opened, envelope.document_signed, envelope.all_signed, envelope.completed, envelope.declined, envelope.voided, envelope.expired, envelope.recalled, envelope.reminded.

Each delivery carries an X-VG-Signature: sha256=<hex>header, an HMAC-SHA256 of the raw request body, keyed with your subscription’s shared secret. Recompute it and compare before processing.X-VG-Delivery-Id repeats the id in the body — deduplicate on it, since delivery is at-least-once.

SDKs

The API is plain REST + JSON, so any HTTP client works. There is no hand-written client SDK, but /api/v1/openapi.json is a complete OpenAPI 3.1 description, which most generators will turn into a typed client for your language. If you would rather have one we maintain, tell us at info@vg-realestate.ca.

Rate limits

Each workspace token is limited to 600 requests per minute (and 600/min per source IP), measured over a rolling 60-second window. Reminder sends are capped tighter, at 60/min. Over-limit requests get a 429 with a Retry-After header. Need a higher ceiling? Contact us.

Limits

Up to 15 documents per envelope, 25 MB and 50 pages per PDF, 50 recipients and 500 field placements. Uploads to POST /envelopesmust be PDFs; other formats go through the web uploader, which converts them first. Envelope creation counts against your plan’s monthly allowance and answers 402 when it runs out.