Unifize Knowledge Base
  • Quickstart
    • Welcome to Unifize!
  • Getting started
    • Setting up your Unifize account
      • Signing up with invite link
      • Logging in with email
    • Quickstart demo
    • Key features & navigation
      • Records
      • Conversations
      • Checklists
    • First steps for new users
      • Creating a new record
      • Creating records from inbound email
      • Filling checklist metadata
      • Linking related records
      • Sharing conversations as email
      • Sending and receiving emails in Unifize
      • Inviting people
      • Changing your preferred language
      • Filtering records in My Inbox
      • Generating PDF reports
      • Creating custom reports
      • Creating custom dashboards
    • Using Unifize AI
  • Troubleshooting & support guide
  • User Guide
    • Definitions
      • Process
      • Record
      • Conversation
      • Report
      • Chart
      • Checklist
      • Org
    • Navigating the platform
      • Profile
      • My Inbox
      • Manage
      • Homescreen
      • Contacts
      • Direct Messages
      • Dashboard
    • Data & process management
      • File Management
      • Checklists & Forms
      • Rich text in checklist
      • Working with records
        • Due dates & priorities of a record
    • User & role management
      • Understanding roles & access
      • Managing permissions
      • Deactivating users
      • Team & organization
    • Mobile & web accessibility
      • Unifize Lite
      • Mobile app
      • Web app vs Unifize Lite
    • Security, compliance & infrastructure
    • Personalizations
      • Set your profile picture
      • Reset your Passwords
      • Customizing Homescreen
      • Set your email notification preferences
    • File upload
      • SharePoint
        • Configuring SharePoint on Unifize
        • Using SharePoint on Unifize
    • SSO
      • Logging in with SSO
      • SSO using SAML
    • Process Builder
      • Checklist
        • Picklist
          • Picklist field in Checklist
  • Product Help
    • Unifize Document Management System (DMS)
      • Document Control
      • Change Control
      • Training Management
      • Onboarding guide for DMS
      • Troubleshooting & support guide for DMS
  • Admin Guide
    • Multi-language translation support
      • Enabling and configuring language support
      • Managing user language preferences at scale
      • Using the translation editor to customize UI
    • Customization & configuration
      • Configuring processes
      • Configuring revision fields
      • Configuring approval workflows
      • Configuring reminders on processes
      • Checklist layout settings
      • Custom language settings
      • Creating a chart from reports
      • Configuring Microsoft Office 365
        • Permissions required for SharePoint
  • Developer Documentation
    • Introduction
      • Concepts & terminologies
    • Authentication
      • App management
      • App tokens
    • Usage
      • Fair usage policy
      • Testing environment
      • Quickstart
    • API Reference
      • Applications
      • Processes
      • Records
      • Field values
  • RELEASE NOTES
    • February 2025
    • March 2025
    • April 2025
      • Rich Text Fields in Checklist
      • Filling Checklist Metadata with AI
      • 'My Conversations' is now 'My Inbox'
      • Feature Enhancements
Powered by GitBook
On this page
  • Introduction
  • Authentication and Authorization
  • Organizations
  • Test it out
Export as PDF
  1. Developer Documentation
  2. Usage

Quickstart

Make your first API call!

PreviousTesting environmentNextAPI Reference

Last updated 1 month ago

Before you get started with this section, pleasure ensure you have the following 3 pieces of data with you:

  1. Your App ID

  2. Your App's RSA private key

  3. The Org ID corresponding to your testing/live environment

For (1) and (2), revisit the section.

For (3), revisit the section.

Introduction

The Unifize APIs are crafted following RESTful standards, ensuring that interaction with resources is consistent and intuitive. The APIs are endpoint-driven and typically represent distinct resources, allowing for clear, organized, and efficient communication between systems.

