Created
March 18, 2025 13:44
-
-
Save dennisedson/666742c45701e662075bc44f22902574 to your computer and use it in GitHub Desktop.
Generate an invoice with HubSpot's APIs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const axios = require('axios'); | |
const hubspot = require('@hubspot/api-client'); | |
exports.main = async (event, callback) => { | |
const token = process.env.Token; | |
const hubspotClient = new hubspot.Client({ accessToken: token }); | |
// Retrieve the deal record ID (hs_object_id) from the workflow input fields. | |
const hs_object_id = event.inputFields['hs_object_id']; // This is the deal ID | |
// Set invoice dates. | |
const invoiceDate = new Date(); | |
const dueDate = addDays(invoiceDate, 30); | |
// STEP 1: Create a draft invoice. | |
const invoiceProperties = { | |
"hs_invoice_date": invoiceDate.toISOString(), | |
"hs_due_date": dueDate.toISOString(), | |
"hs_invoice_status": "draft", // Allowed values: "draft", "open", "paid", "voided" | |
"hs_currency": "USD" | |
}; | |
try { | |
// Create the invoice. | |
const invoiceResponse = await axios({ | |
method: 'post', | |
url: 'https://api.hubapi.com/crm/v3/objects/invoices', | |
headers: { | |
'Authorization': `Bearer ${token}`, | |
'Content-Type': 'application/json' | |
}, | |
data: JSON.stringify({ properties: invoiceProperties }) | |
}); | |
const invoiceId = invoiceResponse.data.id; | |
console.log(`Created invoice ${invoiceId}`); | |
// STEP 2: Associate the invoice with the deal using the default association endpoint. | |
await axios({ | |
method: 'put', | |
url: `https://api.hubapi.com/crm/v4/objects/invoices/${invoiceId}/associations/default/deal/${hs_object_id}`, | |
headers: { | |
'Authorization': `Bearer ${token}`, | |
'Content-Type': 'application/json' | |
} | |
}); | |
console.log(`Associated invoice ${invoiceId} with deal ${hs_object_id}`); | |
// STEP 3: Retrieve the contact associated with the deal and associate it with the invoice. | |
const contactsResults = await hubspotClient.crm.associations.v4.basicApi.getPage( | |
"Deal", | |
hs_object_id, | |
"Contact", | |
undefined, | |
10 | |
); | |
if (contactsResults.results.length > 0) { | |
const contactId = String(contactsResults.results[0].toObjectId); | |
await axios({ | |
method: 'put', | |
url: `https://api.hubapi.com/crm/v4/objects/invoices/${invoiceId}/associations/default/contact/${contactId}`, | |
headers: { | |
'Authorization': `Bearer ${token}`, | |
'Content-Type': 'application/json' | |
} | |
}); | |
console.log(`Associated invoice ${invoiceId} with contact ${contactId}`); | |
} else { | |
console.log(`No contact found for deal ${hs_object_id}`); | |
} | |
// STEP 3b: Retrieve the company associated with the deal and associate it with the invoice. | |
const companiesResults = await hubspotClient.crm.associations.v4.basicApi.getPage( | |
"Deal", | |
hs_object_id, | |
"Company", | |
undefined, | |
10 | |
); | |
if (companiesResults.results.length > 0) { | |
const companyId = String(companiesResults.results[0].toObjectId); | |
await axios({ | |
method: 'put', | |
url: `https://api.hubapi.com/crm/v4/objects/invoices/${invoiceId}/associations/default/company/${companyId}`, | |
headers: { | |
'Authorization': `Bearer ${token}`, | |
'Content-Type': 'application/json' | |
} | |
}); | |
console.log(`Associated invoice ${invoiceId} with company ${companyId}`); | |
} else { | |
console.log(`No company found for deal ${hs_object_id}`); | |
} | |
// STEP 4: Retrieve the line items associated with the deal. | |
const lineItemsResults = await hubspotClient.crm.associations.v4.basicApi.getPage( | |
"Deal", | |
hs_object_id, | |
"Line_Item", | |
undefined, | |
10 | |
); | |
const dealLineItemIds = lineItemsResults.results.map(({ toObjectId }) => String(toObjectId)); | |
// STEP 5: For each deal line item, create an equivalent line item and associate it with the invoice. | |
for (const lineItemId of dealLineItemIds) { | |
// Retrieve the original line item details. | |
const lineItemResponse = await axios({ | |
method: 'get', | |
url: `https://api.hubapi.com/crm/v3/objects/line_items/${lineItemId}`, | |
headers: { | |
'Authorization': `Bearer ${token}`, | |
'Content-Type': 'application/json' | |
} | |
}); | |
const lineItemData = lineItemResponse.data; | |
// Extract details—adjust property keys as needed. | |
const { name, quantity, price, hs_product_id, hs_tax_rate_group_id } = lineItemData.properties; | |
// Build new line item properties. | |
let newLineItemProperties = { | |
"name": name, | |
"quantity": quantity, | |
"price": price | |
}; | |
if (hs_product_id) { | |
newLineItemProperties.hs_product_id = hs_product_id; | |
} | |
if (hs_tax_rate_group_id) { | |
newLineItemProperties.hs_tax_rate_group_id = hs_tax_rate_group_id; | |
} | |
// Create the new line item. | |
const newLineItemResponse = await axios({ | |
method: 'post', | |
url: 'https://api.hubapi.com/crm/v3/objects/line_items', | |
headers: { | |
'Authorization': `Bearer ${token}`, | |
'Content-Type': 'application/json' | |
}, | |
data: JSON.stringify({ properties: newLineItemProperties }) | |
}); | |
const newLineItemId = newLineItemResponse.data.id; | |
console.log(`Created new line item ${newLineItemId} based on deal line item ${lineItemId}`); | |
// Associate the new line item with the invoice using the default association endpoint. | |
await axios({ | |
method: 'put', | |
url: `https://api.hubapi.com/crm/v4/objects/invoices/${invoiceId}/associations/default/line_item/${newLineItemId}`, | |
headers: { | |
'Authorization': `Bearer ${token}`, | |
'Content-Type': 'application/json' | |
} | |
}); | |
console.log(`Associated new line item ${newLineItemId} with invoice ${invoiceId}`); | |
} | |
// STEP 6: Update the invoice status to "open". | |
await axios({ | |
method: 'patch', | |
url: `https://api.hubapi.com/crm/v3/objects/invoices/${invoiceId}`, | |
headers: { | |
'Authorization': `Bearer ${token}`, | |
'Content-Type': 'application/json' | |
}, | |
data: JSON.stringify({ | |
properties: { | |
"hs_invoice_status": "open" | |
} | |
}) | |
}); | |
console.log(`Updated invoice ${invoiceId} status to open`); | |
callback({ | |
outputFields: { | |
invoiceId: invoiceId | |
} | |
}); | |
} catch (error) { | |
console.error(error.response ? error.response.data : error); | |
callback({ outputFields: {} }); | |
} | |
}; | |
// Helper function to add days to a date. | |
function addDays(date, days) { | |
const result = new Date(date); | |
result.setDate(result.getDate() + days); | |
return result; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment