Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,26 @@
## signNow API SDK configuration
##

## Replace these dummy values with your actual credentials except SIGNNOW_API_HOST
# Required — replace placeholders with real credentials before running.
SIGNNOW_API_HOST=https://api.signnow.com
SIGNNOW_API_BASIC_TOKEN=test
SIGNNOW_API_USERNAME=test
SIGNNOW_API_PASSWORD=test
SIGNNOW_DOWNLOADS_DIR=~/Downloads
SIGNNOW_API_BASIC_TOKEN=<replace-me>
SIGNNOW_API_USERNAME=<replace-me>
SIGNNOW_API_PASSWORD=<replace-me>

# Path inside the running environment where downloaded files are written.
# Inside Docker, leave as /tmp (or another writable path). The ~ does not expand in containers.
SIGNNOW_DOWNLOADS_DIR=/tmp

##
## Sample-app runtime configuration
##

# Public base URL used to build redirect URIs sent to the SignNow embed widget.
# Must match the host the browser reaches this app on.
APP_BASE_URL=http://localhost:8080

# Demo-only signer credentials used by samples that generate limited signer tokens.
# For production deployments replace with per-tenant values or remove the affected samples.
SIGNNOW_DEMO_USER_EMAIL=example@example.com
SIGNNOW_DEMO_USER_PASSWORD=example
SIGNNOW_SIGNER_EMAIL=test@example.com
23 changes: 17 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
FROM maven:3.9.9-eclipse-temurin-23 AS build
FROM maven:3.9.9-eclipse-temurin-17 AS build
WORKDIR /app
COPY pom.xml ./
RUN mvn -B dependency:go-offline
COPY src ./src
RUN mvn clean install package -DskipTests
RUN mvn -B clean package -DskipTests

