The Connect API provides powerful filtering capabilities to query and retrieve exactly the data you need. Filters are passed as JSON-encoded objects in the filter query parameter.
Overview
Filters are used primarily with the GET /requests endpoint to narrow down the list of forms returned. All filter parameters are optional and can be combined to create complex queries.
Basic Usage
const filter = {
flow: { slug: 'client-onboarding' },
active: true ,
completed: false
};
const url = `https://connect.penbox.io/v1/requests?filter= ${ encodeURIComponent ( JSON . stringify ( filter )) } ` ;
const response = await fetch ( url , {
headers: { 'Authorization' : `Bearer ${ accessToken } ` }
});
const requests = await response . json ();
Available Filters
Workspace Filtering
Filter forms by workspace (company) using the workspace slug:
{
"company" : {
"slug" : "acme-corp"
}
}
Use cases:
Multi-tenant applications where each customer has their own workspace
Filtering forms for specific organizations
Workspace-specific reporting
Example:
// Get all forms from a specific workspace
const filter = {
company: { slug: 'acme-corp' }
};
Filter by form template (flow) using the template slug:
{
"flow" : {
"slug" : "client-onboarding"
}
}
Use cases:
Display forms from a specific template
Template-specific analytics
Workflow-based filtering
Example:
// Get all client onboarding forms
const filter = {
flow: { slug: 'client-onboarding' }
};
User Filtering
Filter forms by the contact’s information:
{
"user" : {
"email" : "[email protected] " ,
"given_name" : "John" ,
"family_name" : "Doe" ,
"phone" : "+1234567890" ,
"internal_ref" : "CRM-12345" ,
"company_name" : "Acme Corp"
}
}
Available user fields:
email: Contact’s email address
given_name: Contact’s first name
family_name: Contact’s last name
phone: Contact’s phone number
internal_ref: Your internal reference ID
company_name: Contact’s company name
Use cases:
Find all forms sent to a specific contact
Customer-specific dashboards
Support lookup by email or phone
Example:
// Find all forms for a specific email
const filter = {
user: { email: '[email protected] ' }
};
// Find forms by phone number
const filter = {
user: { phone: '+1234567890' }
};
Owner Filtering
Filter by the form owner (the person who created/sent the form):
Use cases:
Team member performance tracking
Personal dashboards
Assignment-based filtering
Example:
// Get forms owned by a specific team member
const filter = {
owner: { email: '[email protected] ' }
};
Status Filtering
Filter forms by their lifecycle status:
{
"active" : true ,
"archived" : false ,
"completed" : true ,
"processed" : false
}
Status Fields:
Field Type Description activeboolean Forms currently active (not expired) archivedboolean Forms that have been archived completedboolean Forms with at least one completed response processedboolean Forms marked as processed
Use cases:
Dashboard metrics (pending vs completed)
Archive management
Workflow state tracking
Examples:
// Get all active, unarchived forms awaiting completion
const filter = {
active: true ,
archived: false ,
completed: false
};
// Get completed but not yet processed forms
const filter = {
completed: true ,
processed: false
};
// Get archived forms for reporting
const filter = {
archived: true
};
External Args Filtering
Filter by your custom metadata stored in external_args:
{
"external_args" : {
"order_id" : "ORD-12345" ,
"source" : "crm" ,
"campaign" : "summer-2024"
}
}
Use cases:
Link forms to your system’s entities (orders, tickets, leads)
Campaign tracking
Source attribution
Custom categorization
Example:
// Find form by your order ID
const filter = {
external_args: { order_id: 'ORD-12345' }
};
// Filter by multiple custom fields
const filter = {
external_args: {
source: 'website' ,
campaign: 'summer-2024'
}
};
Use external_args to create bidirectional links between Penbox forms and your system’s data model.
Combining Filters
All filter criteria can be combined for precise queries:
// Complex filter: Active onboarding forms from Acme Corp that are completed but not processed
const filter = {
company: { slug: 'acme-corp' },
flow: { slug: 'client-onboarding' },
active: true ,
completed: true ,
processed: false
};
// Filter by user and external reference
const filter = {
user: { email: '[email protected] ' },
external_args: { crm_id: '12345' }
};
Control the number of results and implement pagination:
const params = new URLSearchParams ({
filter: JSON . stringify ({
flow: { slug: 'onboarding' },
active: true
}),
'page[limit]' : '50' , // Max 100
'page[offset]' : '0'
});
const response = await fetch (
`https://connect.penbox.io/v1/requests? ${ params } ` ,
{ headers: { 'Authorization' : `Bearer ${ accessToken } ` } }
);
Pagination Parameters:
Parameter Type Default Max Description page[limit]integer 30 100 Number of results per page page[offset]integer 0 - Number of results to skip
The maximum page[limit] is 100. For large datasets, implement pagination using page[offset].
Common Use Cases
Show all forms awaiting completion:
const filter = {
active: true ,
completed: false ,
archived: false
};
Support Lookup
Find all forms for a customer:
const filter = {
user: { email: customerEmail }
};
Track team member activity:
const filter = {
owner: { email: teamMemberEmail },
completed: true
};
Integration Sync
Find unprocessed forms to sync with your system:
const filter = {
completed: true ,
processed: false ,
external_args: { synced: false }
};
Template Analytics
Get metrics for a specific form template:
const filter = {
flow: { slug: 'client-onboarding' },
completed: true
};
Best Practices
Always filter by the most specific criteria first (e.g., external_args or user.email) to reduce result sets.
Cache frequently-used filter results (like “active forms”) to reduce API calls.
Use external_args consistently
Establish a consistent schema for external_args across your application for easier filtering and maintenance.
Always check if the result array is empty before processing: if ( requests . length === 0 ) {
console . log ( 'No forms found matching filter' );
}
Examples
Multi-Workspace Application
async function getUserForms ( userId , workspaceSlug ) {
const filter = {
company: { slug: workspaceSlug },
external_args: { user_id: userId }
};
const response = await fetch (
`https://connect.penbox.io/v1/requests?filter= ${ encodeURIComponent ( JSON . stringify ( filter )) } ` ,
{ headers: { 'Authorization' : `Bearer ${ accessToken } ` } }
);
return await response . json ();
}
CRM Integration
async function syncCompletedForms ( crmContactId ) {
const filter = {
external_args: { crm_contact_id: crmContactId },
completed: true ,
processed: false
};
const forms = await fetch (
`https://connect.penbox.io/v1/requests?filter= ${ encodeURIComponent ( JSON . stringify ( filter )) } ` ,
{ headers: { 'Authorization' : `Bearer ${ accessToken } ` } }
). then ( r => r . json ());
// Process each form and mark as processed
for ( const form of forms ) {
await syncToCRM ( form );
await markAsProcessed ( form . id );
}
}
async function getDashboardStats () {
// Get counts with different filters
const [ pending , completed , processed ] = await Promise . all ([
fetch ( `https://connect.penbox.io/v1/requests?filter= ${ JSON . stringify ({ active: true , completed: false }) } ` ),
fetch ( `https://connect.penbox.io/v1/requests?filter= ${ JSON . stringify ({ completed: true , processed: false }) } ` ),
fetch ( `https://connect.penbox.io/v1/requests?filter= ${ JSON . stringify ({ processed: true }) } ` )
]). then ( responses => Promise . all ( responses . map ( r => r . json ())))
. then ( results => results . map ( r => r . length ));
return { pending , completed , processed };
}
Error Handling
Invalid filters return a 400 Bad Request error:
{
"errors" : [
{
"status" : "400" ,
"title" : "Invalid Filter" ,
"detail" : "Invalid filter parameter format"
}
]
}
Common issues:
Invalid JSON format in filter parameter
Unrecognized filter fields
Type mismatches (e.g., string instead of boolean)
Solution:
try {
const response = await fetch ( url , { headers });
if ( ! response . ok ) {
const error = await response . json ();
console . error ( 'Filter error:' , error );
return [];
}
return await response . json ();
} catch ( error ) {
console . error ( 'Request failed:' , error );
return [];
}
Next Steps