Skip to main content

Developer Quickstart

This guide will help you get started with the Zapa Client Portals REST API and webhooks in under 10 minutes.

Enterprise Feature

API access requires an Enterprise plan with API access enabled for your organization.

Base URL: https://api.zapaportal.com

For the complete endpoint reference, see the API Reference.

Prerequisites

  • A Zapa Client Portals organization account (admin access required, Enterprise plan)
  • Basic knowledge of REST APIs and OAuth 2.0
  • A tool for making HTTP requests (Postman, curl, or similar)

Step 1: Create an OAuth Client

  1. Log into your Zapa Client Portals account
  2. Navigate to SettingsAPI Settings (see API & Webhook Settings)
  3. Enable API Access if it is not already enabled
  4. Click Create OAuth Client:
    • Enter a name (e.g., "My Integration")
    • Add your redirect URI (e.g., https://your-app.com/callback)
    • Select the scopes you need (start with portal:read, portal:write)
  5. IMPORTANT: Copy your client_id and client_secret immediately — the secret is shown only once!

Step 2: Get an Access Token

The API uses the OAuth 2.0 Authorization Code flow.

1. Direct the user to the authorization URL (on the web app domain):

https://app.zapaportal.com/oauth/authorize?
client_id=YOUR_CLIENT_ID&
response_type=code&
redirect_uri=YOUR_REDIRECT_URI&
scope=portal:read portal:write file:list&
state=RANDOM_STRING

2. The user approves and is redirected back with a code:

https://your-redirect-uri?code=AUTHORIZATION_CODE&state=RANDOM_STRING

3. Exchange the code for an access token (on the API domain):

curl -X POST https://api.zapaportal.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=AUTHORIZATION_CODE" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "redirect_uri=YOUR_REDIRECT_URI"

Response:

{
"access_token": "eyJhbGc...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "refresh_token_here",
"scope": "portal:read portal:write file:list"
}

The token endpoint accepts both application/x-www-form-urlencoded and application/json bodies.

Step 3: Make Your First API Call

# Verify authentication
curl https://api.zapaportal.com/api/v1/me \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"

# List all portals
curl https://api.zapaportal.com/api/v1/portals \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"

# Create a new portal
curl -X POST https://api.zapaportal.com/api/v1/portals \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Client Onboarding - ABC Corp",
"tags": ["client", "onboarding"]
}'

Step 4: Set Up Webhooks (Optional)

Subscribe to real-time events with the webhooks API:

curl -X POST https://api.zapaportal.com/api/v1/webhooks \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/zapa",
"events": ["portal.created", "file.uploaded", "task.completed"]
}'

The response includes a secret for signature verification. You can also manage webhooks in the app under SettingsWebhooks — see API & Webhook Settings.

Verify Webhook Signatures

const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
const hmac = crypto.createHmac('sha256', secret);
hmac.update(JSON.stringify(payload));
const expectedSignature = hmac.digest('hex');
return signature === expectedSignature;
}

// In your webhook endpoint
app.post('/webhooks/zapa', (req, res) => {
const signature = req.headers['x-webhook-signature'];
const payload = req.body;

if (verifyWebhookSignature(payload, signature, WEBHOOK_SECRET)) {
console.log('Webhook verified:', payload.event, payload.data);
res.status(200).send('OK');
} else {
res.status(401).send('Invalid signature');
}
});

Step 5: Refresh Your Access Token

Access tokens expire after 1 hour. Use the refresh token to get a new one:

curl -X POST https://api.zapaportal.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "refresh_token=YOUR_REFRESH_TOKEN" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"

Available Scopes

ScopeDescription
portal:readList and view portals
portal:writeCreate and update portals
file:listList file names and metadata
file:uploadUpload files
task:readList tasks
task:writeCreate, update, and complete tasks
guest:inviteInvite guests to portals
webhook:manageManage webhooks

Available Webhook Events

EventDescription
portal.createdNew portal created
portal.workflow_changedPortal workflow state changed
file.uploadedFile uploaded to portal
file.signedPDF signature completed
task.createdNew task created
task.completedTask marked as done
guest.invitedGuest invited to portal

Error Handling

All API errors return standard HTTP status codes with JSON error details:

{
"error": "invalid_request",
"error_description": "The request is missing a required parameter"
}

Common error codes:

  • 400 - Bad Request (invalid parameters)
  • 401 - Unauthorized (invalid or missing token)
  • 403 - Forbidden (insufficient scopes)
  • 404 - Not Found
  • 429 - Too Many Requests (rate limit exceeded)
  • 500 - Internal Server Error

Rate Limits

  • API Calls: 10,000 requests per day per client
  • Webhook Delivery: 3 retry attempts with exponential backoff

Webhook Testing

Use webhook.site to test webhook delivery:

  1. Go to webhook.site and copy your unique URL
  2. Register it as a webhook (Step 4 above)
  3. Trigger an event (create a portal, upload a file, etc.)
  4. See the webhook payload in real-time

Security Best Practices

  1. Never share your client secret — treat it like a password
  2. Use HTTPS only — never send tokens over unencrypted connections
  3. Store tokens securely — use environment variables or secure vaults
  4. Verify webhook signatures — always check HMAC signatures
  5. Use minimum required scopes — only request what you need
  6. Handle token expiration — implement refresh token logic

What the API Can't Do (Yet)

  • File downloads: the API returns file metadata only, never file contents. This is a deliberate privacy guarantee — the OAuth consent screen tells users that connected apps cannot download their documents. To point someone at a file, link them into the web app instead: https://app.zapaportal.com/org/{org_id}/vault/{portal_id}/folder/main?file={file_id}
  • Guest permission management: invited guests receive default permissions; adjust them in the web app.

Need one of these, or something else the API doesn't cover? Email support@zapaportal.com — API additions are prioritized based on customer requests.

Next Steps

  • Browse the full API Reference
  • Connect without code using our Zapier integration