Client Portal API
Client Portal API
Overview
The Client Portal API allows you to programmatically manage portal invitations, retrieve portal configuration, and generate portal access tokens.
Base URL
All endpoints are under /api/v1/client-portal/
Authentication
All endpoints require authentication using a Bearer token:
Authorization: Bearer your-api-token-here
Endpoints
Get Portal Configuration
Get the current portal configuration for the authenticated tenant.
Endpoint: GET /api/v1/client-portal/config
Response:
{
"data": {
"portal_name": "Client Portal",
"portal_logo": "portal-logos/logo.png",
"primary_color": "#3B82F6",
"secondary_color": "#1E40AF",
"welcome_message": "Welcome to your client portal!",
"enabled_modules": ["invoices", "proposals", "tasks"],
"is_active": true,
"allow_file_sharing": true,
"show_activity_feed": true,
"token_expiration_days": 30
}
}
Example:
curl -H "Authorization: Bearer your-token" \
https://your-domain.com/api/v1/client-portal/config
Send Portal Invitation to Contact
Send a portal access invitation email to a contact.
Endpoint: POST /api/v1/client-portal/contacts/{contactId}/invite
URL Parameters:
contactId(required) - The ID of the contact
Request Body:
{
"custom_message": "Welcome to your client portal! Click the link below to access your invoices, proposals, and more."
}
Response:
{
"message": "Portal invitation sent successfully",
"token": "portal-access-token-here"
}
Example:
curl -X POST \
-H "Authorization: Bearer your-token" \
-H "Content-Type: application/json" \
-d '{"custom_message": "Welcome!"}' \
https://your-domain.com/api/v1/client-portal/contacts/1/invite
Error Responses:
400 Bad Request- Contact doesn't have an email address404 Not Found- Contact not found500 Internal Server Error- Failed to send invitation
Send Portal Invitation to Company
Send a portal access invitation email to a company.
Endpoint: POST /api/v1/client-portal/companies/{companyId}/invite
URL Parameters:
companyId(required) - The ID of the company
Request Body:
{
"custom_message": "Welcome to your company portal!"
}
Response:
{
"message": "Portal invitation sent successfully",
"token": "portal-access-token-here"
}
Example:
curl -X POST \
-H "Authorization: Bearer your-token" \
-H "Content-Type: application/json" \
-d '{"custom_message": "Welcome!"}' \
https://your-domain.com/api/v1/client-portal/companies/1/invite
Get Portal Token
Get or create a portal access token for a contact or company.
Endpoint: POST /api/v1/client-portal/token
Request Body:
{
"type": "contact",
"id": 1
}
Parameters:
type(required) - Either"contact"or"company"id(required) - The ID of the contact or company
Response:
{
"token": "portal-access-token-here",
"url": "https://your-domain.com/client-portal/token-here",
"expires_at": "2026-02-19T00:00:00Z"
}
Example:
curl -X POST \
-H "Authorization: Bearer your-token" \
-H "Content-Type: application/json" \
-d '{"type": "contact", "id": 1}' \
https://your-domain.com/api/v1/client-portal/token
Use Case:
Use this endpoint to generate portal access tokens programmatically. You can then:
- Embed the portal URL in your own application
- Create custom invitation flows
- Build integrations that require portal access
Error Responses
All endpoints return standard error responses:
400 Bad Request:
{
"message": "Contact does not have an email address"
}
404 Not Found:
{
"message": "Contact not found"
}
500 Internal Server Error:
{
"message": "Failed to send portal invitation: Error details"
}
Rate Limiting
API requests are rate limited to 60 requests per minute per token. If you exceed this limit, you'll receive a 429 Too Many Requests response.
Webhooks
Portal-related webhook events:
client_portal.invitation_sent- Fired when a portal invitation is sentclient_portal.token_created- Fired when a new portal token is createdclient_portal.token_accessed- Fired when a portal token is accessed
See Webhooks Documentation for more information.
Examples
Send Invitation and Get Token
// Send invitation
const response = await fetch('/api/v1/client-portal/contacts/1/invite', {
method: 'POST',
headers: {
'Authorization': 'Bearer your-token',
'Content-Type': 'application/json'
},
body: JSON.stringify({
custom_message: 'Welcome to your portal!'
})
});
const data = await response.json();
console.log('Portal token:', data.token);
console.log('Portal URL:', `https://your-domain.com/client-portal/${data.token}`);
Get Portal Configuration
const response = await fetch('/api/v1/client-portal/config', {
headers: {
'Authorization': 'Bearer your-token'
}
});
const { data } = await response.json();
console.log('Portal name:', data.portal_name);
console.log('Enabled modules:', data.enabled_modules);
Best Practices
- Store Tokens Securely: If you store portal tokens, encrypt them
- Monitor Token Expiration: Check
expires_atand send new invitations before expiration - Handle Errors Gracefully: Always check response status and handle errors appropriately
- Respect Rate Limits: Implement retry logic with exponential backoff
- Use Custom Messages: Personalize invitation messages when possible
Next Steps
- See Client Portal Overview
- Review Webhooks Documentation
- Check Authentication Guide
Updated on: 13/03/2026
Thank you!
