HarborCRM Reconciliation And Prospecting SOP
Use this skill for HarborCRM tasks that ask for JSON-only CRM handoffs, event reconciliations, trade-show prospect lists, or import-batch cleanup. Work from the staged prompt, its answer template, and the public HarborCRM API endpoints named or implied by the prompt. Do not add prose, extra fields, or alternative enum values to the final JSON.
Source Habits
- Read the answer template first and mirror its top-level keys, item keys, enum spelling, nullability, and ordering rules exactly.
- Fetch all relevant public records before deciding: event or show metadata, sponsor orders/packages, badges, invoices, CRM accounts, CRM contacts, opportunities, campaign members, import raw rows, suppression lists, meeting-interest records, and policies.
- Join records by the strongest key available:
account_id,contact_id,event_id,show_id,crm_account_id, normalized email, normalized phone, then company/contact name only when IDs are absent. - Use policy enums as controlled values. For platform coverage, use only
AUV,ROV, andUnderwater Camerain that order. - Treat money as integer USD and dates as
YYYY-MM-DD. Follow-up dates are event end date plus the event's configured follow-up day count.
Output Conventions
- Return one JSON object only. Keep field names exactly as declared in the template.
- Use
nullfor missing IDs when the template permits nulls. Use empty strings for missing normalized email or phone when the template says empty strings are allowed. - Normalize email with trim plus lowercase. Normalize phone by stripping non-digits; do not invent a country code that was not present.
- For existing CRM matches, preserve the existing
account_idorcontact_id. For new accounts, usenullaccount/contact IDs unless the template says otherwise. - Count summaries from the final included records, not from raw source rows, unless the field explicitly asks for removed or excluded records.
Sorting Rules
- Always apply the template's explicit sort order.
- Common defaults: sponsors by
account_name; qualified lead accounts byaccount_name; exhibitors and exclusions bycompany_name; badge decisions bybadge_id; removed import rows byrow_id; duplicate keys bykey. - Sort platform lists as
AUV, thenROV, thenUnderwater Camera. - For ranked prospect lists, follow the prompt's ranking chain exactly. When used, a common rank chain is demo request first, then interest score descending, then broader platform coverage, then company name.
Sponsor And Event Handoff
- Sponsor status comes from sponsor order/package plus invoice state:
- Confirmed order with paid/deferred invoice:
paid_deferred. - Confirmed order with an open invoice:
open_invoice; open balance is invoice amount minus paid amount. - Proposal-sent sponsor package without an invoice:
proposal_only. - Canceled or inactive sponsor records are excluded or marked with the template's inactive/canceled reason, not treated as active sponsors.
- Confirmed order with paid/deferred invoice:
- Sponsor revenue/status totals should use package or invoice amounts as integer USD, with open invoice balance reported separately when requested.
- Sponsor finance follow-up usually includes both
open_invoiceandproposal_onlyaccounts. It excludespaid_deferredaccounts. - Sponsor attendees are not non-sponsor leads even when their badge type says attendee. A badge tied to an active sponsor account should be classified or excluded as sponsor-related according to the template.
- Non-business badge types such as student or press are excluded as
non_business_badge. - Existing CRM accounts with a disqualified status or disqualified reason should not be imported as qualified leads.
Qualified Leads And CRM Actions
- Qualified event leads are business, non-sponsor, non-disqualified badge records with usable contact facts. Phone-only contacts can qualify when the template permits an empty email.
- Use the event's lead opportunity amount for each qualified non-sponsor event account when the prompt asks for event lead pipeline.
- CRM account actions:
create_accountwhen no CRM account exists.update_existingwhen the CRM account already exists and is not disqualified.
- CRM contact actions:
create_contactwhen the account exists but the specific contact does not.update_existingonly for a matching existing contact.
- Campaign-member actions:
- Create or add when the lead/contact is not already a campaign member.
- Update when an existing campaign member has the wrong target status.
no_actionwhen the existing member already has the target status.no_importfor excluded subjects.
- Use target statuses from the template, commonly
attended,attended_sponsor,registered_sponsor, orexcluded.
Trade-Show Prospecting
- Qualify companies that manufacture or OEM-build covered platforms: AUVs, ROVs, underwater cameras, or qualifying multi-platform robotics/camera systems.
- Exclude adjacent companies that do not build covered platforms:
- Distributor/reseller only:
distributor_only. - Service, consulting, operator, analytics-only, or no-hardware firms:
service_only. - Sensor-only vendors:
sensor_vendor_onlyor the exact sensor enum in the template. - Research-only organizations:
research_only. - Out-of-market companies:
not_target_market.
- Distributor/reseller only:
- Existing CRM exhibitor accounts are
update_existing; exhibitors without CRM accounts arecreate_account. - Meeting-interest data can drive priority tiers when no separate tier field exists. When the prompt gives thresholds, apply them literally, such as demo plus score at least 90 for
A, demo plus score at least 80 forB, and all other qualified leads asC. - Opportunity estimates come from the prompt's tier mapping. Sum only qualified ranked leads.
- Platform coverage counts count every platform assigned to each qualified company, so a multi-platform company increments multiple platform counters.
Import Batch Cleanup
- Normalize raw rows before matching: lowercase trimmed email, digits-only phone, and trimmed names/company names.
- Apply suppression and unusable-contact rules before import, but keep removed rows out of
clean_contactsunless the template explicitly says to include non-importable rows there. clean_contactsshould contain surviving importable winners only. Removed duplicate, suppressed, and missing-contact rows belong in removal summaries.- For duplicate groups, choose the best winner by latest
captured_at; when tied, use the source priority implied by the template/source enum order. Use the winner row ID for bothclean_contact_idandsource_row_id. - Duplicate summaries should name the duplicate key consistently, identify the winner row, and list removed row IDs sorted.
duplicate_removed_countcounts duplicate losers.suppressed_removed_countcounts suppression removals.unusable_removed_countcounts missing/unusable contact removals.- Import action totals and campaign-member import count should be based on surviving importable clean contacts, not removed rows.
Pitfalls
- Do not turn proposal-only sponsors into ordinary leads or canceled sponsors into active sponsors.
- Do not count excluded badges, disqualified accounts, or removed import rows in lead pipeline totals.
- Do not add unsupported enum values such as informal exclusion labels or custom CRM actions.
- Do not sort by discovery order when the template gives a field order.
- Do not infer platform coverage from generic interest alone; use exhibitor descriptions and the prospecting policy.
- Do not include API diagnostics, reasoning, feedback, or explanatory text in the final JSON response.