All interactions are managed through the JSON data format, which necessitates setting the content type to application/json. This requirement is enforced for both request and response bodies unless otherwise specified, facilitating seamless data exchange and integration with various applications. Such consistent data handling simplifies interaction and enhances compatibility with different platforms and programming environments.

Authentication and Authorization

Authentication is a necessary aspect of utilizing the Unifize APIs and is implemented via app tokens. These tokens are generated according to the guidelines detailed in the App Tokens page.

Additionally, authorization is handled via a permissions framework, which grants granular control over access levels and operations. Permissions can be set initially during app creation and remain flexible, allowing for modifications as the needs of the application evolve. This dual-layered security model ensures that the Unifize APIs provide robust protection for sensitive operations and data.

Organizations

Central to Unifize's architecture are logical entities known as "Organizations," which help partition and manage resources within the system. The Org Id of these organizations must be specified during the initial token request process. This token, once embedded within a JWT, eliminates the need for repeatedly specifying the Org Id in further API calls, streamlining authentication processes and reducing complexity.

You can read more about Organizations in the Concepts and Terminologies page.

Test it out

To do this using your preferred programming language, the only requirements are:

  • A library to mint JWTs

  • A library to read/parse PEM files

  • A library to make network requests

Below are some examples in commonly used programming languages.

Prerequisites:

npm install jsonwebtoken axios
const fs = require('fs');
const jwt = require('jsonwebtoken');
const axios = require('axios');

/**
 * Loads a private key from a PEM file
 * @param {string} filePath - Path to the PEM file
 * @returns {string} Private key as a string
 */
function loadPrivateKeyFromPem(filePath) {
  return fs.readFileSync(filePath, 'utf8');
}

/**
 * Generates a JWT token with the given app ID and signed using the private key
 * @param {number} appId - The application ID to use as issuer
 * @param {string} privateKeyPath - Path to the private key PEM file
 * @returns {string} Signed JWT token
 */
function generateJwt(appId, privateKeyPath) {
  // Load the private key
  const privateKey = loadPrivateKeyFromPem(privateKeyPath);
  
  // Get current time in seconds
  const nowSeconds = Math.floor(Date.now() / 1000);
  
  // Create the payload
  const payload = {
    iss: appId.toString(),
    iat: nowSeconds,
    exp: nowSeconds + 600
  };
  
  // Sign the JWT
  return jwt.sign(payload, privateKey, { algorithm: 'RS256' });
}

/**
 * Exchanges the JWT for an access token
 * @param {string} jwtToken - The JWT token to exchange
 * @param {number} orgId - The organization ID
 * @returns {Promise} Promise resolving to the access token response
 */
async function exchangeJwtForAccessToken(jwtToken, orgId) {
  try {
    const response = await axios.post(
      `https://api.example.com/application/installation/${orgId}/token`,
      { token: jwtToken },
      {
        headers: {
          'Authorization': `Bearer ${jwtToken}`,
          'Content-Type': 'application/json'
        }
      }
    );
    return response.data;
  } catch (error) {
    throw error;
  }
}

/**
 * Makes an API call with the access token in the Authorization header
 * @param {string} accessToken - The access token to use for authorization
 * @returns {Promise} Promise resolving to the API response
 */
async function makeApiCall(accessToken) {
  try {
    const response = await axios.get('https://api.example.com/', {
      headers: {
        'Authorization': `Bearer ${accessToken}`
      }
    });
    return response;
  } catch (error) {
    throw error;
  }
}

/**
 * Main function to demonstrate the JWT generation, token exchange, and API call
 */