FROM openjdk:23-jdk-slim
VOLUME /tmp
COPY --from=build /app/target/java-sample-app-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
FROM eclipse-temurin:17-jre
RUN apt-get update \
&& apt-get install -y --no-install-recommends curl \
&& rm -rf /var/lib/apt/lists/* \
&& groupadd -r app && useradd -r -g app -d /home/app -m app
WORKDIR /home/app
COPY --from=build /app/target/java-sample-app-0.0.1-SNAPSHOT.jar /home/app/app.jar
RUN chown -R app:app /home/app
USER app
ENV JAVA_OPTS="-XX:MaxRAMPercentage=75 -XX:+UseG1GC"
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s --start-period=20s --retries=3 \
CMD curl -fsS http://127.0.0.1:8080/actuator/health || exit 1
ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS -jar /home/app/app.jar"]
21 changes: 21 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# The MIT License

Copyright (c) 2003-present SignNow

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
202 changes: 153 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,93 +1,197 @@
# SignNow Java SDK Sample Application
# SignNow Java Sample App

This is a demonstration project that showcases how to use the [SignNow Java SDK](https://github.com/signnow/SNJavaSDK) to interact with the SignNow API.
[![Java](https://img.shields.io/badge/java-17-orange)](https://openjdk.org/)
[![Spring Boot](https://img.shields.io/badge/Spring_Boot-3.4-brightgreen)](https://spring.io/projects/spring-boot)
[![SignNow SDK](https://img.shields.io/badge/SignNow_SDK-3.5+-light)](https://github.com/signnow/SNJavaSDK)
[![License](https://img.shields.io/badge/license-MIT-green)](./LICENSE)

Each sample represents a standalone use case and is implemented in a separate directory under:
A Spring Boot application demonstrating the SignNow API via the official [SignNow Java SDK](https://github.com/signnow/SNJavaSDK).

```
src/main/java/com/signnow/samples
```
## Quick Start

The static frontend resources for each sample (e.g. HTML, JS, CSS) are located in:
### 1. Enter the directory

```
src/main/resources/static/samples
```bash
cd SampleApps/java-sample-app
```

## Getting Started

### 1. Set Up Your Environment

Copy the provided `.env.example` file to `.env`:
### 2. Configure environment

```bash
cp .env.example .env
```

Edit the `.env` file and replace the placeholder values with your actual SignNow API credentials and settings.
Edit `.env` and fill in your SignNow credentials:

### 2. Build and Run the Application
| Variable | Example | Description |
|---|---|---|
| `SIGNNOW_API_HOST` | `https://api.signnow.com` | Production or sandbox URL |
| `SIGNNOW_API_BASIC_TOKEN` | `c2lnbk5vdy4...` | Base64 token from [API Dashboard](https://app.signnow.com/webapp/api-dashboard/keys) |
| `SIGNNOW_API_USERNAME` | `you@example.com` | Your SignNow account email |
| `SIGNNOW_API_PASSWORD` | `••••••` | Your SignNow account password |
| `SIGNNOW_DOWNLOADS_DIR` | `/tmp/signnow-downloads` | Where downloaded documents are cached |
| `APP_BASE_URL` | `http://localhost:8080` | Public base URL used in `redirect_uri` |
| `SIGNNOW_SIGNER_EMAIL` | `signer@example.com` | Default embedded signer email |
| `SIGNNOW_DEMO_USER_EMAIL` | `demo@example.com` | Demo sender email (used in some samples) |
| `SIGNNOW_DEMO_USER_PASSWORD` | `••••••` | Demo sender password |

You can build and run the application using Docker:
### 3. Run with Docker

```bash
docker build -t java-sample-app .
docker run -v $(pwd)/.env:/.env -p 8080:8080 java-sample-app
```

Once the app is running, access it via:
### 4. Run locally (no Docker)

```
http://localhost:8080/samples/{exampleName}
```bash
mvn spring-boot:run
```

Replace `{exampleName}` with the name of the specific example you want to run (e.g. `DocumentInvite`, `PrefillForm`, etc.).
Requires Java 17+ and Maven 3.9+ on `PATH`. The app reads `.env` from the working directory.

## Routing Logic
### 5. Open a sample

All requests are routed through a single controller: `RoutingController`.
```
http://localhost:8080/samples/EmbeddedSignerConsentForm
```

* **GET /samples/{exampleName}**: Loads and executes the corresponding `IndexController` class from the example folder.
* **POST /api/samples/{exampleName}**: Handles form submissions for the given example.
`http://localhost:8080/samples` lists all available samples.

## Available Samples (20)

| Sample | Description |
|---|---|
| EmbeddedSignerConsentForm | Consent form with single embedded signer |
| EmbeddedSenderWithoutFormFile | Sales proposal — embedded sender |
| EmbeddedSenderWithFormCreditLoanAgreement | Credit loan agreement |
| EmbeddedSignerConsumerServices | Veterinary intake form |
| EmbeddedSignerPatientIntakeForm | Patient intake (healthcare) |
| EmbeddedSignerWithFormInsurance | Insurance claim form |
| MedicalInsuranceClaimForm | Medical insurance claim |
| EmbeddedEditingAndSigningDG | Document generation: edit + sign |
| EmbeddedSenderWithFormAndFirstSigner | Sender is also first signer |
| EmbeddedSenderWithFormDG | Document generation variant |
| EmbeddedSenderWithFormDGAdjunct | DG adjunct form |
| EmbeddedSenderWithFormDGConstr | DG construction form |
| ISVWithFormAndOneClickSendBasicPrefill | ISV one-click send, basic prefill |
| ISVWithFormAndOneClickSendMergeFields | ISV one-click send, merge fields |
| HROnboardingSystem | HR onboarding multi-document flow |
| UploadEmbeddedSender | Upload PDF + embedded sender |
| PrefillAndEmbeddedSendingAgreement | Prefill + embedded send |
| PrefillAndOneClickSendingAgreement | Prefill + one-click send |
| EVDemoSendingAnd3EmbeddedSigners | Real estate: 3 sequential embedded signers |
| UploadEmbeddedEditingAndInvite | Upload PDF, embedded edit, invite |

## Project Structure

Only example names matching `^[a-zA-Z0-9_]+$` are allowed for security reasons.
```
src/main/java/com/signnow/
javasampleapp/
JavaSampleAppApplication.java Spring Boot entry point
ExampleInterface.java Sample contract (handleGet + handlePost)
controllers/
RoutingController.java GET /samples/:name, POST /api/samples/:name
config/
AppConfig.java Reads .env; provides AppConfig.sampleUrl()
samples/
<SampleName>/
IndexController.java Implements ExampleInterface

src/main/resources/
static/
samples/<SampleName>/
index.html UI served on GET /samples/<SampleName>
css/, img/ Shared static assets
application.properties Spring config

src/test/
JavaSampleAppApplicationTests.java Context load test
controllers/RoutingControllerTest.java MockMvc routing tests
```

## Structure of a Sample Example
## Routing

| Method | Path | Handler |
|---|---|---|
| GET | `/samples/{name}` | `samples/<name>/IndexController.handleGet` |
| POST | `/api/samples/{name}` | `samples/<name>/IndexController.handlePost` |
| GET | `/css/*`, `/img/*`, etc. | Shared static files |

Sample names must match `^[a-zA-Z0-9_]+$`. `RoutingController` loads each sample's `IndexController` by class name convention at request time — no whitelist or registration needed.

## Add a New Sample

1. Create `src/main/java/com/signnow/samples/MyNewSample/IndexController.java`:
```java
package com.signnow.samples.MyNewSample;

import com.signnow.javasampleapp.ExampleInterface;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import java.io.IOException;
import java.util.Map;

@Controller
public class IndexController implements ExampleInterface {
@Override
public ResponseEntity<String> handleGet(Map<String, String> queryParams) throws IOException {
try (var in = getClass().getResourceAsStream("/static/samples/MyNewSample/index.html")) {
return ResponseEntity.ok().header("Content-Type", "text/html")
.body(new String(in.readAllBytes()));
}
}

@Override
public ResponseEntity<?> handlePost(String formData) throws Exception {
// parse formData as JSON and implement your logic
return ResponseEntity.ok("{}");
}
}
```
2. Create `src/main/resources/static/samples/MyNewSample/index.html`.
3. Restart the application — `RoutingController` discovers the new controller automatically.

## Tests

Each sample should implement the `ExampleInterface` and provide its own `IndexController` class with `handleGet()` and `handlePost()` methods.
```bash
mvn test
```

____
2 test classes:
- `JavaSampleAppApplicationTests` — Spring context loads without errors
- `RoutingControllerTest` — 6 MockMvc tests covering name validation (`^[a-zA-Z0-9_]+$`), 404 for unknown samples, and routing dispatch

## Ready to build eSignature integrations with SignNow API? Get the SignNow extension for GitHub Copilot
Tests do **not** exercise real SignNow API calls (live credentials required).

Use AI-powered code suggestions to generate SignNow API code snippets in your IDE with GitHub Copilot. Get examples for common integration tasks—from authentication and sending documents for signature to handling webhooks, and building branded workflows.
## SDK Notes

### **🚀 Why use SignNow with GitHub Copilot**
Known constraints in the SignNow Java SDK that affect this codebase:

* **Relevant code suggestions**: Get AI-powered, up-to-date code snippets for SignNow API calls. All examples reflect the latest API capabilities and follow current best practices.
* **Faster development**: Reduce time spent searching documentation.
* **Fewer mistakes**: Get context-aware guidance aligned with the SignNow API.
* **Smooth onboarding**: Useful for both new and experienced developers working with the API.
**No multipart support in `RoutingController`** — `handlePost` receives `@RequestBody String formData` (raw JSON), not multipart. Samples that conceptually "upload" a file instead read a pre-bundled PDF from `src/main/resources/static/samples/<Name>/`. See `UploadEmbeddedSender` for the pattern.

### **Prerequisites:**
**`Invite` constructor order** — `new Invite(email, roleId, order, firstName, lastName)`. There is no shorter overload; all five parameters are required.

1\. GitHub Copilot installed and enabled.
2\. SignNow account. [Register here](https://www.signnow.com/developers)
**`DocumentInvitePostResponse.getData()`** — Returns a collection; each item exposes `.getRoleId()` (to match against role IDs you looked up) and `.getId()` (the invite ID needed for `DocumentInviteLinkPostRequest`).

### ⚙️ **How to use it**
**`DocumentInviteLinkPostRequest` constructor** — `(authType, linkExpiration)` where `authType` is typically `"none"`. Chain `.withDocumentId()` and `.withFieldInviteId()` before sending.

1\. Install the [SignNow extension](https://github.com/apps/signnow).
**`DocumentEmbeddedEditorLinkPostRequest` constructor** — `(redirectUri, redirectTarget, linkExpiration)`. Chain `.withDocumentId()` before sending. Response: `getData().getUrl()`.

2\. Start your prompts with [@signnow](https://github.com/signnow) in the Copilot chat window. The first time you use the extension, you may need to authorize it.
## Tech Stack

3\. Enter a prompt describing the integration scenario.
Example: @signnow Generate a Java code example for sending a document group to two signers.
- Java 17
- Spring Boot 3.4.1
- `signnow-java-sdk` 3.5.1 (from Maven Central)
- Maven 3.9
- JUnit 5 + Spring MockMvc (tests)
- Docker: multi-stage `maven:3.9-eclipse-temurin-17` → `eclipse-temurin:17-jre`

4\. Modify the generated code to match your app’s requirements—adjust parameters, headers, and workflows as needed.
## GitHub Copilot Extension

### **Troubleshooting**
**The extension doesn’t provide code examples for the SignNow API**
Get AI-powered SignNow code suggestions in your IDE:
[github.com/apps/signnow](https://github.com/apps/signnow) — start prompts with `@signnow`.

Make sure you're using `@signnow` in the Copilot chat and that the extension is installed and authorized.
## License

____
See [LICENSE](./LICENSE).
6 changes: 5 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
Expand All @@ -42,7 +46,7 @@
<dependency>
<groupId>com.signnow</groupId>
<artifactId>signnow-java-sdk</artifactId>
<version>3.5.0</version>
<version>3.5.1</version>
</dependency>
</dependencies>

Expand Down
Loading