Skip to main content

Migrating from DocuSign

This guide helps you migrate existing DocuSign integrations to Propper's Sign API. The API is designed to be DocuSign-compatible, making migration straightforward.

Overview

Propper's Sign API implements the DocuSign eSignature REST API v2.1 specification. Most existing code will work with minimal changes:

  1. Update base URLs
  2. Update authentication
  3. Adjust for any feature differences

Quick Migration Checklist

  • Update API base URL
  • Update authentication to use Propper OAuth
  • Replace DocuSign SDK with direct API calls or Propper SDK
  • Update webhook endpoints (same format, different source)
  • Test all signing workflows
  • Update error handling for Propper-specific codes

AI-Assisted Migration

Use this prompt with Claude, ChatGPT, or your preferred AI assistant to analyze your codebase and generate a customized migration plan:

📋 Copy Migration Assistant Prompt
You are an expert at migrating DocuSign integrations to Propper Sign API. I need your help migrating my codebase.

## Your Task

1. **Analyze** - Search my codebase for all DocuSign integration points
2. **Ask Questions** - Clarify my requirements and current implementation
3. **Plan** - Create a detailed, step-by-step migration plan

## What to Look For

Search for these patterns in my code:
- DocuSign SDK imports (e.g., `docusign-esign`, `DocuSign.eSign`)
- Base URLs containing `docusign.net` or `docusign.com`
- Environment variables like `DOCUSIGN_*`
- JWT authentication with DocuSign
- Envelope creation, recipient management, embedded signing
- Webhook handlers for DocuSign Connect events
- Any DocuSign-specific error handling

## Questions to Ask Me

Before creating the plan, ask me about:
1. Which DocuSign features am I using? (envelopes, templates, embedded signing, webhooks, etc.)
2. What's my current authentication method? (JWT, Authorization Code, etc.)
3. Do I use the DocuSign SDK or direct API calls?
4. What languages/frameworks is my integration built with?
5. Do I have any custom webhook handlers?
6. What's my timeline and can I do a phased migration?
7. Are there any compliance or audit requirements I need to maintain?

## Migration Reference

Key changes from DocuSign to Propper:

| Component | DocuSign | Propper |
|-----------|----------|---------|
| Base URL | `https://na1.docusign.net` | `https://api.propper.ai` |
| Auth URL | `https://account.docusign.com` | `https://auth.propper.ai` |
| Auth Method | JWT or Auth Code | OAuth Client Credentials |
| SDK | `docusign-esign` | Direct API (fetch/axios) |
| Scopes | `signature` | `sign:read sign:write` |

API paths are identical - just change the base URL:
- `POST /restapi/v2.1/accounts/{accountId}/envelopes`
- `GET /restapi/v2.1/accounts/{accountId}/envelopes/{envelopeId}`
- `POST /restapi/v2.1/accounts/{accountId}/envelopes/{envelopeId}/views/recipient`

## Output Format

After analyzing and asking questions, provide:

1. **Current State Summary** - What DocuSign features I'm using
2. **Migration Complexity Assessment** - Low/Medium/High with reasoning
3. **Step-by-Step Migration Plan** - Detailed implementation steps (see below)
4. **Potential Risks** - What might break and how to mitigate
5. **Rollback Plan** - How to revert if needed

## Implementation Steps Format

For each migration step, provide:

### Step N: [Step Name]
**Files to modify:**
- path/to/file.js (lines X-Y)

**Before:** [show current DocuSign code]
**After:** [show new Propper code]

**Validation Checkpoint:**
- [ ] Run: [specific test command]
- [ ] Verify: [what to check]
- [ ] Expected result: [what success looks like]

## Validation Checkpoints

Include these checkpoints at key stages:

### Checkpoint 1: Authentication Migration
- [ ] Propper OAuth credentials configured in environment
- [ ] Token request returns valid access_token
- [ ] Token refresh works before expiry
- [ ] Test command: `curl -X POST https://auth.propper.ai/oauth/token -d '...'`

