Documentation Index Fetch the complete documentation index at: https://docs.propal.io/llms.txt
Use this file to discover all available pages before exploring further.
This guide shows you how to automatically create a Propal proposal when a deal reaches a specific stage in your CRM (HubSpot, Salesforce, Pipedrive, etc.).
Flow overview
A deal reaches the “Proposal” stage in your CRM
Your webhook/automation triggers a script
The script creates (or finds) a lead in Propal
Creates a proposal from a template
Publishes it and sends the link back to the CRM
Prerequisites
An API key with scopes: leads:read, leads:write, proposals:read, proposals:write, templates:read
At least one proposal template in Propal
Step 1: Find or create the lead
First, check if the contact already exists in Propal. If not, create them.
async function findOrCreateLead ( client , contactData ) {
// Search for existing lead by email
const { data : existingLeads } = await client
. request ( '/leads?search=' + encodeURIComponent (contactData.email))
. then ( r => r. json ());
if (existingLeads. length > 0 ) {
return existingLeads[ 0 ];
}
// Create a new lead
const response = await client. request ( '/leads' , {
method: 'POST' ,
body: JSON . stringify ({
name: contactData.name,
email: contactData.email,
company: contactData.company,
phone: contactData.phone,
}),
});
return response. json ();
}
Step 2: Pick a template
List your templates and select the right one:
async function getTemplate ( client , category ) {
const response = await client. request (
`/templates?category=${ category }&limit=1`
);
const { data } = await response. json ();
if (data. length === 0 ) {
throw new Error ( `No template found for category: ${ category }` );
}
return data[ 0 ];
}
Step 3: Create the proposal
async function createProposal ( client , lead , template , dealName ) {
const slug = dealName
. toLowerCase ()
. replace ( / [ ^ a-z0-9] + / g , '-' )
. replace ( / ^ - | - $ / g , '' );
const response = await client. request ( '/proposals' , {
method: 'POST' ,
body: JSON . stringify ({
template_id: template.id,
title: dealName,
slug: `${ slug }-${ Date . now () }` ,
lead_id: lead.id,
language: 'en' ,
settings: {
allow_client_to_sign: true ,
allow_client_to_deny: true ,
allow_payment: true ,
allow_client_to_download_pdf: true ,
},
}),
});
return response. json ();
}
Step 4: Publish the proposal
async function publishProposal ( client , proposalId ) {
await client. request ( `/proposals/${ proposalId }/publish` , {
method: 'POST' ,
});
}
Full example
import { PropalClient } from './propal-client.js' ;
const client = new PropalClient (process.env. PROPAL_API_KEY );
async function handleDealStageChange ( deal ) {
// 1. Find or create the lead
const lead = await findOrCreateLead (client, {
name: deal.contact.name,
email: deal.contact.email,
company: deal.contact.company,
phone: deal.contact.phone,
});
// 2. Get the right template
const template = await getTemplate (client, 'custom' );
// 3. Create the proposal
const proposal = await createProposal (
client,
lead,
template,
deal.name,
);
// 4. Publish it
await publishProposal (client, proposal.id);
// 5. Return the proposal URL to your CRM
const proposalUrl = `https://app.propal.io/p/${ proposal . id }` ;
console. log ( `Proposal created and published: ${ proposalUrl }` );
return proposalUrl;
}
Connecting to your CRM
Use HubSpot Workflows to trigger a webhook when a deal enters the “Proposal” stage. Point the webhook to your server running the script above. Alternatively, use Propal’s native HubSpot integration for a no-code setup.
Create a Zap or Scenario that triggers when a deal stage changes in your CRM, then use the “Webhooks” action to call the Propal API directly.
Poll your CRM’s API for deal stage changes, or set up webhooks if your CRM supports them. Run the script above whenever a deal reaches the proposal stage.