CRM und ERP
Neue passende Ausschreibungen automatisch als Verkaufschance im CRM, Fristen und Werte im ERP, mit Feldzuordnung und Schutz vor Dubletten.
Diese Leistung erhalten Sie über ein individuelles Angebot.
Ihr CRM bekommt neue passende Ausschreibungen als Verkaufschance. Das CRM ist die Software, in der Ihr Vertrieb Kunden und Verkaufschancen führt. Die Verkaufschance trägt Frist, Auftraggeber und Auftragswert, soweit procuris sie kennt. Hat die Vergabestelle keinen Auftragswert veröffentlicht, kann ein geschätzter Wert kommen, der als geschätzt gekennzeichnet ist. Verschiebt die Vergabestelle die Frist, zieht das CRM nach. Ihr ERP, die Software für Aufträge, Planung und Buchhaltung, bekommt dieselben Daten für Angebotsplanung und Auswertung.
Die Anbindung baut Ihre IT oder Ihr Dienstleister. procuris liefert die Daten über Webhooks und, je nach Variante, zusätzlich über die API. Soll procuris die Anbindung bauen, nehmen wir das in Ihr Angebot auf.
Die Rezepte setzen nur eine Schnittstelle in Ihrem System voraus. Ihr CRM oder ERP muss Daten über eine eigene Schnittstelle annehmen. Salesforce, HubSpot, Microsoft Dynamics, Pipedrive und SAP bieten eine solche Schnittstelle. Einen fertigen Connector für ein bestimmtes Produkt gibt es nicht. Welches Feld wohin gehört, legen Sie selbst fest, nach der Tabelle unter Felder zuordnen.
Für ein CRM empfehlen wir einen eigenen kleinen Dienst. Ein Workflow-Builder käme ohne Programmierung aus, reicht aber nur für einfache Abläufe wie eine Teams-Nachricht. Der Abgleich mit dem CRM braucht in beiden Varianten eine Warteschlange und den Vergleich von Ständen. Variante A braucht zusätzlich eine Erstbefüllung über die API.
Rezept 1: Neuer Treffer wird Verkaufschance
Das Rezept hat zwei Varianten. Sie unterscheiden sich darin, welche Ausschreibungen ins CRM sollen und welche Zugänge Sie brauchen.
- Variante A bringt alle Ausschreibungen zu Ihren Filtern für Branche und Region ins CRM (
tender.published). Sie braucht API und Webhooks: die API für die Erstbefüllung und den nächtlichen Abgleich, Webhooks für alles dazwischen. - Variante B bringt nur die Treffer Ihrer Suchaufträge (
search.hit). Sie braucht nur Webhooks. Eine Erstbefüllung entfällt.
Die Schritte 4, 5 und 9 gelten nur für Variante A.
Felder anlegen. Im CRM an der Verkaufschance ein eindeutiges Textfeld „procuris-ID“ für
tender.id, ein Feld „procuris-Stand“ für lastModified, ein Zahlenfeld „Passung“ und ein
Feld „Passung vom“ für den Zeitpunkt der Passung. Am Account oder Geschäftspartner ein
eindeutiges Textfeld „procuris-Organisation“ für organizations[].id. Über „procuris-ID“
erkennt Ihr System dieselbe Ausschreibung wieder. Über „procuris-Organisation“ erkennt es
denselben Auftraggeber, sofern procuris ihn als dieselbe Stelle erkannt hat. Zwei verschiedene
id schließen nicht aus, dass es dieselbe Stelle ist. Dann entstehen im CRM zwei Accounts, die
Ihr Vertrieb von Hand zusammenführt. Die Felder „procuris-Stand“ und „Passung vom“ braucht
Schritt 7.
Empfänger mit Warteschlange bauen. Ein kleiner Dienst nimmt die Nachrichten an und prüft die Signatur mit einer fertigen Bibliothek aus Zustellung und Sicherheit. Danach legt er die Nachricht in eine Warteschlange und antwortet mit 2xx, bevor er ins CRM schreibt. So bleibt er unter den 15 Sekunden, die procuris auf eine Antwort wartet. Ins CRM schreibt er erst in Schritt 6.
Zieladresse anlegen und Ereignisse wählen. Die Person mit der Rolle Inhaber legt in
procuris unter Einstellungen › Organisation › Webhooks die Adresse des Dienstes als
Zieladresse an. Den Bereich Webhooks gibt es erst, wenn der Zugang nach Vertragsschluss
eingerichtet ist. Bis dahin führt die gleichnamige Zeile im Abschnitt Auf Anfrage nur zur
Anfrage eines Angebots. Variante A: die Ereignisarten tender.published mit den Filtern für Ihre
Branche und Region, dazu tender.updated für geänderte Werte, Lose und Fristen und
tender.archived zum Abschließen. Variante B: die Ereignisarten search.hit, tender.updated
und tender.archived, dazu die Suchaufträge, deren Treffer ins CRM sollen. Legen Sie bei der
Zieladresse fest, dass die Auswahl der Suchaufträge auch für tender.updated und
tender.archived gilt. Dann kommen geänderte Werte, verschobene Fristen und Archivierungen zu
jeder Ausschreibung, die schon einmal Treffer eines dieser Suchaufträge war, siehe
Ereignisse. Ab dem Speichern laufen die gewählten Ereignisse in die
Warteschlange. Ob sie dort ankommen, prüfen Sie mit Testnachricht senden.
Erstbefüllung (Variante A). Die Erstbefüllung bringt einmal alle Ausschreibungen ins CRM,
die es zu Ihren Filtern schon gibt. Ihr Dienst merkt sich den Zeitpunkt, zu dem er beginnt.
Dann ruft er über die API mit denselben Filtern ab, die bei der Zieladresse stehen, und legt je
Ausschreibung eine Verkaufschance an, siehe Filter und Takt. Zu
jeder Verkaufschance speichert er lastModified in „procuris-Stand“.
Nachholabruf (Variante A). Danach ruft er ein zweites Mal ab, mit updated_since gleich dem
gemerkten Zeitpunkt aus Schritt 4. So bekommt er, was sich während der Erstbefüllung geändert
hat.
Warteschlange abarbeiten. Erst jetzt verarbeitet der Dienst die Nachrichten aus der
Warteschlange, danach jede neue. In Variante B kommen die ersten Treffer am Morgen nach dem
Anlegen der Zieladresse. Die Reihenfolge der Nachrichten ist nicht garantiert, weil
Wiederholungen und Nachlieferungen später ankommen können. Darum kann jedes Ereignis außer der
Testnachricht eine Verkaufschance anlegen. Nachrichten mit data.test gleich true übergeht
der Dienst.
Die procuris-ID entscheidet über Anlegen oder Nachziehen. Der Dienst sucht zuerst eine
Verkaufschance mit procuris-ID gleich data.tender.id. Gibt es eine, gilt Schritt 7. Gibt es
keine, legt er sie aus data.tender an, bei tender.archived gleich mit dem Status aus der
Tabelle unter Status abbilden. Beim Anlegen speichert er data.tender.lastModified in
„procuris-Stand“. Bei search.hit speichert er data.fit in „Passung“ und den timestamp der
Nachricht in „Passung vom“. Den Auftraggeber sucht er über „procuris-Organisation“ und legt ihn
nur an, wenn es ihn im CRM nicht gibt.
In Variante B kann eine Chance ohne Passung entstehen. Das passiert, wenn tender.updated oder
tender.archived zu einem früheren Treffer kommt, zu dem das CRM noch keine Chance hat, etwa
zu einem Treffer von vor dem Anlegen der Zieladresse. Nur search.hit trägt eine Passung. Das
Feld „Passung“ bleibt dann leer.
Änderungen nachziehen. Ist data.tender.lastModified neuer als „procuris-Stand“, schreibt
der Dienst alle zugeordneten Felder aus data.tender neu, nicht nur die aus changedFields.
Danach speichert er das neue lastModified in „procuris-Stand“. Ist es älter oder gleich,
übernimmt er aus data.tender nichts. data.fit übernimmt er nur, wenn der timestamp der
Nachricht neuer ist als „Passung vom“, und speichert diesen timestamp dann dort. So
überschreibt weder ein verspäteter noch ein nachgelieferter search.hit einen neueren Stand.
Nachrichten zu Änderungen, die schon aus Erstbefüllung oder Nachholabruf im CRM stehen, fallen
so weg. Zwischen Erstbefüllung und Webhooks entsteht in Variante A keine Lücke, weil die
Warteschlange ab dem Speichern der Zieladresse läuft und die Erstbefüllung erst danach beginnt.
Abschließen. Bei tender.archived bildet der Dienst data.tender.archiveReason auf den
Status im CRM ab, siehe Tabelle unter Status abbilden.
Nächtlicher Abgleich (Variante A). Der nächtliche Abgleich zieht herausgefallene
Ausschreibungen nach und legt fehlende Chancen an. Passt eine Ausschreibung nach einer Änderung
nicht mehr zu Ihren Filtern, etwa weil die Vergabestelle die Region korrigiert, kommt für sie
kein tender.updated mehr, nur noch tender.archived. Darum ruft der Dienst jede Nacht über
die API ohne inhaltliche Filter ab, nur mit updated_since.
Der erste nächtliche Lauf holt alles ab dem Start der Erstbefüllung. Der Dienst setzt updated_since
dafür auf den Zeitpunkt, den er sich in Schritt 4 gemerkt hat. So erfasst er auch
Ausschreibungen, die seit Beginn der Erstbefüllung aus den Filtern gefallen sind. Ab der
zweiten Nacht gilt das größte lastModified des vorigen Laufs.
Die procuris-ID entscheidet, was mit einem Datensatz geschieht. Gibt es sie im CRM, zieht der
Dienst die Chance nach den Regeln aus Schritt 7 nach. Gibt es sie nicht, prüft er selbst, ob
der Datensatz zu den Filtern der Zieladresse passt, zum Beispiel über cpvClassifications und
regionCodes. Passt er, legt der Dienst die Chance an wie in Schritt 6, eine archivierte gleich
mit Status. So kommen auch Ausschreibungen ins CRM, deren Nachricht verloren gegangen ist. Alle
übrigen Datensätze übergeht er.
Am Ende des Laufs speichert er das größte lastModified als Stand für die nächste Nacht.
Liefert ein Lauf nichts, bleibt der gespeicherte Stand unverändert. Der Abruf ohne Filter holt
jede geänderte Ausschreibung des Bestands und braucht darum mehr Abrufe als ein gefilterter,
siehe Filter und Takt.
Lücken schließen
Verpasste Nachrichten holen Sie je nach Alter auf verschiedenen Wegen nach. procuris verwirft eine Nachricht, wenn auch der zehnte Versuch scheitert, gut drei Tage nach dem ersten. Verworfene Nachrichten meldet procuris der Inhaberin in einer Sammelmail, einmal am Tag, siehe Zustellung und Sicherheit.
- Nachrichten der letzten 7 Tage sendet die Inhaberin unter Webhooks bei der Zieladresse erneut. Das gilt für beide Varianten.
- Ältere Lücken bei
tender.*holt nur ein System mit API-Zugang überupdated_sincenach. In Variante A erledigt das der nächtliche Abgleich aus Schritt 9. In Variante B ohne API bleibt eine solche Lücke offen. - Ältere
search.hitlassen sich nicht nachholen, weil die API keine Passung und keine Suchaufträge kennt.
Felder zuordnen
Ereignisse tragen die Ausschreibung mit den Feldern der API. Sie steht unter data.tender. Die Werte im Hinweis stammen aus dem Musterdatensatz des Datenmodells.
| Feld in der Nachricht | Typisches Feld im CRM | Hinweis |
|---|---|---|
data.tender.id | procuris-ID | eindeutig, erkennt dieselbe Ausschreibung wieder, siehe Dubletten vermeiden |
data.tender.lastModified | procuris-Stand | Zeitpunkt der letzten inhaltlichen Änderung bei procuris, in UTC |
data.tender.title | Name der Verkaufschance | „Nordhausen - Sanierung Rolandbrunnen, Erneuerung Brunnentechnik“ |
data.tender.url | Link | öffentliche Seite der Bekanntmachung |
data.tender.organizations[] mit role gleich contractingParty | Account oder Geschäftspartner | id in „procuris-Organisation“, dazu name, address, email, phone |
data.tender.organizations[].contactName | Kontaktperson am Account | kann null sein oder eine Stelle statt einer Person nennen, im Muster „Vergabestelle“ |
data.tender.submissionDate | Abschlussdatum | Angebotsfrist in UTC, im Muster nach der Verschiebung der 14. Oktober 2026, 08:00 UTC |
data.tender.participationDeadline | zweites Datumsfeld, zum Beispiel „Teilnahmefrist“ | nur bei zweistufigen Verfahren gesetzt |
data.tender.contractAmount.value | Betrag | ohne Umsatzsteuer, in contractAmount.currency. Im Muster 351.000 Euro. |
data.tender.contractAmount.estimated | Hinweis „Betrag geschätzt“ | bei true, weil die Vergabestelle keinen Wert veröffentlicht hat |
data.tender.cpvClassifications[0].title | Kategorie | Die Liste kann leer sein, dann bleibt die Kategorie leer. |
data.tender.tenderNumber | Referenz | Vergabenummer, im Muster „33/61/2026“ |
data.tender.lots[] | Positionen oder Unterchancen | je Los lotNumber, title, contractAmount |
data.fit (nur search.hit) | Passung | Passung von 0 bis 100 |
timestamp (nur search.hit) | Passung vom | Zeitpunkt der Passung, entscheidet in Schritt 7 über das Überschreiben |
Fehlende Werte bleiben leer oder bekommen einen Ersatz. Ist submissionDate gleich null und verlangt Ihr CRM ein Abschlussdatum, setzen Sie publicationDate plus 30 Tage und markieren Sie die Chance mit „Frist offen“. Sobald die Vergabestelle eine Frist nennt, kommt tender.updated mit submissionDate in changedFields. Ist contractAmount gleich null, lassen Sie den Betrag leer.
Status abbilden
archiveReason | Status im CRM |
|---|---|
expired | verloren oder geschlossen, wenn kein Angebot abgegeben wurde |
cancelled | verloren oder geschlossen, Grund „aufgehoben“ |
awarded | an Dritte vergeben, wenn Ihr Angebot nicht gewonnen hat |
merged | Gibt es die Chance zu mergedInto, beide zusammenführen. Fehlt der bleibende Datensatz im CRM: Mit API-Zugang (Variante A) holt der Dienst ihn mit GET /v1/tenders/{mergedInto} und legt die Chance daraus an. Ohne API-Zugang (Variante B) schließt er die alte Chance und vermerkt mergedInto an ihr. Die Chance zur bleibenden Ausschreibung entsteht erst, wenn sie Treffer eines gewählten Suchauftrags ist und ein Ereignis zu ihr kommt. |
Dubletten vermeiden
Die procuris-ID verhindert doppelte Chancen zu derselben id. Ein Datensatz je Ausschreibung ist bei procuris das Ziel, keine Garantie. Erscheint eine Bekanntmachung auf mehreren Portalen, führt procuris sie zu einem Datensatz zusammen. Erkennt procuris eine Dublette erst später, archiviert es den jüngeren Datensatz mit archiveReason gleich merged und nennt in mergedInto die id des Datensatzes, der bestehen bleibt. Ihr Dienst behandelt das nach der Zeile merged in der Tabelle oben.
Rezept 2: Nächtlicher Abgleich ins ERP
Im ERP wird jede passende Ausschreibung ein Angebotsprojekt. Passend heißt hier: Sie passt zu Ihren Filtern. In SAP ist das zum Beispiel ein Projekt oder ein Vertriebsbeleg der Art Angebot. Daran hängen Frist als Termin, Auftraggeber als Geschäftspartner und Auftragswert als geplanter Umsatz.
Ein nächtlicher Abruf über die API reicht hier. Planung und Auswertung kommen mit dem Stand vom Vortag aus. Häufigere Abrufe sind möglich. procuris liefert jedoch höchstens einen neuen Stand je Stunde.
Erstbefüllung. Ein Ladelauf ruft GET /v1/tenders mit Ihren Filtern ab und legt je
Datensatz ein Projekt an, über id als Schlüssel.
Nächtlicher Lauf. Er ruft mit updated_since gleich dem größten lastModified des vorigen
Laufs ab. Es kommen neue, geänderte und archivierte Ausschreibungen. Archivierte schließt er im
ERP ab oder führt sie zusammen, nach der Tabelle unter Status abbilden.
Herausgefallene Ausschreibungen behalten im gefilterten Lauf den alten Stand. Sollen sie im ERP aktuell bleiben, ruft der Lauf ohne inhaltliche Filter ab, wie Schritt 9 in Rezept 1. Der Ablauf im Einzelnen steht unter Filter und Takt, alle Felder im Datenmodell.
Verwandte Seiten
Angebot anfordern
Schildern Sie uns, was Sie nutzen oder anbinden möchten. Ihr Angebot richtet sich nach diesem Umfang.