DealFilter einbinden
Verbinde DealFilter mit Claude, Codex oder einem eigenen Skript - per MCP-Server, REST API oder CLI.
DealFilter API, MCP-Server und CLI
Verbinde DealFilter mit Claude, Codex oder einem eigenen Skript.
Voraussetzung: Premium- oder Ultra-Plan + API-Key (df_... - generierbar unter Einstellungen > API-Zugang).
| Plan | Abrufen, Auflisten, Kontingent | Einreichen | Phase ändern |
|---|---|---|---|
| Essential | - | - | - |
| Premium | ✓ | - | - |
| Ultra (in Planung) | ✓ | ✓ | ✓ |
Inhaltsverzeichnis
- Authentifizierung und Key-Verwaltung
- REST API v1
- MCP-Server
- OAuth-Connector und Token-Verwaltung
- CLI
- Fehler-Referenz
- Async-Vertrag: Einreichen und Polling
Authentifizierung
DealFilter kennt zwei Arten von Zugangstoken:
| Token | Prefix | Herkunft | Verwendung |
|---|---|---|---|
| Persönlicher API-Key | df_ | Manuell unter Einstellungen > API-Zugang erstellt | REST API, MCP-Server, CLI, eigene Skripte |
| OAuth-Connector-Token | dfo_ | Automatisch beim Verbinden eines MCP-Clients (z. B. Claude.ai) | MCP-Server über den Connector-Flow |
Beide werden ausschließlich gehasht gespeichert und im selben Authorization-Header verwendet.
API-Key generieren
Settings > API-Zugang (ab Premium sichtbar). Der Key wird einmalig im Klartext angezeigt.
Format: df_ + 43 Zeichen (Base64url).
Gültigkeitsdauer wählen
Beim Erstellen wählst du die Gültigkeit: 30 Tage, 90 Tage (Standard), 1 Jahr oder unbegrenzt.
Nach Ablauf wird der Key abgelehnt (401) - erstelle dann unter Einstellungen > API-Zugang einen neuen.
Auf der Seite siehst du Ablaufdatum und einen Hinweis, sobald ein Key abgelaufen ist.
Key erneuern oder widerrufen
- Erneuern: "Neu erstellen" erzeugt einen frischen Key und macht den alten sofort ungültig.
- Widerrufen: "Widerrufen" macht den Key sofort ungültig, ohne einen neuen zu erstellen.
Key in Requests mitgeben
Authorization: Bearer df_<key>
Gilt für REST API, MCP-Server und CLI.
REST API v1
Base URL: https://dealfilter.ai
Prefix: /api/v1
POST /api/v1/applications Ultra (in Planung) — Anfrage einreichen
Reicht eine neue Anfrage zur KI-Analyse ein. Verbraucht 1 Credit.
Die Analyse läuft asynchron - die Response enthält sofort status: "analyzing".
Request
POST /api/v1/applications
Authorization: Bearer df_<key>
Content-Type: application/json
{
"mailText": "Betreff: Senior Java Developer gesucht\n\nHallo,\n...",
"channel": "EMAIL",
"agentId": "cm1abc123",
"newAgentName": "SOLCOM GmbH"
}
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
mailText | string (min 10) | ja | Vollständiger Text der Anfrage |
channel | EMAIL|PORTAL|PHONE|SEARCH_AGENT | nein | Standard: EMAIL |
agentId | string | nein | ID eines bestehenden Recruiters |
newAgentName | string | nein | Name eines neuen Recruiters (alternativ zu agentId) |
Response 202
{
"applicationId": "cmq0go2ib000a1h9kn8dno71t",
"status": "analyzing"
}
Analyse-Status abrufen: GET /api/v1/applications/{applicationId} nach 30-60 Sekunden.
GET /api/v1/applications Premium Ultra (in Planung) — Anfragen auflisten
GET /api/v1/applications?active=true&limit=20&offset=0
Authorization: Bearer df_<key>
Query-Parameter
| Parameter | Typ | Default | Beschreibung |
|---|---|---|---|
phase | string | - | Exakter Phase-Filter (s. u.) |
active | true|false | - | true = nicht archiviert, false = nur ARCHIVED |
limit | int (1-100) | 50 | Anzahl Ergebnisse |
offset | int | 0 | Offset für Paginierung |
phase und active schliessen sich aus - phase hat Vorrang.
Phasen-Werte: INCOMING, APPLIED, PROFILE_AT_CLIENT, WON, CONTRACT_SIGNED, ARCHIVED
Response 200
{
"items": [
{
"id": "cmq0go2ib000a1h9kn8dno71t",
"status": "INCOMING",
"channel": "PORTAL",
"projectTitle": "Senior Software Engineer - Microservices",
"agentName": "SOLCOM",
"analysisStatus": "done",
"scoreLabel": "GREEN",
"scorePercent": 88,
"createdAt": "2026-06-05T05:05:47.699Z",
"lastContactAt": "2026-06-05T05:07:49.699Z"
}
],
"total": 32,
"limit": 20,
"offset": 0
}
GET /api/v1/applications/ Premium Ultra (in Planung) — Einzelne Anfrage abrufen
GET /api/v1/applications/cmq0go2ib000a1h9kn8dno71t
Authorization: Bearer df_<key>
Response 200
{
"id": "cmq0go2ib000a1h9kn8dno71t",
"status": "INCOMING",
"channel": "PORTAL",
"analysisStatus": "done",
"scoreLabel": "GREEN",
"scorePercent": 88,
"matchScore": {
"techFit": 90,
"rateFit": 85,
"locationFit": 80
},
"redFlags": ["Keine Remote-Option erwähnt"],
"hints": ["Java 17+", "Microservices", "Kubernetes"],
"aiSummary": "Solides Java-Projekt bei einem Endkunden im Finanzbereich...",
"createdAt": "2026-06-05T05:05:47.699Z",
"lastContactAt": "2026-06-05T05:07:49.699Z",
"originalMail": "Betreff: Senior Software Engineer...",
"project": {
"title": "Senior Software Engineer - Microservices",
"description": "...",
"location": "Frankfurt",
"remotePercentMin": 60,
"remotePercentMax": 80,
"durationMonthsMin": 6,
"durationMonthsMax": 12,
"startDate": "2026-07-01T00:00:00.000Z"
},
"agentName": "SOLCOM",
"communicationLog": [
{
"id": "cm2xyz456",
"date": "2026-06-06T10:00:00.000Z",
"type": "PHONE",
"direction": "INBOUND",
"contactSuccessful": true,
"note": "Telefonat mit Recruiter - Rate verhandelt"
}
]
}
analysisStatus-Werte:
| Wert | Bedeutung |
|---|---|
analyzing | Analyse läuft noch - später erneut abfragen |
done | Score, redFlags, hints und aiSummary verfügbar |
failed | Analyse endgültig fehlgeschlagen (max. Retries) |
PATCH /api/v1/applications/ Ultra (in Planung) — Phase ändern
Kein Credit-Verbrauch.
PATCH /api/v1/applications/cmq0go2ib000a1h9kn8dno71t
Authorization: Bearer df_<key>
Content-Type: application/json
{
"status": "APPLIED"
}
Response 200
{
"id": "cmq0go2ib000a1h9kn8dno71t",
"status": "APPLIED"
}
GET /api/v1/quota Premium Ultra (in Planung) — Kontingent abfragen
GET /api/v1/quota
Authorization: Bearer df_<key>
Response 200
{
"used": 44,
"limit": 500,
"remaining": 456,
"resetAt": "2026-07-01T00:00:00.000Z"
}
MCP-Server
Endpoint: POST https://dealfilter.ai/api/mcp
Transport: StreamableHTTP (stateless, kein Session-Management)
Protokoll: MCP 2024-11-05
Konfiguration in Claude Code
Einstellungen - MCP-Server - Server hinzufügen:
{
"name": "dealfilter",
"url": "https://dealfilter.ai/api/mcp",
"headers": {
"Authorization": "Bearer df_<key>"
}
}
Konfiguration in Claude.ai, OpenAI Codex und kompatiblen Clients
Alle MCP-kompatiblen Clients (Claude.ai, OpenAI Codex, Cursor u.a.) verwenden das mcpServers-Format:
{
"mcpServers": {
"dealfilter": {
"url": "https://dealfilter.ai/api/mcp",
"headers": {
"Authorization": "Bearer df_<key>"
}
}
}
}
MCP-Protokoll: initialize
POST /api/mcp
Authorization: Bearer df_<key>
Content-Type: application/json
Accept: application/json, text/event-stream
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": { "name": "claude-code", "version": "1.0" }
}
}
Response (SSE)
event: message
data: {"result":{"protocolVersion":"2024-11-05","capabilities":{"tools":{"listChanged":true}},"serverInfo":{"name":"dealfilter","version":"1.0.0"}},"jsonrpc":"2.0","id":1}
MCP-Protokoll: tools/list
POST /api/mcp
Authorization: Bearer df_<key>
Content-Type: application/json
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}
Response (Ausschnitt)
{
"result": {
"tools": [
{ "name": "submit_inquiry", "description": "... (async, Polling erforderlich)" },
{ "name": "list_inquiries", "description": "..." },
{ "name": "get_inquiry", "description": "..." },
{ "name": "change_phase", "description": "..." },
{ "name": "get_quota", "description": "..." }
]
}
}
MCP-Tools im Detail
submit_inquiry Ultra (in Planung)
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "submit_inquiry",
"arguments": {
"mailText": "Betreff: Java Entwickler für 6 Monate\n\nHallo...",
"channel": "EMAIL",
"newAgentName": "Hays AG"
}
}
}
Response
{
"result": {
"content": [{ "type": "text", "text": "{\"applicationId\":\"cmq0xyz123\",\"status\":\"analyzing\"}" }],
"isError": false
}
}
Warte 30-60 Sekunden, dann get_inquiry mit der applicationId aufrufen.
list_inquiries Premium Ultra (in Planung)
{
"method": "tools/call",
"params": {
"name": "list_inquiries",
"arguments": { "active": "true", "limit": 10, "offset": 0 }
}
}
get_inquiry Premium Ultra (in Planung)
{
"method": "tools/call",
"params": {
"name": "get_inquiry",
"arguments": { "id": "cmq0go2ib000a1h9kn8dno71t" }
}
}
Wenn analysisStatus = "analyzing": erneut abfragen. Wenn "done": scoreLabel, scorePercent, redFlags, hints, aiSummary auswerten.
change_phase Ultra (in Planung)
{
"method": "tools/call",
"params": {
"name": "change_phase",
"arguments": { "id": "cmq0go2ib000a1h9kn8dno71t", "status": "APPLIED" }
}
}
get_quota Premium Ultra (in Planung)
{
"method": "tools/call",
"params": {
"name": "get_quota",
"arguments": {}
}
}
OAuth-Connector
MCP-Clients wie Claude.ai verbinden sich nicht über einen manuell eingefügten df_-Key, sondern
über einen standardkonformen OAuth-2.0-Flow (RFC 6749 mit PKCE S256). Dabei stellt DealFilter ein
dfo_-Token aus, das im Hintergrund verwaltet wird.
Discovery
DealFilter veröffentlicht die Metadaten nach RFC 8414 und RFC 9728:
GET /.well-known/oauth-authorization-server
GET /.well-known/oauth-protected-resource
Die Authorization-Server-Metadaten nennen alle Endpunkte:
{
"issuer": "https://dealfilter.ai",
"authorization_endpoint": "https://dealfilter.ai/api/oauth/authorize",
"token_endpoint": "https://dealfilter.ai/api/oauth/token",
"registration_endpoint": "https://dealfilter.ai/api/oauth/register",
"revocation_endpoint": "https://dealfilter.ai/api/oauth/revoke",
"response_types_supported": ["code"],
"grant_types_supported": ["authorization_code"],
"code_challenge_methods_supported": ["S256"],
"token_endpoint_auth_methods_supported": ["none"]
}
Ablauf
- Client-Registrierung (
POST /api/oauth/register): Der Client registriert sich dynamisch mitredirect_uris(nur HTTPS, außerlocalhost) und erhält eineclient_id. - Autorisierung (
GET /api/oauth/authorize): Der User meldet sich an und bestätigt den Zugriff auf einer Zustimmungsseite. PKCE mitcode_challenge_method=S256ist Pflicht. - Token-Tausch (
POST /api/oauth/token): Der Client tauscht dencodepluscode_verifiergegen eindfo_-Token.
{
"access_token": "dfo_...",
"token_type": "Bearer",
"expires_in": 7776000
}
Token-Ablauf und Erneuerung
dfo_-Tokens laufen nach 90 Tagen ab (expires_in in Sekunden). Refresh-Tokens gibt es bewusst
nicht: Läuft das Token ab, startet der MCP-Client beim nächsten 401 automatisch den Connector-Flow
erneut und holt sich ein frisches Token - ohne manuelles Zutun.
Verbindung beenden
Zwei Wege:
- In der App: Einstellungen > API-Zugang > Verbundene Apps > "Beenden". Die App verliert sofort den Zugriff.
- Per Endpunkt (RFC 7009): Der Client widerruft sein eigenes Token.
POST /api/oauth/revoke
Content-Type: application/json
{ "token": "dfo_<token>" }
Antwort ist immer 200, auch bei unbekanntem Token (gemäß RFC 7009).
CLI
Voraussetzung: Node.js 18+
Installation
# Einmalig global installieren (empfohlen)
npm install -g @dealfilter/cli
# Oder direkt ohne Installation via npx
npx @dealfilter/cli <subkommando>
Konfiguration
Option 1 - Env-Variable (empfohlen für CI/Skripte):
export DEALFILTER_API_KEY=df_<key>
export DEALFILTER_BASE_URL=https://dealfilter.ai # optional
Option 2 - Config-Datei ~/.dealfilter.json:
{
"apiKey": "df_<key>",
"baseUrl": "https://dealfilter.ai"
}
Priorität: Env-Variable > Config-Datei. baseUrl ist optional (Standard: https://dealfilter.ai).
submit Ultra (in Planung) — Anfrage einreichen
# Text als Argument
dealfilter submit "Hallo, wir suchen einen Java-Entwickler für 6 Monate..."
# Text aus Datei
dealfilter submit --file=/tmp/anfrage.txt
# Text aus stdin (Pipeline)
cat anfrage.txt | dealfilter submit
pbpaste | dealfilter submit --channel=EMAIL --agent="Hays AG"
Optionen:
| Flag | Werte | Beschreibung |
|---|---|---|
--file=<pfad> | Dateipfad | Text aus Datei lesen |
--channel=<wert> | EMAIL|PORTAL|PHONE|SEARCH_AGENT | Standard: EMAIL |
--agent=<name> | string | Neuer Recruiter-Name |
--agentId=<id> | string | Bestehender Recruiter-ID |
Ausgabe:
{ "applicationId": "cmq0xyz123", "status": "analyzing" }
list Premium Ultra (in Planung) — Anfragen auflisten
dealfilter list --active=true # alle aktiven
dealfilter list --phase=INCOMING # nur INCOMING
dealfilter list --limit=5 --offset=10
dealfilter list --active=false # archivierte
Optionen:
| Flag | Werte | Beschreibung |
|---|---|---|
--phase=<wert> | Phase-Enum | Exakter Phase-Filter |
--active=true|false | boolean | Aktiv/archiviert Filter |
--limit=<n> | 1-100 | Standard: 50 |
--offset=<n> | int | Standard: 0 |
Ausgabe:
{
"items": [
{
"id": "cmq0go2ib000a1h9kn8dno71t",
"status": "INCOMING",
"channel": "PORTAL",
"projectTitle": "Senior Software Engineer - Microservices",
"agentName": "SOLCOM",
"analysisStatus": "done",
"scoreLabel": "GREEN",
"scorePercent": 88,
"createdAt": "2026-06-05T05:05:47.699Z",
"lastContactAt": "2026-06-05T05:07:49.699Z"
}
],
"total": 32,
"limit": 50,
"offset": 0
}
get Premium Ultra (in Planung) — Einzelne Anfrage abrufen
dealfilter get cmq0go2ib000a1h9kn8dno71t
Ausgabe (analysisStatus = "done"):
{
"id": "cmq0go2ib000a1h9kn8dno71t",
"status": "INCOMING",
"analysisStatus": "done",
"scoreLabel": "GREEN",
"scorePercent": 88,
"redFlags": [],
"hints": ["Java 17", "Kubernetes", "Remote 80%"],
"aiSummary": "Solides Java-Projekt...",
"project": {
"title": "Senior Software Engineer - Microservices",
"location": "Frankfurt",
"remotePercentMin": 60,
"remotePercentMax": 80,
"durationMonthsMin": 6,
"durationMonthsMax": 12
},
"agentName": "SOLCOM",
"communicationLog": []
}
Ausgabe (Analyse noch laufend):
{
"id": "cmq0xyz123",
"analysisStatus": "analyzing",
"scoreLabel": null,
"scorePercent": null,
"redFlags": null,
"hints": null,
"aiSummary": null
}
phase Ultra (in Planung) — Phase ändern
dealfilter phase cmq0go2ib000a1h9kn8dno71t APPLIED
Gültige Phasen: INCOMING > APPLIED > PROFILE_AT_CLIENT > WON / CONTRACT_SIGNED > ARCHIVED
Ausgabe:
{ "id": "cmq0go2ib000a1h9kn8dno71t", "status": "APPLIED" }
quota Premium Ultra (in Planung) — Kontingent abfragen
dealfilter quota
Ausgabe:
{
"used": 44,
"limit": 500,
"remaining": 456,
"resetAt": "2026-07-01T00:00:00.000Z"
}
Fehler-Referenz
| HTTP-Status | error-Wert | Beschreibung |
|---|---|---|
| 401 | unauthorized | Kein oder ungültiger Bearer-Token |
| 403 | api.read requires Premium plan or higher | Abrufen: kein Premium oder höher |
| 403 | api.write requires Ultra plan | Einreichen/Phase ändern: kein Ultra |
| 400 | invalid_id | Ungültige applicationId |
| 400 | validation_error | Pflichtfelder fehlen oder falsche Typen |
| 400 | invalid_json | Request-Body kein gültiges JSON |
| 404 | not_found | Anfrage nicht gefunden (oder gehört anderem User) |
| 429 | quota_exceeded | Credit-Limit erreicht |
| 429 | rate_limit_exceeded | Zu viele Requests in kurzer Zeit |
quota_exceeded-Response:
{
"error": "quota_exceeded",
"remaining": 0,
"limit": 500,
"used": 500
}
Async-Vertrag
submit_inquiry / POST /api/v1/applications folgt einem Fire-and-Poll-Muster:
1. POST /api/v1/applications → 202 { applicationId, status: "analyzing" }
2. Warte 30-60 Sekunden
3. GET /api/v1/applications/{id}
→ analysisStatus: "analyzing" → nochmal warten und wiederholen
→ analysisStatus: "done" → Ergebnis verfügbar
→ analysisStatus: "failed" → Analyse endgültig fehlgeschlagen
Für AI-Agenten: Einen Tool-Call für submit_inquiry als abgeschlossen werten bedeutet NICHT, dass das Ergebnis vorliegt. Nach dem Submit immer mit get_inquiry pollen bis analysisStatus != "analyzing". Niemals ein leeres scoreLabel als fertiges Ergebnis interpretieren.
Empfohlenes Polling-Intervall: 30 Sekunden, max. 5 Versuche (Analyse dauert typisch 10-30s nach dem Submit).