Back

Step by Step Guide to Building a DocuSign API Integration in Go

Aug 1, 20247 minute read

Hey there, fellow Go developer! Ready to add some document signing magic to your application? Let's dive into building a DocuSign API integration using Go and the awesome esign package. Buckle up, because we're about to make your app a whole lot more powerful!

Introduction

DocuSign's API is a game-changer when it comes to handling electronic signatures. With the esign package for Go, we can tap into this power and create seamless signing experiences for our users. Trust me, your future self will thank you for this integration!

Prerequisites

Before we jump in, make sure you've got:

  • Go installed on your machine (I know you do, you rockstar!)
  • A DocuSign Developer account (it's free, so no excuses!)
  • API credentials (Integration Key, User ID, Account ID) - keep these handy!

Setting up the project

Let's get our project off the ground:

mkdir docusign-go-integration cd docusign-go-integration go mod init docusign-go-integration go get github.com/docusign/docusign-esign-go-client

Great! We're all set up and ready to roll.

Authentication

First things first, let's get authenticated:

import ( "github.com/docusign/docusign-esign-go-client" "github.com/docusign/docusign-esign-go-client/auth" ) func getAccessToken() (string, error) { scopes := []string{oauth.Scope_SIGNATURE, oauth.Scope_IMPERSONATION} jwtConfig := auth.NewOAuth() jwtConfig.SetOAuthBasePath("account-d.docusign.com") jwtConfig.SetClientID("YOUR_INTEGRATION_KEY") jwtConfig.SetImpersonatedUserGuid("YOUR_USER_ID") jwtConfig.SetPrivateKey([]byte("YOUR_PRIVATE_KEY")) accessToken, err := jwtConfig.GetAccessToken(scopes) if err != nil { return "", err } return accessToken, nil }

Creating an envelope

Now, let's create an envelope to send:

func createEnvelope() (*esign.EnvelopeDefinition, error) { doc := esign.Document{ DocumentBase64: "BASE64_ENCODED_DOCUMENT", Name: "Document.pdf", FileExtension: "pdf", DocumentId: "1", } signer := esign.Signer{ Email: "[email protected]", Name: "John Doe", RecipientId: "1", RoutingOrder: "1", } signHere := esign.SignHere{ DocumentId: "1", PageNumber: "1", RecipientId: "1", XPosition: "100", YPosition: "100", } signer.Tabs = &esign.Tabs{SignHereTabs: []esign.SignHere{signHere}} envelope := esign.EnvelopeDefinition{ EmailSubject: "Please sign this document", Documents: []esign.Document{doc}, Recipients: &esign.Recipients{Signers: []esign.Signer{signer}}, Status: "sent", } return &envelope, nil }

Sending the envelope

Time to send that envelope off into the wild:

func sendEnvelope(accessToken, accountId string, envelope *esign.EnvelopeDefinition) (string, error) { apiClient := esign.NewAPIClient(esign.NewConfiguration()) apiClient.GetConfig().AddDefaultHeader("Authorization", "Bearer "+accessToken) envelopesApi := apiClient.EnvelopesApi result, _, err := envelopesApi.CreateEnvelope(accountId, envelope) if err != nil { return "", err } return result.EnvelopeId, nil }

Retrieving envelope status

Let's keep tabs on our envelope:

func getEnvelopeStatus(accessToken, accountId, envelopeId string) (*esign.Envelope, error) { apiClient := esign.NewAPIClient(esign.NewConfiguration()) apiClient.GetConfig().AddDefaultHeader("Authorization", "Bearer "+accessToken) envelopesApi := apiClient.EnvelopesApi envelope, _, err := envelopesApi.GetEnvelope(accountId, envelopeId) if err != nil { return nil, err } return envelope, nil }

Handling webhooks (optional)

If you want to receive real-time updates, set up a webhook endpoint:

func handleWebhook(w http.ResponseWriter, r *http.Request) { // Parse the incoming webhook payload var payload WebhookPayload if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } // Process the event based on payload.Event switch payload.Event { case "envelope-sent": // Handle sent event case "envelope-delivered": // Handle delivered event case "envelope-completed": // Handle completed event } w.WriteHeader(http.StatusOK) }

Error handling and best practices

Always handle errors gracefully and be mindful of rate limits. DocuSign has some pretty generous limits, but it's good practice to implement retries and backoff strategies.

Testing the integration

Don't forget to test! Here's a quick example of how you might test the envelope creation:

func TestCreateEnvelope(t *testing.T) { envelope, err := createEnvelope() if err != nil { t.Fatalf("Failed to create envelope: %v", err) } if envelope.EmailSubject != "Please sign this document" { t.Errorf("Unexpected email subject: %s", envelope.EmailSubject) } // Add more assertions as needed }

Conclusion

And there you have it! You've just built a DocuSign API integration in Go. Pretty cool, right? Remember, this is just scratching the surface. DocuSign's API is packed with features, so don't be afraid to explore and expand on this foundation.

For more in-depth info, check out the DocuSign API documentation and the esign package documentation.

Sample code repository

Want to see it all put together? I've got you covered! Check out the complete example in this GitHub repository.

Now go forth and sign those documents! Happy coding! 🚀📝