Envelope Signing (eSign)API ReferenceSign Recipient via API (Interface Signing)

Sign Recipient via API (Interface Signing)

POST/openapi/v1/envelopes/{envelopeId}/recipients/{recipientId}/sign

The customer server completes signing on behalf of a signer using their Signing PIN (the signer does not enter the signing page).

  • The signer must have a Signing PIN configured and must have accepted the ERSD disclosure toward the sender (first-time consent happens on the signing page / frontend); an error is returned if either is missing
  • Idempotency: the Idempotency-Key header takes precedence over the body IdempotencyKey; sending neither is an error. Replaying the same key returns the previous successful result (IdempotentReplay=true)
  • Asset resolution: signing controls not explicitly bound in Tabs use SignatureId / SealId as the default asset; at least one must be available. The signature/seal must belong to the signer
  • envelopeId and recipientId are path parameters, not part of the body

Applicable controls & default assets

  • This endpoint signs / seals on behalf of the signer and only covers signing-type controls (e.g. signHere, initialHere, stamp). It does not fill other data-entry controls (text / date / email / number, etc.); envelopes with such unfilled fields must first be completed on the signing page by the signer, otherwise a "field not filled" error is returned
  • Tabs is optional — usually no per-control binding is needed: signing controls not listed in Tabs fall back to SignatureId (signature) or SealId (seal) as the default asset

Credential (JWE)

Encrypt the signing PIN with JWE (RFC7516): alg=RSA-OAEP-256, enc=A256GCM.

  1. Public key: GET {baseUrl}/.well-known/jwks.json, take the use=enc key (keep its kid).
  2. Plaintext payload:
{"typ":"sign_pin","secret":"<PIN>","context":{"userId":"<recipient UserId>","envelopeId":"<envelopeId in URL>","recipientId":"<recipientId in URL>"},"iat":<sec>,"exp":<iat+60>,"jti":"<uuid>"}
  1. Encrypt to a 5-segment Compact string (protected.encryptedKey.iv.ciphertext.tag) and put it in Credential.

Notes: must be 5 segments (WebCrypto: split the trailing 16-byte tag into its own segment); header is the AAD; exp<=60s, jti single-use (re-sign on retry); context must match the recipient and URL.

Plaintext PIN: not accepted by default — contact us to enable it.


Request Parameters

AuthorizationRequiredstring
Bearer <access_token>
X-Operator-User-IdOptionalstring
Operator user ID. Omit under authorization-code mode (the authorized user is used); optional under client-credentials mode, defaulting to the system user ID.
Idempotency-KeyOptionalstring
Idempotency key (either this header or body IdempotencyKey; header takes precedence)
application/json
SignatureIdOptionalstring
Signature asset (the default when a control is not explicitly bound, along with SealId; one of the two must be usable)
SealIdOptionalstring
Seal asset (the default when a control is not explicitly bound, along with SignatureId)
TabsOptionalarray<object>
Tab-level asset bindings (optional). Signing controls absent from Tabs fall back to the SignatureId / SealId default asset.
TabIdRequiredstring
Tab ID (required)
SignatureIdOptionalstring
Signature asset ID for this tab (optional)
SealIdOptionalstring
Seal ID for this tab (optional)
IdempotencyKeyOptionalstring
Idempotency key (optional). Either this or the Idempotency-Key header is required; the header takes precedence. The idempotency key may be reused, but each retry must carry a newly issued Credential (credentials are one-time tickets and are not replayed with the idempotency key).
CredentialOptionalstring
JWE-encrypted credential (RSA-OAEP-256 + A256GCM, typ=sign_pin; context carries userId/envelopeId/recipientId). Valid for 60 seconds and single-use. Either Credential or SigningPin must be provided.
SigningPinOptionalstring
Signing PIN (plaintext not accepted by default; contact us to enable)

Response Parameters

EnvelopeStatusOptionalstring
Current envelope status
RecipientStatusOptionalstring
Recipient status after this signing
SignedAtOptionalstring
Signing completion time (RFC3339)
EnvelopeCompletedOptionalboolean
Whether the envelope is completed (all signers signed)
IdempotentReplayOptionalboolean
Whether this is an idempotent replay (returns the previous successful result verbatim)

Error Codes

Error CodeDescription
INVALID_REQUESTInvalid request (missing idempotency key / empty path parameter etc.)
NOT_FOUNDEnvelope not found
RECIPIENT.NOT_RECIPIENTThe recipientId is not a signer of this envelope (or is a carbon copy)
ENVELOPE.INVALID_STATUSEnvelope status does not allow signing (completed / voided / draft etc.)
SIGNING.RECIPIENT_ALREADY_SIGNEDThe signer has already signed
SIGNING.RECIPIENT_DECLINEDThe signer has declined
SIGNING.CONSENT_REQUIREDThe signer has not accepted the ERSD disclosure yet
AUTH.PIN_NOT_CONFIGUREDThe signer has no Signing PIN configured
AUTH.PIN_INVALIDSigning PIN is incorrect
AUTH.PIN_LOCKEDToo many incorrect PIN attempts; temporarily locked
AUTH.CREDENTIAL_REQUIREDPlaintext is not allowed for this app; use a JWE Credential
AUTH.CREDENTIAL_INVALIDCredential is invalid (decryption/binding failed or replayed)
AUTH.CREDENTIAL_EXPIREDCredential expired (check client clock and retry)
SIGNING.ENVELOPE_NOT_SIGNABLEThe envelope is not signable now
SIGNING.RECIPIENT_NOT_SIGNABLEThe recipient is not signable now
INTERNAL_ERROR服务内部错误