-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Context
You are updating a Node.js application that formats MyCarrierPackets webhook events into rich Slack messages. The carrier.packet.completed webhook payload has been significantly expanded with additional data fields that should be displayed in the Slack notification.
Current Implementation
The current Slack message for carrier.packet.completed displays:
- Carrier information (Legal Name, DBA, DOT Number, MC Number)
- Packet details (Packet Type, Completion Date)
- Customer information (Company Name, Customer ID)
- A "View in MCP" button
Expanded Webhook Payload
The webhook now includes much richer data:
{
"eventType": "carrier.packet.completed",
"eventDateTime": "2025-04-29T22:16:41.5102923Z",
"eventData": {
"agreement": {
"signatureDate": "2025-04-29T22:16:20.6352903",
"signaturePerson": "MCP Test Carrier",
"signaturePersonTitle": "President",
"signaturePersonEmail": "[email protected]",
"signaturePersonPhoneNumber": "9999999999",
"agreementImageBlobName": "company-agreement/6/b7453f55-3f3b-454d-8726-89f746082a06",
"ipAddress": {
"address": "127.0.0.1",
"city": "New York City",
"region": "New York",
"country": "United States of America"
},
"geolocation": {
"latitude": 34.0544,
"longitude": -118.244,
"error": null,
"method": "IPAddress"
}
},
"carrier": {
"dotNumber": 9999997,
"docketNumber": "MC9999997",
"legalName": "MCP TEST CARRIER 9999997",
"dbaName": null
},
"customer": {
"customerID": 6,
"companyName": "MCP Test Customer"
}
}
}New Fields Available:
-
Agreement Information:
agreement.signatureDate- When the agreement was signedagreement.signaturePerson- Name of the person who signedagreement.signaturePersonTitle- Their title/roleagreement.signaturePersonEmail- Their emailagreement.signaturePersonPhoneNumber- Their phone numberagreement.agreementImageBlobName- Reference to the signed agreement image
-
IP Address Information:
agreement.ipAddress.address- IP address usedagreement.ipAddress.city- City derived from IPagreement.ipAddress.region- State/Provinceagreement.ipAddress.country- Country
-
Geolocation Data:
agreement.geolocation.latitude- Latitude coordinateagreement.geolocation.longitude- Longitude coordinateagreement.geolocation.method- How location was determined (enum: "DeviceOrBrowser" or "IPAddress")agreement.geolocation.error- Any error in obtaining geolocation
Task
Update the formatPacketCompletedMessage function in utils/formatters.js to include these new fields in the Slack message blocks. The enhanced message should:
Requirements:
- Maintain Existing Structure - Keep the current header, carrier section, and customer section
- Add Agreement Signer Section - Display who signed the packet and their contact info
- Add Location Information - Show where the packet was signed from (city, region, country)
- Format for Readability - Use appropriate Slack Block Kit elements
- Handle Missing Data - Gracefully handle cases where optional fields might be null/undefined
- Preserve Existing Functionality - Keep the "View in MCP" button and color coding
Design Guidelines:
- Use
sectionblocks withfieldsarrays for structured data - Use
contextblocks for supplementary information (like geolocation method) - Format phone numbers for readability:
(999) 999-9999 - Format dates consistently: use
new Date().toLocaleString()format - Use markdown formatting (
*bold*) for field labels - Group related information logically
- Consider adding a Google Maps link for the geolocation coordinates (optional)
Suggested Section Order:
- Header (existing)
- Divider (existing)
- Carrier Information (existing)
- Packet Details (existing)
- NEW: Agreement Signer Details
- NEW: Signature Location
- Customer Information (existing)
- Context/Timestamp (existing)
- Action Buttons (existing)
Example of New Sections to Add:
// Agreement Signer Section
const signerSection = {
type: "section",
fields: [
{
type: "mrkdwn",
text: `*Signed By:* ${eventData.agreement?.signaturePerson || 'N/A'}`
},
{
type: "mrkdwn",
text: `*Title:* ${eventData.agreement?.signaturePersonTitle || 'N/A'}`
},
{
type: "mrkdwn",
text: `*Email:* ${eventData.agreement?.signaturePersonEmail || 'N/A'}`
},
{
type: "mrkdwn",
text: `*Phone:* ${formatPhoneNumber(eventData.agreement?.signaturePersonPhoneNumber) || 'N/A'}`
}
]
};
// Location Section
const locationSection = {
type: "section",
fields: [
{
type: "mrkdwn",
text: `*Location:* ${eventData.agreement?.ipAddress?.city || ''}, ${eventData.agreement?.ipAddress?.region || ''}, ${eventData.agreement?.ipAddress?.country || 'N/A'}`
},
{
type: "mrkdwn",
text: `*IP Address:* ${eventData.agreement?.ipAddress?.address || 'N/A'}`
}
]
};
// Geolocation Context (if available)
const geolocationContext = eventData.agreement?.geolocation ? {
type: "context",
elements: [
{
type: "mrkdwn",
text: `📍 Coordinates: ${eventData.agreement.geolocation.latitude}, ${eventData.agreement.geolocation.longitude} (via ${eventData.agreement.geolocation.method})`
}
]
} : null;Additional Considerations:
- Add a helper function
formatPhoneNumber(phone)to format phone numbers - Consider whether to show the
agreementImageBlobName(probably not needed in Slack) - Handle the case where the entire
agreementobject might be missing (backward compatibility) - Test with both complete and partial payloads
- Ensure the message doesn't become too cluttered
Expected Output
Provide the complete updated formatPacketCompletedMessage function with:
- All new sections integrated
- Proper null/undefined checking
- Helper functions if needed (like
formatPhoneNumber) - Comments explaining the new sections
- The complete blocks array with all sections in the proper order
Code Location
File: utils/formatters.js
Function: formatPacketCompletedMessage(eventType, formattedDate, eventData, carrierSection, customerSection, contextSection)
Backward Compatibility Note
Some webhooks may still arrive with the old payload structure (without the agreement object). Ensure the code handles both cases gracefully without breaking.