HarborCRM Task Solving Skill
Overview
This skill describes the workflow for solving HarborCRM data-reconciliation and CRM-import tasks. Each task requires querying a shared HarborCRM REST API, applying business rules from the prompt and from policy metadata, and producing a single JSON object that matches a strict answer template.
API Base URL
- Use the base URL supplied by the task runner (e.g.
http://34.46.77.124:8001). - Do not start a local environment or read env source files.
- Only query endpoints and entity IDs explicitly named in the task prompt.
General Workflow
- Read the prompt – identify the event / batch / show ID and the required output schema.
- Fetch all relevant data from the named API endpoints. Common endpoints include:
/api/events/{event_id}/api/events/{event_id}/orders/api/events/{event_id}/badges/api/events/{event_id}/sponsor_packages/api/finance/invoices?event_id={event_id}/api/crm/accounts/api/crm/contacts/api/crm/opportunities/api/crm/campaign_members?event_id={event_id}/api/tradeshows/{show_id}/exhibitors/api/tradeshows/{show_id}/meeting_interest/api/import_batches/{batch_id}/raw_contacts/api/import_batches/{batch_id}/suppression/api/policies
- Apply business rules (see sections below).
- Produce JSON matching the answer template exactly. No extra keys, no prose outside the JSON.
- Respect sorting rules explicitly stated in each template.
Sponsor Reconciliation Rules
- Use
sponsor_packages(ororders) as the authoritative list of sponsor accounts. - Map each sponsor to a status using finance invoices:
paid_deferred– invoice status ispaid_deferred.open_invoice– invoice status isopen(unpaid or partially paid).proposal_only– order status isproposal_sentand there is no invoice.
- Exclude inactive/canceled sponsor records from the sponsor status list.
- For open invoices, compute
open_balance = amount - paid_amount. - Revenue totals are integer USD.
open_invoice_balanceis the sum of open balances. - Unpaid sponsors (open invoice or proposal only) are finance follow-up targets.
Lead Qualification Rules (Event Handoff)
- Qualified leads are non-sponsor attendees with business badges.
- Exclude:
- Sponsor contacts (any badge from a sponsoring company).
- Non-business badges (
student,press, etc.). - Contacts whose CRM account status is
disqualified.
- Use the event's
lead_opportunity_amountfor each qualified lead account. - If a company already exists in CRM, mark
crm_account_action: update_existing; otherwisecreate_account. - If the contact already exists in CRM, mark
crm_contact_action: update_existing; otherwisecreate_contact. - Campaign member action is
add_campaign_memberfor qualified leads.
Contact Hygiene
- Normalize email: lowercase, trim whitespace. Empty string if missing / blank.
- Normalize phone: digits only (strip
+,-,(,), spaces, dots). Empty string if missing / blank. - For US/Canada numbers that start with
1after stripping+, keep the leading1(e.g.+1 415 555 0101→14155550101).
Import Batch Cleaning (Duplicate / Suppression / Missing)
- Duplicates: group raw contacts by normalized email. Keep the earliest
captured_atrow as winner; remove the rest with reasonduplicate. - Suppression: remove any row whose normalized email or normalized phone appears in the suppression list. Reason:
suppressed. - Missing contact: remove rows with blank normalized email AND blank normalized phone. Reason:
missing_contact. crm_actionfor surviving cleaned contacts:update_existingif the company name matches an existing CRM account.create_accountotherwise.no_importorsuppressfor removed rows (counted inimport_action_totals).
campaign_member_import_count= number of surviving cleaned contacts.
Trade-Show Prospecting Rules
- Read exhibitor descriptions and the
prospectingpolicy to decide qualification. - Qualified exhibitors build or OEM-build target platforms (AUV, ROV, Underwater Camera).
- Exclude:
- Distributors →
distributor_only - Service-only providers →
service_only - Sensor-only vendors (no platform manufacturing) →
sensor_only - Research-only organizations →
research_only
- Distributors →
- Map each qualified exhibitor to applicable
platformsenums, ordered:AUV,ROV,Underwater Camera. - Priority tier rules (from prompt):
Afor demo-requested qualified leads with score ≥ 90 (opportunity USD 120000).Bfor demo-requested qualified leads with score ≥ 80 (opportunity USD 90000).Cfor all other qualified leads (opportunity USD 50000).
- Rank qualified leads by: demo request first, then interest score descending, then broader platform coverage, then company name ascending.
- Existing CRM accounts get
crm_action: update_existing; new ones getcreate_account.
Campaign Member Actions
- For existing campaign members at the event, decide
action:updateif current status isregistered_sponsorand the attendee actually attended.no_actionif alreadyattended_sponsorand no change needed.createfor new qualified non-sponsor leads.
target_statusvalues:attended_sponsor,registered_sponsor,attended,excluded.
Sorting Rules (Critical)
sponsor_statuses→ byaccount_nameascending.qualified_lead_accounts→ byaccount_nameascending.excluded_records→ bycompany_nameascending, thencontact_nameascending.qualified_exhibitors→ bycompany_nameascending.excluded_near_misses→ bycompany_nameascending.ranked_leads→ byrankascending (1-based contiguous).clean_contacts→ byclean_contact_idascending.duplicate_keys→ bykeyascending.removed_rows→ byrow_idascending.badge_decisions→ bybadge_idascending.campaign_member_actions→ bysubject_keyascending.badge_only_contacts→ bycompany_nameascending.existing_crm_overlap_account_ids→ CRM account IDs ascending.
Due-Date Calculation
lead_due_date= eventend_date+followup_days_after_enddays.sponsor_finance_due_date= eventend_date+sponsor_followup_days_after_enddays.- Use calendar date arithmetic (simple date addition).
Common Pitfalls
- Do not include canceled/inactive sponsors in sponsor statuses.
- Do not include sponsor attendees in qualified leads.
- Do not include press, student, or other non-business badges in leads.
- Normalize emails and phones consistently before deduplication or suppression checks.
- Use the exact enum values from the template; do not invent new ones.
- Compute open balance for open invoices as
amount - paid_amount, notdeferred_amount. - Count all removed rows (duplicate + suppressed + missing) in
removal_summary.removed_rows, but the summary also needs separateunusable_removed_countandsuppressed_removed_counttallies. - Do not add extra top-level keys or omit required keys.
- Opportunity totals for non-sponsor leads = number of qualified leads × event
lead_opportunity_amount. - For import batches,
import_action_totalsmust include counts for all four actions (create_account,update_existing,no_import,suppress), even if some are zero.
Output Convention
- Return only the JSON object. No markdown fences, no explanatory text.
- All monetary values are integers (USD).
- All dates are
YYYY-MM-DD. - All timestamps are ISO-8601 strings from the source data.