async function main() {
  // Example usage
  const appId = 12345;
  const orgId = 67890;
  const privateKeyPath = 'path/to/private_key.pem';
  
  try {
    // Generate JWT
    const jwt = generateJwt(appId, privateKeyPath);
    console.log('JWT generated successfully');
    
    // Exchange JWT for access token
    const tokenResponse = await exchangeJwtForAccessToken(jwt, orgId);
    const accessToken = tokenResponse.access_token;
    const expiresAt = tokenResponse.expires_at;
    console.log(`Access token received, expires at: ${expiresAt}`);
    
    // Make API call with access token
    const response = await makeApiCall(accessToken);
    
    // Print response
    console.log(`Status code: ${response.status}`);
    console.log(`Response body:`, response.data);
  } catch (error) {
    console.error('Error:', error.message);
    if (error.response) {
      console.error('Response status:', error.response.status);
      console.error('Response data:', error.response.data);
    }
  }
}

// Execute the main function
main();

Prerequisites:

pip install pyjwt requests cryptography
import jwt
import time
import requests
from pathlib import Path
from cryptography.hazmat.primitives.serialization import load_pem_private_key
from cryptography.hazmat.backends import default_backend


def load_private_key_from_pem(file_path):
    """
    Loads a private key from a PEM file
    
    Args:
        file_path (str): Path to the PEM file
        
    Returns:
        cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey: The private key object
    """
    pem_data = Path(file_path).read_bytes()
    # Load the private key - passing None for password if the key is not encrypted
    private_key = load_pem_private_key(pem_data, password=None, backend=default_backend())
    return private_key


def generate_jwt(app_id, private_key_path):
    """
    Generates a JWT token with the given app ID and signed using the private key
    
    Args:
        app_id (int): The application ID to use as issuer
        private_key_path (str): Path to the private key PEM file
        
    Returns:
        str: Signed JWT token
    """
    # Load the private key
    private_key = load_private_key_from_pem(private_key_path)
    
    # Get current time in seconds
    now_seconds = int(time.time())
    
    # Create the payload
    payload = {
        'iss': str(app_id),
        'iat': now_seconds,
        'exp': now_seconds + 600
    }
    
    # Sign the JWT
    return jwt.encode(payload, private_key, algorithm='RS256')


def exchange_jwt_for_access_token(jwt_token, org_id):
    """
    Exchanges the JWT for an access token
    
    Args:
        jwt_token (str): The JWT token to exchange
        org_id (int): The organization ID
        
    Returns:
        dict: The access token response containing access_token and expires_at
    """
    headers = {
        'Authorization': f'Bearer {jwt_token}',
        'Content-Type': 'application/json'
    }
    
    payload = {
        'token': jwt_token
    }
    
    response = requests.post(
        f'https://api.example.com/application/installation/{org_id}/token',
        headers=headers,
        json=payload
    )
    
    response.raise_for_status()  # Raise an exception for HTTP errors
    return response.json()


def make_api_call(access_token):
    """
    Makes an API call with the access token in the Authorization header
    
    Args:
        access_token (str): The access token to use for authorization
        
    Returns:
        requests.Response: The API response
    """
    headers = {
        'Authorization': f'Bearer {access_token}'
    }
    
    return requests.get('https://api.example.com/', headers=headers)


def main():
    """
    Main function to demonstrate the JWT generation, token exchange, and API call
    """
    # Example usage
    app_id = 12345
    org_id = 67890
    private_key_path = 'path/to/private_key.pem'
    
    try:
        # Generate JWT
        jwt_token = generate_jwt(app_id, private_key_path)
        print("JWT generated successfully")
        
        # Exchange JWT for access token
        token_response = exchange_jwt_for_access_token(jwt_token, org_id)
        access_token = token_response['access_token']
        expires_at = token_response['expires_at']
        print(f"Access token received, expires at: {expires_at}")
        
        # Make API call with access token
        response = make_api_call(access_token)
        
        # Print response
        print(f"Status code: {response.status_code}")
        print(f"Response body: {response.text}")
        
    except Exception as e:
        print(f"Error: {str(e)}")


if __name__ == "__main__":
    main()