### Checkpoint 2: API Integration
- [ ] Create a draft envelope (status: "created")
- [ ] Retrieve the envelope by ID
- [ ] List envelopes returns results
- [ ] Test command: `curl https://api.propper.ai/restapi/v2.1/accounts/{id}/envelopes`

### Checkpoint 3: Signing Flow
- [ ] Generate recipient signing URL
- [ ] Complete a test signature
- [ ] Verify envelope status changes to "completed"
- [ ] Download signed document

### Checkpoint 4: Webhooks (if applicable)
- [ ] Webhook endpoint receives events
- [ ] Signature verification passes
- [ ] Events processed correctly (sent, viewed, completed)

### Checkpoint 5: Production Readiness
- [ ] All unit tests pass
- [ ] Integration tests pass
- [ ] Error handling covers Propper error codes
- [ ] Monitoring/logging updated
- [ ] Documentation updated

Start by searching my codebase for DocuSign integration points, then ask your clarifying questions.
Pro Tip

For best results, use this prompt with an AI coding assistant that has access to your codebase (like Claude Code, Cursor, or GitHub Copilot). The AI can then search your files directly and provide specific file paths and line numbers.

API Endpoint Mapping

Base URL

EnvironmentDocuSignPropper
Productionhttps://na1.docusign.nethttps://api.propper.ai

Endpoint Paths

The path structure is identical. Simply replace the base URL:

OperationPath (same for both)
Create envelopePOST /restapi/v2.1/accounts/{accountId}/envelopes
Get envelopeGET /restapi/v2.1/accounts/{accountId}/envelopes/{envelopeId}
List envelopesGET /restapi/v2.1/accounts/{accountId}/envelopes
Update envelopePUT /restapi/v2.1/accounts/{accountId}/envelopes/{envelopeId}
Get recipientsGET /restapi/v2.1/accounts/{accountId}/envelopes/{envelopeId}/recipients
Recipient viewPOST /restapi/v2.1/accounts/{accountId}/envelopes/{envelopeId}/views/recipient
Sender viewPOST /restapi/v2.1/accounts/{accountId}/envelopes/{envelopeId}/views/sender
List documentsGET /restapi/v2.1/accounts/{accountId}/envelopes/{envelopeId}/documents
Download documentGET /restapi/v2.1/accounts/{accountId}/envelopes/{envelopeId}/documents/{documentId}

Authentication Migration

DocuSign JWT Flow → Propper OAuth

// DocuSign JWT authentication
const docusign = require('docusign-esign');

const apiClient = new docusign.ApiClient();
apiClient.setBasePath('https://na1.docusign.net/restapi');

const results = await apiClient.requestJWTUserToken(
integrationKey,
userId,
'signature',
privateKey,
3600
);

const accessToken = results.body.access_token;

Scopes Mapping

DocuSign ScopePropper ScopeDescription
signaturesign:read sign:writeFull signing access
extendedsign:read sign:writeSame as signature
impersonationNot supportedUse service accounts instead

SDK Migration

Option 1: Replace SDK with Direct API Calls

The most portable approach is to use direct HTTP calls:

const docusign = require('docusign-esign');

const envelopesApi = new docusign.EnvelopesApi(apiClient);

const envelope = await envelopesApi.createEnvelope(accountId, {
envelopeDefinition: {
emailSubject: 'Please sign',
documents: [{ documentBase64: '...', documentId: '1', name: 'Contract.pdf' }],
recipients: {
signers: [{ email: 'signer@example.com', name: 'John', recipientId: '1' }],
},
status: 'sent',
},
});

Option 2: Create a Thin Wrapper

If you have extensive SDK usage, create a compatibility wrapper:

// propper-docusign-compat.js
class PropperEnvelopesApi {
constructor(baseUrl, accessToken) {
this.baseUrl = baseUrl;
this.accessToken = accessToken;
}

async createEnvelope(accountId, { envelopeDefinition }) {
const response = await fetch(
`${this.baseUrl}/restapi/v2.1/accounts/${accountId}/envelopes`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${this.accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(envelopeDefinition),
}
);
return response.json();
}

async getEnvelope(accountId, envelopeId) {
const response = await fetch(
`${this.baseUrl}/restapi/v2.1/accounts/${accountId}/envelopes/${envelopeId}`,
{
headers: { 'Authorization': `Bearer ${this.accessToken}` },
}
);
return response.json();
}

async listStatusChanges(accountId, options = {}) {
const params = new URLSearchParams();
if (options.fromDate) params.set('from_date', options.fromDate);
if (options.status) params.set('status', options.status);

const response = await fetch(
`${this.baseUrl}/restapi/v2.1/accounts/${accountId}/envelopes?${params}`,
{
headers: { 'Authorization': `Bearer ${this.accessToken}` },
}
);
return response.json();
}

// Add more methods as needed...
}

// Usage - minimal code changes
const envelopesApi = new PropperEnvelopesApi(
'https://api.propper.ai',
accessToken
);

const envelope = await envelopesApi.createEnvelope(accountId, {
envelopeDefinition: { /* same structure as before */ },
});

Request/Response Format

The request and response formats are identical. Here's a comparison:

Create Envelope Request

{
"emailSubject": "Please sign this document",
"emailBlurb": "Please review and sign at your convenience.",
"status": "sent",
"documents": [
{
"documentId": "1",
"name": "Contract.pdf",
"documentBase64": "JVBERi0xLjQKJeLjz9M...",
"order": "1"
}
],
"recipients": {
"signers": [
{
"email": "signer@example.com",
"name": "John Smith",
"recipientId": "1",
"routingOrder": "1",
"clientUserId": "user-123",
"tabs": {
"signHereTabs": [
{
"documentId": "1",
"pageNumber": "1",
"xPosition": "100",
"yPosition": "500"
}
]
}
}
]
}
}

This exact payload works with both DocuSign and Propper.

Envelope Response

{
"envelopeId": "abc123-def456-...",
"status": "sent",
"statusDateTime": "2024-01-15T10:30:00Z",
"sentDateTime": "2024-01-15T10:30:00Z",
"emailSubject": "Please sign this document",
"emailBlurb": "Please review and sign at your convenience."
}

Feature Parity

Fully Supported Features

FeatureSupport LevelNotes
Create/send envelopesFullSame API
Multiple recipientsFullSequential and parallel routing
Embedded signingFullSame recipient view API
Document upload (Base64)FullSame format
Recipient types (signer, cc, viewer)FullSame structure
Envelope status trackingFullSame statuses
Webhooks/ConnectFullSame event format
Void envelopesFullSame API
Audit trailFullJSON and PDF certificate
TemplatesFullSame template API

Partially Supported Features

FeatureSupport LevelNotes
Tabs (signature fields)PartialBasic tabs supported, advanced tabs coming
Bulk sendPartialUse loop with standard API
PowerFormsNot yetRoadmap item
SMS deliveryNot yetEmail only currently
IDV (ID Verification)Not yetRoadmap item

Not Supported

FeatureAlternative
DocuSign Connect (push webhooks to specific URL)Use Propper webhooks with same payload format
DocuSign Admin APIUse Propper Admin dashboard
Click (clickwrap)Use Propper Click API (separate product)

Webhook Migration

Webhook payloads follow the same structure. Update your endpoint URL in the Propper dashboard:

// DocuSign Connect webhook handler
app.post('/docusign/webhook', (req, res) => {
const event = req.body;

if (event.event === 'envelope-completed') {
const envelopeId = event.data.envelopeId;
// Process completed envelope
}

res.status(200).send();
});

Webhook Event Mapping

DocuSign EventPropper Event
envelope-sentdocument.sent
envelope-delivereddocument.viewed
envelope-completeddocument.completed
envelope-declineddocument.declined
envelope-voideddocument.voided
recipient-sentdocument.sent (per recipient)
recipient-completeddocument.signed

