Skip to main content

Docusign eSignature

The Docusign connector reaches the eSignature REST API v2.1 for one account. It is good for the read side of a signing workflow: which envelopes moved this week, who has signed and who has not, what documents an envelope contains, and what the audit trail says. It can also create and send an envelope, but that action ships switched off and approval-gated, because sending an envelope emails real people asking them to sign something.

What you need

Docusign has no API keys. Every call is authenticated with an OAuth access token, so you register your own integration and let the gateway obtain tokens from it.

1. Register an integration key. In Docusign Admin, open Settings → Apps and Keys (the developer sandbox equivalent is the Apps and Keys page of your demo account) and choose Add App and Integration Key. Name the app, then:

  • Under Authentication, add a secret key. The gateway's OAuth flow takes a client id and a client secret, and applies PKCE on top of them where the connector's manifest records that the provider supports it.
  • Under Redirect URIs, add http://127.0.0.1:7376/oauth/callback for a gateway running on your own machine, or https://<your-gateway-host>/oauth/callback for a tunnelled gateway. Docusign rejects any redirect that is not registered here, exactly.
  • Copy the Integration Key. That is your OAuth client id.

2. Request the least privilege you need. For this connector that is signature, which grants the eSignature API and nothing else. Ask for extended alongside it: that is what gives you a refresh token the gateway can keep renewing, rather than one that expires with the access token, and the gateway will not seal a credential it cannot refresh.

3. Find your account base URI and account id. Both are on the same Apps and Keys page, under My Account Information: the API Account ID is the account id every capability takes, and the Account's Base URI (something like https://na3.docusign.net) is what the connection's base URL is built from. Note them before you go any further — the base URL is set when you create the connection, which happens before the OAuth flow runs.

The userinfo endpoint returns the same pair, as account_id and base_uri on the entry of the accounts array with "is_default": true, if you would rather read them from a script. It needs an access token of its own, though; under the flow below the gateway holds the tokens, not you.

# Sandbox. For production, use https://account.docusign.com/oauth/userinfo
curl -s https://account-d.docusign.com/oauth/userinfo \
-H "Authorization: Bearer $DS_ACCESS_TOKEN"
Change the base URL before you install

The connector ships pointed at the developer sandbox, https://demo.docusign.net/restapi. That is deliberate: if you forget to change it, calls land in the sandbox rather than sending real signature requests.

For production, set the connection's base URL to your own base_uri with /restapi appended, for example https://na3.docusign.net/restapi. Nothing else works: Docusign returns 401 if you call an account through the wrong account server, and the gateway pins the host, so an agent cannot reach a different one.

The authorisation server moves with it. The sandbox issues tokens from account-d.docusign.com, production from account.docusign.com, and a demo token is not accepted by a production account server. The oauth block in this connector's manifest names the sandbox pair, matching the default base URL — and unlike the base URL, those endpoints come from the manifest rather than from the connection, so changing one connection's base URL to production leaves its OAuth flow authorising against the demo server and the token it seals will be refused.

For production, install a second copy of the manifest under its own id: take docusign.json, change "id" to something like docusign-production, point both oauth URLs at account.docusign.com, POST it to /v1/connectors/install, and create the connection from that. The two then sit side by side in the catalog with separate credentials.

OAuth runs on the gateway, not in the console

Gateway 1.1.0 and later runs the whole authorisation code flow itself, against the integration key you just registered. You start it, approve once in a browser, and the gateway exchanges the code, seals the access token, refresh token and client secret as the connection's credential, and from then on refreshes the access token on its own — two minutes before each eight-hour token runs out, on the invoke path. Nothing to re-paste, nothing to babysit. permaura.com is never involved and never sees any of it.

What is not there yet is a Sign in with Docusign button: permaura.com's connector OAuth endpoint still answers with a "rolling out" response. Today you start the flow through the gateway's own REST API, as below.

Add the connection

Both halves of this are gateway-side today. The console's Add connection dialog will not create a connection without a credential, it has no field for the per-account base URI you need here, and the OAuth path it offers sends your client id and secret to permaura.com rather than to your gateway. So create the connection against the gateway, pinning your own account's base URI as you go:

BASE=http://127.0.0.1:7376
curl -s -X POST $BASE/v1/connections/from-preset \
-H "authorization: Bearer $TOKEN" -H 'content-type: application/json' -d '{
"preset_id": "docusign",
"name": "docusign-live",
"base_url": "https://na4.docusign.net/restapi"
}'

The response echoes the host it pinned, so you can check it took, and carries the connection_id used below. Then start the flow with an operator token:

curl -s -X POST $BASE/v1/connections/$CONNECTION_ID/oauth/start \
-H "authorization: Bearer $TOKEN" \
-H 'content-type: application/json' -d '{
"client_id": "…your integration key…",
"client_secret": "…your secret key…",
"redirect_uri": "http://127.0.0.1:7376/oauth/callback",
"scopes": ["signature", "extended"]
}'

The response carries an authorize_url. Open it in a browser and approve. Docusign redirects back to your gateway, which finishes the exchange and shows a plain "Connected" page. The credential is sealed on your gateway and never displayed again. Nothing can use it until a grant allows it.

Four things to watch:

  • redirect_uri has to match what you registered with Docusign, exactly. The gateway asks for it rather than guessing, because a mismatch is the most common way this fails. Loopback addresses (http://127.0.0.1:7376/oauth/callback, http://localhost:…) may be plain http; anything else has to be https.
  • The authorize link is single-use and expires after ten minutes. Start again if it goes stale.
  • No refresh token, no credential. If Docusign returns an access token without a refresh token, the gateway refuses the exchange rather than sealing something that dies in eight hours, and the error says so. That is what the extended scope is for.
  • Run it from the gateway's own host if you have a device enrolled for approvals. Sealing a credential changes the upstream identity the connection acts as, so it is held for a device signature, and a browser redirect cannot carry one. Starting the flow over a tunnel or the broker is refused in that setup.

What the agent can do

Every capability takes accountId as a path parameter, so give the agent the API account id you noted in step 3.

ActionWhat it doesOn by default
envelopes.listLists envelopes changed in a date rangeYes
envelopes.readReads the status of one envelopeYes
recipients.listLists an envelope's recipients and their statusYes
documents.listLists the documents in an envelopeYes
documents.downloadDownloads one document as PDFYes
templates.listLists templatesYes
templates.readReads one templateYes
audit_events.listReads an envelope's audit trailYes
envelopes.sendCreates an envelope and emails it to its recipientsNo, and needs approval

envelopes.send is the only write. It is off on connect, and switching it on still leaves every call waiting for a human approval, because a sent envelope cannot be unsent: the recipients already have the email. The same capability also creates drafts, by setting the status body parameter to created instead of sent. The approval gate applies either way, since only the arguments tell the two apart.

Good to know

  • envelopes.list needs from_date. Docusign requires it unless you filter by envelope or transaction ids, which this connector does not expose. An agent that calls it with no arguments gets a 400. ISO 8601 with an explicit time zone offset is the format Docusign recommends.
  • Sandbox and production are separate worlds. Demo accounts, integration keys and envelopes do not carry across. Docusign also requires a go-live review before an integration key works against production, so expect to test everything on demo.docusign.net first.
  • The JWT grant is the other way to run unattended, and Permaura does not implement it. Docusign's JWT grant needs no browser step at all, which is why it is the usual choice for a service integration. The gateway runs the authorisation code grant instead: one browser approval when you connect, and refreshes on its own after that. If you need the JWT grant specifically, you are outside what this connector does today.
  • Rate limits. 3,000 API calls per hour per account by default, plus a burst limit of 500 calls in any 30 seconds. Over either and you get a 429 telling you when you can resume. Watch the X-RateLimit-Remaining and burst headers.
  • documents.download does not hand the file to the agent. Docusign answers it with a PDF byte stream, and the gateway passes connector responses to agents as JSON, so a successful call comes back empty. It tells you the document exists and is retrievable; it does not put the contract in front of the model. The documentId can be a real document id or one of Docusign's special values: combined (every document in one PDF), archive (a ZIP), portfolio (a PDF portfolio), or certificate (the certificate of completion). To read a document yourself, call the same URL outside Permaura.
  • Most identifying details are redacted, but not every name. Email addresses, first, last and full names, sender and in-person-signer names, phone and fax numbers, IP addresses, signer access codes and client user ids are replaced before the agent sees them. A recipient's name field is not, and that is deliberate: redaction matches on field name anywhere in a response, and name is also what Docusign calls a template and a document, so blanking it would blank the very things templates.list and documents.list exist to return. Assume an agent with recipients.list can see who an envelope went to. Audit trails are outside redaction's reach for the same kind of reason: audit_events.list returns generic name/value pairs rather than named fields.
  • The account id is not part of the pinned host. Pinning the base URL stops an agent reaching a different Docusign server, but an agent that knows another accountId on the same server could try it. Only hand out the account id you intend it to use.