Add the following dependencies to your project:

  • io.jsonwebtoken:jjwt-api

  • io.jsonwebtoken:jjwt-impl

  • io.jsonwebtoken:jjwt-jackson (or another JSON processor implementation)

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.Instant;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.jackson.io.JacksonDeserializer;
import io.jsonwebtoken.jackson.io.JacksonSerializer;
import io.jsonwebtoken.io.Deserializer;
import io.jsonwebtoken.io.Serializer;

public class JwtApiClient {
    
    /**
     * Generates a JWT token with the given app ID and signed using the private key
     */
    public static String generateJwt(int appId, String privateKeyPath) throws Exception {
        // Load the private key from the PEM file
        PrivateKey privateKey = loadPrivateKeyFromPem(privateKeyPath);
        
        // Get current time
        long nowSeconds = Instant.now().getEpochSecond();
        
        // Build the JWT
        return Jwts.builder()
                .setIssuer(String.valueOf(appId))
                .setIssuedAt(new Date(nowSeconds * 1000))
                .setExpiration(new Date((nowSeconds + 600) * 1000))
                .signWith(privateKey, SignatureAlgorithm.RS256)
                .compact();
    }
    
    /**
     * Exchanges the JWT for an access token
     */
    public static Map<String, Object> exchangeJwtForAccessToken(String jwt, int orgId) throws IOException, InterruptedException {
        HttpClient client = HttpClient.newHttpClient();
        
        // Create the JSON payload
        String jsonPayload = String.format("{\"token\":\"%s\"}", jwt);
        
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.example.com/application/installation/" + orgId + "/token"))
                .header("Authorization", "Bearer " + jwt)
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(jsonPayload))
                .build();
        
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        
        if (response.statusCode() >= 400) {
            throw new IOException("Failed to exchange token: " + response.statusCode() + ", " + response.body());
        }
        
        // Parse the JSON response using the JJWT Jackson deserializer
        Deserializer<Map<String, ?>> deserializer = new JacksonDeserializer<>();
        return (Map<String, Object>) deserializer.deserialize(response.body().getBytes());
    }
    
    /**
     * Makes an API call to the root endpoint with the access token in the Authorization header
     */
    public static HttpResponse<String> makeApiCall(String accessToken) throws IOException, InterruptedException {
        HttpClient client = HttpClient.newHttpClient();
        
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.example.com/"))
                .header("Authorization", "Bearer " + accessToken)
                .GET()
                .build();
        
        return client.send(request, HttpResponse.BodyHandlers.ofString());
    }
    
    /**
     * Loads an RSA private key from a PEM file
     */
    private static PrivateKey loadPrivateKeyFromPem(String filePath) throws Exception {
        String key = new String(Files.readAllBytes(Paths.get(filePath)));
        
        // Remove PEM format headers and footers and decode
        String privateKeyPEM = key
                .replace("-----BEGIN PRIVATE KEY-----", "")
                .replace("-----END PRIVATE KEY-----", "")
                .replaceAll("\\s", "");
        
        byte[] encoded = Base64.getDecoder().decode(privateKeyPEM);
        
        // Create the private key
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
        return keyFactory.generatePrivate(keySpec);
    }
    
    public static void main(String[] args) {
        // Example usage
        int appId = 12345;
        int orgId = 67890;
        String privateKeyPath = "path/to/private_key.pem";
        
        try {
            // 1. Generate JWT
            String jwt = generateJwt(appId, privateKeyPath);
            System.out.println("JWT generated successfully");
            
            // 2. Exchange JWT for access token
            Map<String, Object> tokenResponse = exchangeJwtForAccessToken(jwt, orgId);
            String accessToken = (String) tokenResponse.get("access_token");
            String expiresAt = (String) tokenResponse.get("expires_at");
            System.out.println("Access token received, expires at: " + expiresAt);
            
            // 3. Make API call with access token
            HttpResponse<String> response = makeApiCall(accessToken);
            
            // 4. Print response
            System.out.println("Status code: " + response.statusCode());
            System.out.println("Response body: " + response.body());
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Also see the

Authentication
Testing Environment
API Reference.