Error Code Mapping

DocuSign ErrorPropper ErrorHTTP Status
ENVELOPE_NOT_IN_CORRECT_STATEENVELOPE_CANNOT_BE_MODIFIED400
ENVELOPE_DOES_NOT_EXISTENVELOPE_NOT_FOUND404
RECIPIENT_NOT_IN_SEQUENCERECIPIENT_NOT_FOUND404
INVALID_REQUEST_BODYINVALID_REQUEST_BODY400
USER_AUTHENTICATION_FAILEDUNAUTHORIZED401
USER_NOT_AUTHORIZED_FOR_ACCOUNTFORBIDDEN403

Step-by-Step Migration

1. Set Up Propper Account

  1. Sign up at app.propper.ai
  2. Create an organization
  3. Generate API credentials (Settings → API Keys)

2. Update Environment Variables

# Before (DocuSign)
DOCUSIGN_BASE_URL=https://na1.docusign.net
DOCUSIGN_ACCOUNT_ID=abc123
DOCUSIGN_INTEGRATION_KEY=xyz789
DOCUSIGN_USER_ID=user123
DOCUSIGN_PRIVATE_KEY_PATH=./private.key

# After (Propper)
PROPPER_BASE_URL=https://api.propper.ai
PROPPER_ACCOUNT_ID=your-org-id
PROPPER_CLIENT_ID=your-client-id
PROPPER_CLIENT_SECRET=your-client-secret

3. Update Authentication Code

Replace DocuSign JWT with Propper OAuth:

// auth.js
const getAccessToken = async () => {
const response = await fetch(`${process.env.PROPPER_AUTH_URL}/oauth/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
grant_type: 'client_credentials',
client_id: process.env.PROPPER_CLIENT_ID,
client_secret: process.env.PROPPER_CLIENT_SECRET,
scope: 'sign:read sign:write',
}),
});

if (!response.ok) {
throw new Error('Failed to get access token');
}

const { access_token, expires_in } = await response.json();

// Cache token until expiry
tokenCache = {
token: access_token,
expiresAt: Date.now() + (expires_in * 1000) - 60000, // 1 min buffer
};

return access_token;
};

4. Update API Calls

Find and replace the base URL:

// Before
const DOCUSIGN_BASE = 'https://na1.docusign.net/restapi/v2.1';

// After
const PROPPER_BASE = 'https://api.propper.ai/restapi/v2.1';

5. Update Webhooks

  1. Log in to Propper dashboard
  2. Go to Settings → Webhooks
  3. Add your webhook endpoint URL
  4. Select events to subscribe to
  5. Copy the webhook secret for signature verification

6. Test Thoroughly

# Test envelope creation
curl -X POST "$PROPPER_BASE/accounts/$ACCOUNT_ID/envelopes" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"emailSubject":"Test","status":"created","documents":[...]}'

# Test envelope retrieval
curl "$PROPPER_BASE/accounts/$ACCOUNT_ID/envelopes/$ENVELOPE_ID" \
-H "Authorization: Bearer $ACCESS_TOKEN"

# Test embedded signing
curl -X POST "$PROPPER_BASE/accounts/$ACCOUNT_ID/envelopes/$ENVELOPE_ID/views/recipient" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"returnUrl":"https://yourapp.com/done","clientUserId":"user-123",...}'

Common Migration Issues

Issue: "Account not found" errors

Cause: Using DocuSign account ID instead of Propper organization ID.

Solution: Get your organization ID from the Propper dashboard (Settings → Organization).

Issue: Authentication failures

Cause: Using DocuSign JWT format.

Solution: Switch to OAuth client credentials flow (see authentication section above).

Issue: Webhook signature validation fails

Cause: Using DocuSign HMAC key.

Solution: Get new webhook secret from Propper dashboard and update verification code.

Issue: Missing tabs on documents

Cause: Some advanced tab types not yet supported.

Solution: Use basic tab types (signHere, dateSigned, text) or contact support for timeline on specific tabs.

Need Help?