Developer Quickstart
This guide will help you get started with the Zapa Client Portals REST API and webhooks in under 10 minutes.
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
- Log into your Zapa Client Portals account
- Navigate to Settings → API Settings (see API & Webhook Settings)
- Enable API Access if it is not already enabled
- 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)
- IMPORTANT: Copy your
client_idandclient_secretimmediately — 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 Settings → Webhooks — 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
| Scope | Description |
|---|---|
portal:read | List and view portals |
portal:write | Create and update portals |
file:list | List file names and metadata |
file:upload | Upload files |
task:read | List tasks |
task:write | Create, update, and complete tasks |
guest:invite | Invite guests to portals |
webhook:manage | Manage webhooks |
Available Webhook Events
| Event | Description |
|---|---|
portal.created | New portal created |
portal.workflow_changed | Portal workflow state changed |
file.uploaded | File uploaded to portal |
file.signed | PDF signature completed |
task.created | New task created |
task.completed | Task marked as done |
guest.invited | Guest 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 Found429- 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:
- Go to webhook.site and copy your unique URL
- Register it as a webhook (Step 4 above)
- Trigger an event (create a portal, upload a file, etc.)
- See the webhook payload in real-time
Security Best Practices
- Never share your client secret — treat it like a password
- Use HTTPS only — never send tokens over unencrypted connections
- Store tokens securely — use environment variables or secure vaults
- Verify webhook signatures — always check HMAC signatures
- Use minimum required scopes — only request what you need
- 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