HackathonRadar
Get an API key
APIInbound enrichment and suppression

API

Inbound enrichment and suppression

Send an inbound sponsorship lead, get it matched to a hackathon and organizer with a confidence score, and manage do-not-contact rules

Inbound enrichment takes a lead from your form, CRM or inbox, in whatever JSON shape you have, and tells you which hackathon and organizer it is about, how good that event looks, and whether you should contact them. Suppression rules are your account's do-not-contact list, checked on every submission. Both need an API key. See Authentication and keys.

Submit a lead

POST /api/v1/inbound/submit takes any JSON object, stores it as a submission on your account, and returns the match result with status 201.

Request
curl -X POST https://www.hackathonradar.com/api/v1/inbound/submit \
  -H "Authorization: Bearer $HACKATHONRADAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "lead_id": "crm-000123",
    "notes": "Sponsorship request from the website form",
    "mapped": {
      "event_url": "https://treelinehacks.example.com",
      "event_title": "TreeLine Hacks",
      "event_start_month": "2026-03",
      "event_country": "United States",
      "organizer_email": "team@treelinehacks.example.com",
      "organizer_name": "Treeline Hacks"
    }
  }'

mapped is optional. When you send it, only its seven fields are used for matching: event_url, event_title, event_start_month (YYYY-MM or any date), event_country (a country or a city), organizer_email, organizer_name and organizer_linkedin. Everything else in the body is stored untouched as raw_payload.

Without mapped, HackathonRadar reads common key names from the top level of the body. Key names are not case sensitive, and the underscore is optional, so eventLink and event_link both work.

FieldRecognized keys
Event URLurl, event_url, website, link, event_link
Event titletitle, event_title, name, event_name, hackathon
Start monthstart_month, event_start_month, month, start_date, date
Countrycountry, event_country, location, region
Organizer emailemail, organizer_email, contact_email
Organizer nameorganizer_name, organizer, contact_name, name
Organizer LinkedInlinkedin, organizer_linkedin, linkedin_url

A bare name key fills both the event title and the organizer name. Send mapped when your keys are ambiguous.

Read the response

201 response
{
  "submission_id": "76950fb0-2657-4e2d-9ebd-8003c4d34d70",
  "match": {
    "confidence": 0.95,
    "explanation": [
      "Event matched via url_exact (confidence: 0.95)",
      "Organizer matched via email_exact (confidence: 0.95)"
    ],
    "event_id": "6fa487e4-c891-456f-81f1-2a4bedc12967",
    "organizer_id": "76ee2e74-a0b0-4f19-85d9-30f9d2c3f181",
    "event_match_method": "url_exact",
    "organizer_match_method": "email_exact",
    "organizer_inferred_from_event": false
  },
  "event": {
    "title": "TreeLine Hacks",
    "start_at": "2026-03-06T16:45:00.000Z",
    "country": null,
    "city": null,
    "format": "online",
    "quality_score": 55,
    "quality_breakdown": {}
  },
  "organizer": {
    "name": "Treeline Hacks",
    "email": "team@treelinehacks.example.com",
    "num_events_seen": 3,
    "domain_events_seen": 3,
    "first_seen_at": "2025-01-10T12:00:00.000Z",
    "last_seen_at": "2026-03-06T16:45:00.000Z"
  },
  "suppression": { "is_duplicate_inbound": false, "is_suppressed": false, "reasons": [] }
}
FieldWhat it tells you
match.confidenceHow sure the match is, from 0 to 1
match.explanationEach matching step in plain text, ready to show to a sales rep
match.event_id, match.organizer_idThe matched hackathon and organizer, or null. Fetch them in full from the hackathon and organizer endpoints
match.organizer_inferred_from_eventtrue when the organizer was taken from the matched event rather than from the lead
eventThe matched hackathon's basics and its quality score, or null
organizerThe matched organizer, or null. num_events_seen counts their events and domain_events_seen counts events across every organizer on the same domain. first_seen_at is when HackathonRadar first recorded them and last_seen_at is the start of their latest event
suppressionWhether the lead is a duplicate or matches one of your suppression rules, with the reasons

Match methods

event_match_method and organizer_match_method name what the match was based on, or are null when nothing matched.

ValueSideBased on
url_exactEventThe event's website or registration URL
source_urls_containmentEventOne of the event's listing URLs
source_id_exactEventThe event's listing ID, read from the URL
title_country_dateEventTitle, location and date
title_dateEventTitle and date
title_fuzzy_dateEventA similar title and the date
title_fuzzyEventA similar title
email_exactOrganizerEmail address
linkedin_exactOrganizerLinkedIn profile
name_fuzzyOrganizerA similar name
event_inferredOrganizerThe matched event's organizers

Duplicates and statuses

A lead is a duplicate when your account sent the same lead in the last 90 days. Duplicates are still matched and stored. Each stored submission has a status:

statusWhen
duplicateThe same lead was sent in the last 90 days. Takes precedence over the others
suppressedA suppression rule matched
matchedAn event matched
unmatchedNo event matched

Review stored submissions

  • GET /api/v1/inbound/submissions lists your submissions, newest first. Parameters: status, page (default 1) and limit (default 25, at most 100). The response holds data, page, limit, total, totalPages, hasNext and hasPrev.
  • GET /api/v1/inbound/submissions/{id} returns one stored submission with the raw payload, the fields read from it, the match result, the quality snapshot and any suppression reasons. An id from another account returns 404 Submission not found.
  • GET /api/v1/inbound/submissions/export returns all your submissions, or those with one status, as inbound-submissions.csv.

Suppression rules

POST /api/v1/suppression/add creates a rule and returns it with status 201. Sending the same suppression_type and value again updates its reason and expires_at.

Request
curl -X POST https://www.hackathonradar.com/api/v1/suppression/add \
  -H "Authorization: Bearer $HACKATHONRADAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"suppression_type": "domain", "value": "gmail.com", "reason": "Skip personal inboxes", "expires_at": null}'
suppression_typeMatches
emailThe lead's organizer email
domainThe domain of the lead's organizer email
event_urlThe lead's event URL

Submissions are compared in a cleaned-up form: emails in lowercase, and event URLs with https, a lowercase host, no trailing slash or fragment, and tracking parameters such as utm_* removed. Store rule values in that form. A rule stops applying once its expires_at has passed. To lift a rule, add it again with an expires_at in the past.

POST /api/v1/suppression/check runs the same check without storing anything. Send organizer_email and event_url. The check compares values exactly as you send them, so lowercase emails and clean URLs first.

200 response
{ "is_suppressed": true, "reasons": ["Suppressed: domain \"gmail.com\""] }

Each reason names the rule, followed by your reason text when the rule has one.