Ansprechpartner finden
Suchen Sie über die API Personen bei einem Unternehmen, das Ihre Website besucht hat, und schalten Sie die E-Mail frei.
Ein Skript nimmt ein Unternehmen aus Ihren letzten Besuchen und sucht dort die passende Person. Am Ende haben Sie:
- ein Skript, das die Personen eines besuchenden Unternehmens kostenlos auflistet und eine davon auswählt
- die freigeschaltete E-Mail-Adresse dieser Person und ihr LinkedIn-Profil, wenn eines vorliegt, gespeichert mit
company_idundcontact_id - eine Behandlung für zu wenige Credits und die Sicherheit, dass ein zweiter Lauf dieselben Daten nicht noch einmal abbucht
Bevor Sie beginnen
- Dauer: Die Einrichtung dauert etwa 15 Minuten und ein Freischalten wenige Sekunden.
- Konto: Die Ansprechpartner sind in Ihrem Konto einmal im Dashboard eingerichtet, wie unter Ansprechpartner einrichten beschrieben. Sonst antworten Suche und Freischalten mit
403undCONTACTS_SETUP_REQUIRED. - Zugang: Sie brauchen den API-Schlüssel für Visitor Intelligence, den Sie auch für die Besuche nutzen, und Python 3 mit
requests. Der Schnellstart beschreibt, wie Sie den Schlüssel kopieren. - Rechte: Nur Admins sehen den Schlüssel unter Menü > Integrationen > API. Jeder Benutzer kann die Ansprechpartner einrichten.
- Plan: Die API ist in jedem Plan verfügbar, auch im Free-Plan und in der Testphase. Im Free-Plan gilt das nur für Unternehmen, die Sie sehen.
- Credits: Die Suche ist kostenlos, aber das Freischalten kostet Credits und lässt sich nicht rückgängig machen. Sie kaufen Credits im Dashboard, nicht über die API. Mehr dazu unter Credits.
Wenn ein Partner Ihr Konto betreut, muss er die Funktion Datenprofile freigeben. Sonst antwortet die API mit 403 und FEATURE_DISABLED.
Unternehmen auswählen
Sie suchen Ansprechpartner nur bei Unternehmen, die eine Ihrer Websites besucht haben. GET /intensive-visits und GET /company-sessions liefern zum Beispiel die company_id. /intensive-visits enthält nur Besuche von mindestens 30 Sekunden.
Ein Webhook trägt die company_id in data.company.company_id.
Für jede andere company_id antwortet die API mit 403 und COMPANY_NOT_IDENTIFIED. Die API sucht nicht nach Domain, Name oder Person.
Überspringen Sie im Free-Plan Zeilen mit "blurred": true. Für diese verborgenen Unternehmen antwortet die Suche mit 403 und PLAN_REQUIRED. Mehr dazu unter Testphase und Free-Plan.
Die Besuchs-Endpunkte wie /intensive-visits beantworten eine Anfrage pro Sekunde je Endpunkt. Anfragelimits beschreibt die Details.
Credits prüfen
GET /contacts/credits zeigt kostenlos, wie viele Credits Ihr Konto hat. balance ist die Zahl Ihrer Credits und costs.email die Kosten für das Freischalten einer E-Mail.
Lesen Sie die Kosten aus costs, statt sie fest in Ihren Code zu schreiben. Ein Beispiel und alle Felder finden Sie unter Credits in der API.
Brechen Sie bei zu wenigen Credits nicht hart ab, denn die API liefert Daten, die Ihr Konto schon freigeschaltet hat, auch dann ohne Kosten.
Ansprechpartner suchen
POST /contacts/search listet die Personen eines Unternehmens und ist kostenlos. Dieses Beispiel sucht im Marketing ab Bereichsleitung, also auf den Ebenen 6 bis 10:
curl -X POST "https://hub.webmetic.de/contacts/search" \
-H "Authorization: wmtc_IHR_API_SCHLUESSEL" \
-H "Content-Type: application/json" \
-d '{"company_id": "41ea486a9c95", "filters": {"departments": ["Marketing"], "seniority": [10, 9, 8, 7, 6]}}'Das Objekt filters kennt diese Filter:
departments: Abteilungen als Liste von Texten. Webmetic verbindet mehrere Abteilungen mit „oder".seniority: Ebenen als Zahlen, 10 Gründer, 9 C-Level, 8 VP, 7 Partner, 6 Director, 5 Manager, 4 Senior, 3 Einsteiger. Abteilung und Ebene müssen beide passen.require_emailundrequire_phone: nur Personen, zu denen eine E-Mail-Adresse oder Rufnummer vorliegt.
Nutzen Sie in departments nur die Werte, die auch das Dashboard sendet:
| Abteilung im Dashboard | Wert in departments |
|---|---|
| Geschäftsführer | General Management |
| Marketing | Marketing |
| Vertrieb (Sales) | Sales |
| Business Development | Business Development |
| Personal (HR) | Human Resources |
| Technik & Produkt | Engineering & Technical, Information Technology, Product |
| Finanzen & Recht | Finance, Legal |
Die Mindestebene im Dashboard entspricht diesen Ebenen: ab Manager 4 bis 10, ab Bereichsleitung 6 bis 10, nur Geschäftsführung 9 und 10.
Wenn ein Filter fehlt oder leer ist, nutzt Webmetic die Werte aus Ihrem Ansprechpartner-Profil.
Eine Seite enthält höchstens so viele Personen, wie Sie in size angeben: 10 bis 25, ohne Angabe 25 Personen. Die Seiten zählen mit page ab 0, und total nennt alle passenden Personen.
Ansprechperson auswählen
Wählen Sie die Person in Ihrem Code aus, zum Beispiel nach job_title. has_email und has_phone zeigen, welche Daten vorliegen.
Die Antwort enthält keine Abteilung, keine Ebene und keinen Standort. email, linkedin, direct_phone und mobile_phone sind in der Suche immer null, auch für Personen, die Ihr Konto schon freigeschaltet hat.
Merken Sie sich die contact_id aus der Suche und behandeln Sie sie als Text ohne festes Format.
E-Mail freischalten
POST /contacts/reveal schaltet die Daten einer Person frei und kostet Credits. Mit reveal_email erhalten Sie die E-Mail-Adresse und das LinkedIn-Profil und mit reveal_phone die Rufnummern in direct_phone und mobile_phone.
curl -X POST "https://hub.webmetic.de/contacts/reveal" \
-H "Authorization: wmtc_IHR_API_SCHLUESSEL" \
-H "Content-Type: application/json" \
-d '{"contact_id": "v1.q7Rk2mXv9TnL4w", "reveal_email": true}'{
"contact": {
"contact_id": "v1.q7Rk2mXv9TnL4w",
"email": "m.eckhardt@bergquell.example",
"linkedin": "https://www.linkedin.com/in/miriam-eckhardt-example",
"direct_phone": null,
"mobile_phone": null
},
"from_cache": false
}Die Antwort enthält alles, was Ihr Konto zu dieser Person freigeschaltet hat. Was nicht freigeschaltet ist, bleibt null. Im Beispiel fehlen credits_used und credits_remaining, aber die echte Antwort enthält sie.
Wenn Webmetic keine Adresse findet, bleibt email null, und Webmetic bucht dafür nichts ab. Weil ein neuer Versuch wieder genug Credits braucht, wiederholen Sie ihn nicht in einer Schleife.
Für manche Personen darf Webmetic keine Kontaktdaten herausgeben. Dann antwortet die API mit 404 und CONTACT_NOT_FOUND und bucht nichts ab.
Die API antwortet genauso, wenn die contact_id nicht aus einer Suche Ihres Kontos stammt. Suchen Sie dann erneut und nutzen Sie die neue contact_id.
Zu wenige Credits behandeln
Wenn Ihre Credits nicht reichen, antwortet die API mit 402 und INSUFFICIENT_CREDITS. Webmetic prüft das vor dem Abruf und bucht nichts ab.
Die API kann deshalb auch dann mit 402 antworten, wenn Webmetic keine Daten gefunden hätte.
detail.required nennt die Credits, die die Aktion braucht, und detail.available nennt die Credits Ihres Kontos. Kaufen Sie im Dashboard Credits nach und wiederholen Sie dann den Aufruf.
Bei 409 und CONCURRENT_UPDATE wiederholen Sie den Aufruf nach kurzer Zeit und bei 502 und PROVIDER_UNAVAILABLE nach einigen Minuten. Alle Codes finden Sie unter Fehler.
Doppelte Abbuchungen vermeiden
Webmetic bucht dieselben Daten für Ihr Konto nur einmal ab:
- Erneut freischalten: Ein zweiter Aufruf für dieselbe Person und Datenart kostet nichts und liefert
from_cache: true. Das gilt für alle Benutzer und Schlüssel Ihres Kontos. - Neue Datenart: Wenn Sie zur E-Mail später das Telefon anfragen, zahlen Sie nur das Telefon.
- Gleichzeitige Aufrufe: Webmetic bucht doppelte Anfragen einmal ab.
- E-Mail und Telefon zusammen: Wenn Sie beides in einem Aufruf anfragen, bucht Webmetic die gelieferten Daten in einem Schritt ab oder gar nicht.
Wenn Sie keinen zweiten Aufruf senden wollen, speichern Sie die contact_id und überspringen Sie bekannte Personen beim nächsten Lauf.
Ergebnis speichern
Speichern Sie company_id, contact_id, Name, E-Mail-Adresse und LinkedIn-Profil, denn die Suche zeigt freigeschaltete Daten nie an.
Sie lesen die Daten kostenlos wieder mit GET /contacts/lookup und denselben Filtern oder mit einem erneuten Freischalten.
Freigeschaltete Daten gehören Ihrem ganzen Konto, also jedem Benutzer, jedem Schlüssel und dem KI-Assistenten.
Im Profil des Unternehmens im Dashboard erscheint die Person mit ihren Daten aber nur, wenn Ihre Suche dieselben Filter wie das Ansprechpartner-Profil genutzt hat. Lassen Sie dafür filters am besten weg.
Vollständiges Skript
Das Skript verbindet alle Schritte. Ersetzen Sie Schlüssel und Website durch Ihre Werte.
Das Skript wählt unter den Besuchen von mindestens 30 Sekunden aus den letzten sieben Tagen das Unternehmen mit dem höchsten Wert in relevance_score. Dann sucht es im Marketing ab Bereichsleitung nach Personen mit E-Mail-Adresse und hängt das Ergebnis an contacts.jsonl an.
import json
import sys
import requests
API = "https://hub.webmetic.de"
HEADERS = {"Authorization": "wmtc_IHR_API_SCHLUESSEL"}
WEBSITE = "ihre-website.de"
def fail(res):
try:
detail = res.json().get("detail")
except ValueError:
detail = res.text[:200]
# Paths outside the API answer {"detail": "Not Found"}
if not isinstance(detail, dict):
detail = {"error": f"HTTP_{res.status_code}", "message": str(detail)}
sys.exit(f"{res.status_code} {detail['error']}: {detail['message']}")
# 1. Companies with a visit of 30 seconds or more in the last 7 days
res = requests.get(
f"{API}/intensive-visits",
headers=HEADERS,
params={"domain": WEBSITE, "from_date": "-7 days"},
)
if not res.ok:
fail(res)
companies = [c for c in res.json()["result"] if not c.get("blurred")]
if not companies:
sys.exit("No company with an intensive visit")
company = max(companies, key=lambda c: c.get("relevance_score") or 0)
# 2. Check credits (free), warn only: a repeat unlock costs nothing
credits = requests.get(f"{API}/contacts/credits", headers=HEADERS).json()
if credits["balance"] < credits["costs"]["email"]:
print("Not enough credits, the API may answer 402")
# 3. Search contacts (free): marketing, division lead and above, with email
res = requests.post(
f"{API}/contacts/search",
headers=HEADERS,
json={
"company_id": company["company_id"],
"filters": {
"departments": ["Marketing"],
"seniority": [10, 9, 8, 7, 6],
"require_email": True,
},
},
)
if not res.ok:
fail(res)
people = [p for p in res.json()["contacts"] if p["has_email"]]
if not people:
sys.exit(f"No contact found at {company['company_name']}")
person = people[0]
# 4. Unlock the email (costs credits, a repeat costs nothing)
res = requests.post(
f"{API}/contacts/reveal",
headers=HEADERS,
json={"contact_id": person["contact_id"], "reveal_email": True},
)
if res.status_code == 402:
detail = res.json()["detail"]
sys.exit(f"Not enough credits: {detail['required']} needed, {detail['available']} available")
if not res.ok:
fail(res)
unlocked = res.json()
# 5. Store the result
record = {
"company_id": company["company_id"],
"company_name": company["company_name"],
"contact_id": person["contact_id"],
"name": person["name"],
"job_title": person["job_title"],
"email": unlocked["contact"]["email"],
"linkedin": unlocked["contact"]["linkedin"],
}
with open("contacts.jsonl", "a", encoding="utf-8") as f:
f.write(json.dumps(record, ensure_ascii=False) + "\n")
print(record)Weil das Skript require_email setzt, erscheint die Person nicht in der Liste im Dashboard. Wenn das Skript erneut läuft, wählt es bei gleichen Besuchen dieselbe Person, und das Freischalten kostet nichts.
Suchen und freischalten in einem Aufruf
POST /contacts/find sucht und schaltet in einem Aufruf frei und kostet Credits. reveal wählt email, phone oder both. Ohne Angabe gilt email.
curl -X POST "https://hub.webmetic.de/contacts/find" \
-H "Authorization: wmtc_IHR_API_SCHLUESSEL" \
-H "Content-Type: application/json" \
-d '{"company_id": "41ea486a9c95", "filters": {"departments": ["Marketing"]}, "reveal": "email"}'Webmetic nimmt aus den ersten 25 Treffern die erste Person, zu der alle angefragten Daten vorliegen. Wenn es keine solche Person gibt, nimmt Webmetic die erste Person mit einem Teil davon.
Die Antwort ist flach, mit found und den Feldern der Person.
Wenn niemand passt, antwortet die API mit found: false, und Webmetic bucht nichts ab. Derselbe Aufruf wählt wieder dieselbe Person und kostet dann nichts.
Mit find können Sie keine zweite oder dritte Person wählen. Dafür nutzen Sie Suche und Freischalten wie oben.