Sie können Ihre Supportanfragen zwischen Google Cloud und Ihrem CRM-System (Customer-Relationship-Management) (z. B. Jira Service Desk, Zendesk und ServiceNow) synchronisieren, indem Sie einen Connector für die Integration erstellen.
Dieser Connector verwendet die Cloud Support API (CSAPI) von Customer Care. Dieses Dokument enthält ein Beispiel dafür, wie Sie einen Connector erstellen und verwenden können. Sie können das Design an Ihren Anwendungsfall anpassen.
Annahmen
Wir treffen einige wichtige Annahmen darüber, wie Ihr CRM funktioniert und in welcher Sprache Sie den Connector schreiben. Wenn Ihr CRM über unterschiedliche Funktionen verfügt, können Sie trotzdem einen Connector erstellen, der einwandfrei funktioniert. Möglicherweise müssen Sie ihn jedoch anders implementieren als in diesem Leitfaden.
Dieser Leitfaden basiert auf folgenden Annahmen:
- Sie erstellen den Connector mit Python und dem Flask-Mikroframework.
- Wir gehen davon aus, dass Sie Flask verwenden, da es ein einfaches Framework zum Erstellen einer kleinen App ist. Sie können auch andere Sprachen oder Frameworks wie Java verwenden.
- Sie möchten Anhänge, Kommentare, Priorität, Fallmetadaten und Fallstatus synchronisieren. Sie müssen nur dann alle diese Daten synchronisieren, wenn Sie das möchten. Synchronisieren Sie beispielsweise keine Anhänge, wenn Sie das nicht möchten.
- Ihr CRM stellt Endpunkte zur Verfügung, die die zu synchronisierenden Felder lesen und schreiben können. Wenn Sie alle Felder wie in diesem Leitfaden beschrieben synchronisieren möchten, müssen die Endpunkte Ihres CRM-Systems die folgenden Vorgänge unterstützen:
Vorgang CSAPI-Äquivalent Anfragen mit einer unveränderlichen statischen ID abrufen. cases.get
Supportanfragen erstellen cases.create
Schließen Sie Supportanfragen. cases.close
Aktualisieren Sie die Priorität eines Falls. cases.patch
Listen Sie die Anhänge zu einem Fall auf. cases.attachments.list
Laden Sie einen Anhang für eine Supportanfrage herunter. media.download
Laden Sie einen Anhang zu einer Supportanfrage hoch. media.upload
Listen Sie Kommentare zu einem Fall auf. cases.comments.list
Fügen Sie einer Anfrage einen neuen Kommentar hinzu. cases.comments.create
Supportanfragen durchsuchen* cases.search
*Sie müssen nach der Zeit der letzten Aktualisierung filtern können. Außerdem muss es möglich sein, festzustellen, welche Anfragen mit Customer Care synchronisiert werden sollen. Wenn beispielsweise Fälle in Ihrem CRM benutzerdefinierte Felder enthalten können, können Sie ein benutzerdefiniertes boolesches Feld mit dem Namen synchronizeWithGoogleCloudSupport
ausfüllen und danach filtern.
Hochwertiges Design
Der Connector wird vollständig mit Google Cloud-Produkten und Ihrem CRM-System erstellt. Es handelt sich um eine App Engine-Anwendung, die Python im Flask-Mikroframework ausführt. Cloud Tasks wird verwendet, um die CSAPI und Ihr CRM regelmäßig nach neuen Anfragen und Aktualisierungen vorhandener Anfragen abzufragen. Außerdem werden Änderungen zwischen ihnen synchronisiert. Einige Metadaten zu Anfragen werden in Firestore gespeichert, aber gelöscht, wenn sie nicht mehr benötigt werden.
Das folgende Diagramm zeigt das allgemeine Design:
Connector-Ziele
Wenn ein Fall, den Sie synchronisieren möchten, in Ihrem CRM erstellt wird, wird ein entsprechender Fall in der Kundenbetreuung erstellt und alle nachfolgenden Aktualisierungen des Falls werden synchronisiert. Ebenso muss eine Anfrage, die in Customer Care erstellt wird, mit Ihrem CRM synchronisiert werden.
Insbesondere müssen folgende Aspekte von Anfragen synchronisiert werden:
- Fallerstellung:
- Wenn in einem System eine Supportanfrage erstellt wird, muss der Connector im anderen System eine entsprechende Supportanfrage erstellen.
- Wenn ein System nicht verfügbar ist, muss die Anfrage dort erstellt werden, sobald sie verfügbar ist.
- Kommentare:
- Wird einem Fall in einem System ein Kommentar hinzugefügt, muss er auch im anderen System dem entsprechenden Fall hinzugefügt werden.
- Anhänge:
- Wenn ein Fall in einem System als Anhang hinzugefügt wird, muss er im anderen System auch dem entsprechenden Fall hinzugefügt werden.
- Priorität:
- Wenn die Priorität eines Falls in einem System aktualisiert wird, muss die Priorität des entsprechenden Falls im anderen System aktualisiert werden.
- Fallstatus:
- Wenn ein Fall in einem System geschlossen wird, muss er auch im anderen System geschlossen werden.
Infrastruktur
Google Cloud-Produkte
Der Connector ist eine App Engine-Anwendung, die Cloud Firestore im Datastore-Modus zum Speichern von Daten zu den synchronisierten Fällen verwendet. Es verwendet Cloud Tasks, um Jobs mit automatischer Wiederholungslogik zu planen.
Für den Zugriff auf Anfragen in Customer Care nutzt der Connector ein Dienstkonto, um die V2 Cloud Support API aufzurufen. Sie müssen dem Dienstkonto die entsprechenden Berechtigungen zur Authentifizierung erteilen.
Ihr CRM
Der Connector greift über einen von Ihnen bereitgestellten Mechanismus auf Anfragen in Ihrem CRM zu. Vermutlich durch Aufrufen einer API, die von Ihrem CRM bereitgestellt wird.
Sicherheitsaspekte für Ihre Organisation
Der Connector synchronisiert Fälle in der Organisation, in der Sie ihn erstellt haben, und in allen untergeordneten Projekten der Organisation. Dadurch können Nutzer in dieser Organisation möglicherweise auf Daten des Kundensupports zugreifen, auf die sie möglicherweise keinen Zugriff haben sollen. Überlegen Sie sich genau, wie Sie Ihre IAM-Rollen strukturieren, um die Sicherheit in Ihrer Organisation aufrechtzuerhalten.
Detaillierte Konfiguration
CSAPI einrichten
So richten Sie die CSAPI ein:
- Erwerben Sie einen Cloud Customer Care-Support für Ihre Organisation.
- Aktivieren Sie die Cloud Support API für das Projekt, in dem Sie den Connector ausführen möchten.
- Rufen Sie die Anmeldedaten für das Apps Framework-Standarddienstkonto ab, das vom Connector verwendet werden soll .
- Weisen Sie dem Dienstkonto die folgenden Rollen auf Organisationsebene zu:
Tech Support Editor
Organization Viewer
Weitere Informationen zum Einrichten der CSAPI finden Sie im Nutzerhandbuch der Cloud Support API Version 2.
CSAPI aufrufen
Wir verwenden Python, um die CSAPI aufzurufen. Wir empfehlen die folgenden zwei Möglichkeiten, die CSAPI mit Python aufzurufen:
- Clientbibliotheken, die aus ihren Proto-Dateien generiert wurden. Diese sind moderner und idiomatischer, unterstützen jedoch nicht den Aufruf von CSAPI-Anhangsendpunkten. Weitere Informationen finden Sie unter GAPIC Generator.
- Clientbibliotheken, die aus dem Discovery-Dokument generiert wurden. Diese sind älter, unterstützen jedoch Anhänge. Weitere Informationen finden Sie unter Google API-Client.
Hier ist ein Beispiel für den Aufruf der CSAPI mithilfe von Clientbibliotheken, die aus ihrem Discovery-Dokument erstellt wurden:
"""
Gets a support case using the Cloud Support API.
Before running, do the following:
- Set the GOOGLE_APPLICATION_CREDENTIALS environment variable to
your service account credentials.
- Install the Google API Python Client: https://github.com/googleapis/google-api-python-client
- Change NAME to point to a case that your service account has permission to get.
"""
import os
import googleapiclient.discovery
NAME = "projects/some-project/cases/43595344"
def main():
api_version = "v2"
supportApiService = googleapiclient.discovery.build(
serviceName="cloudsupport",
version=api_version,
discoveryServiceUrl=f"https://cloudsupport.googleapis.com/$discovery/rest?version={api_version}",
)
request = supportApiService.cases().get(
name=NAME,
)
print(request.execute())
if __name__ == "__main__":
main()
Weitere Beispiele für den Aufruf der CSAPI findest du in diesem Repository.
Google-Ressourcennamen, -IDs und -Nummern
Lassen Sie organization_id
die ID Ihrer Organisation sein. Sie können in Customer Care Fälle in Ihrer Organisation oder in einem Projekt innerhalb Ihrer Organisation erstellen. Lassen Sie project_id
der Name des Projekts sein, in dem Sie Fälle erstellen können.
Name der Anfrage
Der Name einer Anfrage sieht so aus:
organizations/{organization_id}/cases/{case_number}
projects/{project_id}/cases/{case_number}
Dabei ist case_number
die Nummer, die dem Fall zugewiesen ist. Beispiel: 51234456
.
Name des Kommentars
Der Name eines Kommentars sieht so aus:
organizations/{organization_id}/cases/{case_number}/comments/{comment_id}
Dabei ist comment_id
eine Nummer, die einem Kommentar zugewiesen ist. Beispiel: 3
. Neben Organisationen sind auch Projekte von übergeordneten Organisationen erlaubt.
Name des Anhangs
Der Name eines Anhangs sieht so aus:
organizations/{organization_id}/cases/{case_number}/attachments/{attachment_id}
Dabei ist attachment_id
die ID eines Anhangs in einem Fall, falls vorhanden. Beispiel: 0684M00000JvBpnQAF
. Neben Organisationen sind auch Projekte von übergeordneten Organisationen erlaubt.
Firestore-Entitäten
CaseMapping
Ein CaseMapping
ist ein Objekt, das zum Speichern von Metadaten zu einem Fall definiert ist.
Sie wird für jeden Fall erstellt, der synchronisiert und gelöscht wird, wenn er nicht mehr benötigt wird. Weitere Informationen zu den in Firebase unterstützten Datentypen finden Sie unter Unterstützte Datentypen.
Ein CaseMapping
hat die folgenden Attribute:
Attribut | Beschreibung | Typ | Beispiel |
---|---|---|---|
ID |
Primärschlüssel. Wird von Firestore automatisch zugewiesen, wenn CaseMapping erstellt wird. |
Integer | 123456789 |
googleCaseName |
Der vollständige Name der Anfrage mit der Organisations- oder Projekt-ID und der Fallnummer. | Textstring | organizations/123/cases/456 |
companyCaseID |
Die Fall-ID in Ihrem CRM. | Integer | 789 |
newContentAt |
Das letzte Mal, dass in der Google-Anfrage oder der Anfrage in Ihrem CRM neue Inhalte erkannt wurden. | Datum und Uhrzeit | 0001-01-01T00:00:00Z |
resolvedAt |
Ein Zeitstempel, der angibt, wann der Google-Fall gelöst wurde. Wird zum Löschen von CaseMappings verwendet, wenn sie nicht mehr benötigt werden. |
Datum und Uhrzeit | 0001-01-01T00:00:00Z |
companyUpdatesSyncedAt |
Ein Zeitstempel, der angibt, wann der Connector zuletzt erfolgreich Updates aus Ihrem CRM angefordert und Aktualisierungen mit der Google-Anfrage synchronisiert hat. Wird zum Erkennen von Ausfällen verwendet. | Datum und Uhrzeit | 0001-01-01T00:00:00Z |
googleUpdatesSyncedAt |
Ein Zeitstempel, der angibt, wann der Connector Google erfolgreich nach Updates abgefragt und Aktualisierungen mit der Anfrage Ihres CRM-Systems synchronisiert hat. Wird zum Erkennen von Ausfällen verwendet. | Datum und Uhrzeit | 0001-01-01T00:00:00Z |
outageCommentSentToGoogle |
Gibt an, ob für den Fall, dass ein Ausfall festgestellt wurde, ein Kommentar zur Google-Anfrage hinzugefügt wurde. Damit wird verhindert, dass Kommentare zu mehreren Ausfällen hinzugefügt werden. | Boolesch | False |
outageCommentSentToCompany |
Falls ein Ausfall erkannt wurde, sehen Sie nach, ob der Anfrage Ihres CRM-Systems ein Kommentar hinzugefügt wurde. Damit wird verhindert, dass Kommentare zu mehreren Ausfällen hinzugefügt werden. | Boolesch | False |
priority |
Die Prioritätsstufe der Anfrage. | Integer | 2 |
Global
Global
ist ein Objekt, in dem globale Variablen für den Connector gespeichert werden.
Es wird nur ein Global
-Objekt erstellt und nie gelöscht. Sie sieht so aus:
Attribut | Beschreibung | Typ | Beispiel |
---|---|---|---|
ID | Primärschlüssel. Wird von Firestore automatisch zugewiesen, wenn dieses Objekt erstellt wird. | Integer | 123456789 |
google_last_polled_at |
Der Zeitpunkt, an dem Customer Care zuletzt nach Aktualisierungen abgefragt wurde. | Datum und Uhrzeit | 0001-01-01T00:00:00Z |
company_last_polled_at |
Der Zeitpunkt, zu dem Ihr Unternehmen zuletzt nach Aktualisierungen befragt wurde. | Datum und Uhrzeit | 0001-01-01T00:00:00Z |
Tasks
PollGoogleForUpdates
This task is scheduled to run every 60 seconds. It does the following:
- Search for recently updated cases:
- Call
CSAPI.SearchCases(organization_id, page_size=100, filter="update_time>{Global.google_last_polled_at - GOOGLE_POLLING_WINDOW}")
- Continue fetching pages as long as a
nextPageToken
is returned.
GOOGLE_POLLING_WINDOW
represents the period during which a case is continually checked for updates, even after it has been synced. The larger its value, the more tolerant the connector is to changes that are added while a case is syncing. We recommend that you set GOOGLE_POLLING_WINDOW
to 30 minutes to avoid any problems with comments being added out of order.
- Make a
CaseMapping
for any new cases:
- If
CaseMapping
does not exist for case.name
and case.create_time
is less than 30 days ago, then create a CaseMapping
with the following values:
Property
Value
caseMappingID
N/A
googleCaseName
case.name
companyCaseID
null
newContentAt
current_time
resolvedAt
null
companyUpdatesSyncedAt
current_time
googleUpdatesSyncedAt
null
outageCommentSentToGoogle
False
outageCommentSentToCompany
False
priority
case.priority
(converted to an integer)
- Queue tasks to sync all recently updated cases:
- Specifically,
SyncGoogleCaseToCompany(case.name)
.
- Update
CaseMappings
:
- For each open
CaseMapping
not recently updated, update CaseMapping.googleUpdatesSyncedAt
to the current time.
- Update last polled time:
- Update
Global.google_last_polled_at
in Firestore to the current time.
Retry logic
Configure this task to retry a few times within the first minute and then expire.
PollCompanyForUpdates
This task is scheduled to run every 60 seconds. It does the following:
- Search for recently updated cases:
- Call
YOUR_CRM.SearchCases(page_size=100, filter=”update_time>{Global.company_last_polled_at - COMPANY_POLLING_WINDOW} AND synchronizeWithGoogleCloudSupport=true”)
.
COMPANY_POLLING_WINDOW
can be set to whatever time duration works for you. For example, 5 minutes.
- Make a
CaseMapping
for any new cases:
- For each case, if
CaseMapping
does not exist for case.id
and case.create_time
is less than 30 days ago, create a CaseMapping
that looks like this:
Property
Value
caseMappingID
N/A
googleCaseName
null
companyCaseID
case.id
newContentAt
current_time
resolvedAt
null
companyUpdatesSyncedAt
null
googleUpdatesSyncedAt
current_time
outageCommentSentToGoogle
False
outageCommentSentToCompany
False
priority
case.priority
(converted to an integer)
- Queue tasks to sync all recently updated cases:
- Specifically, queue
SyncCompanyCaseToGoogle(case.name)
.
- Update
CaseMappings
:
- For each open
CaseMapping
not recently updated, update CaseMapping.companyUpdatesSyncedAt
to the current time.
- Update last polled time:
- Update
Global.company_last_polled_at
in Firestore to the current time.
Retry logic
Configure this task to retry a few times within the first minute and then expire.
SyncGoogleUpdatesToCompany(case_name)
Implementation
- Get the case and case mapping:
- Get
CaseMapping
for case_name
.
- Call
CSAPI.GetCase(case_name)
.
- If necessary, update resolved time and case status:
- If
CaseMapping.resolvedAt == null
and case.status == CLOSED
:
- Set
CaseMapping.resolvedAt
to case.update_time
- Close the case in the CRM as well
- Try to connect to an existing case in the CRM. If unable, then make a new one:
- If
CaseMapping.companyCaseID == null
:
- Try to get your CRM case with
custom_field_google_name == case_name
custom_field_google_name
is a custom field you create on the case object in your CRM.
- If the CRM case can't be found, call
YOUR_CRM.CreateCase(case)
with the following case:
Case field name in your CRM
Value
Summary
Case.diplay_name
Priority
Case.priority
Description
"CONTENT MIRRORED FROM GOOGLE SUPPORT:\n" + Case.description
Components
"Google Cloud
"
Customer Ticket (custom_field_google_name
)
case_name
Attachments
N/A
- Update the
CaseMapping
with a CaseMapping
that looks like this:
Property
Value
companyCaseID
new_case.id
googleUpdatesSyncedAt
current_time
- Add comment to Google case: "This case is now syncing with Company Case:
{case_id}
".
- Synchronize the comments:
- Get all comments:
- Call
CSAPI.ListComments(case_name, page_size=100)
. The maximum page size is 100. Continue retrieving successive pages until the oldest comment retrieved is older than googleUpdatesSyncedAt - GOOGLE_POLLING_WINDOW
.
- Call
YOUR_CRM.GetComments(case_id, page_size=50)
. Continue retrieving successive pages until the oldest comment retrieved is older than companyUpdatesSyncedAt - COMPANY_POLLING_WINDOW
.
- Optional: If you'd like, consider caching comments in some way so you can avoid making extra calls here. We leave the implementation of that up to you.
- Compare both lists of comments to determine if there are new comments on the Google Case.
- For each new Google comment:
- Call
YOUR_CRM.AddComment(comment.body)
, starting with "[Google Comment {comment_id}
by {comment.actor.display_name}
]".
- Repeat for attachments.
- Update
CaseMapping.googleUpdatesSyncedAt
to the current time.
Retry logic
Configure this task to retry indefinitely with exponential backoff.
SyncCompanyUpdatesToGoogle(case_id)
Implementation:
- Get the case and case mapping.
- Get
CaseMapping
for case.id
.
- Call
YOUR_CRM.GetCase(case.id)
.
- If necessary, update resolved time and case status:
- If
CaseMapping.resolvedAt == null
and case.status == CLOSED
:
- Set
CaseMapping.resolvedAt
to case.update_time
- Close the case in CSAPI as well
- Try to connect to an existing case in CSAPI. If unable, then make a new one:
- If
CaseMapping.googleCaseName == null
:
- Search through cases in CSAPI. Try to find a case that has a comment containing “This case is now syncing with Company Case:
{case_id}
”. If you're able to find one, then set googleCaseName
equal to its name.
- Otherwise, call
CSAPI.CreateCase(case)
:
- Synchronize the comments.
- Get all comments for the case from CSAPI and the CRM:
- Call
CSAPI.ListComments(case_name, page_size=100)
. Continue retrieving successive pages until the oldest comment retrieved is older than googleUpdatesSyncedAt - GOOGLE_POLLING_WINDOW
.
- Call
YOUR_CRM.GetComments(case_id, page_size=50)
. Continue retrieving successive pages until the oldest comment retrieved is older than companyUpdatesSyncedAt - COMPANY_POLLING_WINDOW
.
- NOTE: If you'd like, consider caching comments in some way so you can avoid making extra calls here. We leave the implementation of that up to you.
- Compare both lists of comments to determine if there are new comments on the CRM case.
- For each new Company comment:
- Call
CSAPI.AddComment
, starting with "[Company Comment {comment.id}
by {comment.author.displayName}
]".
- Repeat for attachments.
- Update
CaseMapping.companyUpdatesSyncedAt
to the current time.
Retry logic
Configure this task to retry indefinitely with exponential backoff.
CleanUpCaseMappings
This task is scheduled to run daily. It deletes any CaseMapping
for a case that has been closed for 30 days according to resolvedAt
.
Retry logic
Configure this task to retry with exponential backoff for up to 24 hours.
DetectOutages
This task is scheduled to run once every 5 minutes. It detects outages and alerts your Google and CRM cases (when possible) if a case is not syncing within the expected latency_tolerance
.
latency_tolerance
is defined as follows, where Time Since New Content = currentTime - newContentAt
:
Priority
Fresh (<1 hour)
Default (1 hour-1day)
Stale (>1 day)
P0
10 min
10 min
15 min
P1
10 min
15 min
60 min
P2
10 min
20 min
120 min
P3
10 min
20 min
240 min
P4
10 min
30 min
240 min
The latency that is relevant for the connector is not request latency, but rather the latency between when a change is made in one system and when it is propagated to the other. We make latency_tolerance
dependent on priority and freshness to avoid spamming cases unnecessarily. If there is a short outage, such as scheduled maintenance on either system, we don't need to alert P4
cases that haven't been updated recently.
When DetectOutages
runs, it does the following:
- Determine if a
CaseMapping
needs an outage comment, whereupon it adds one:
- For each
CaseMapping
in Firestore:
- If recently added (
companyCaseId
or googleUpdatesSyncedAt
is not defined), then ignore.
- If
current_time > googleUpdatesSyncedAt + latency_tolerance OR current_time > companyUpdatesSyncedAt + latency_tolerance
:
- If
!outageCommentSentToGoogle
:
- Try:
- Add comment to Google that "This case has not synced properly in
{duration since sync}
."
- Set
outageCommentSentToGoogle = True
.
- If
!outageCommentSentToCompany
:
- Try:
- Add comment to your CRM that "This case has not synced properly in
{duration since sync}
."
- Set
outageCommentSentToCompany = True
.
- Else:
- If
outageCommentSentToGoogle
:
- Try:
- Add comment to Google that "Syncing has resumed."
- Set
outageCommentSentToGoogle = False
.
- If
outageCommentSentToCompany
:
- Try:
- Add comment to your CRM that "Syncing has resumed."
- Set
outageCommentSentToCompany = False
.
- Return a failing status code (4xx or 5xx) if an outage is detected. This causes any monitoring you've set up to notice that there is a problem with the task.
Retry logic
Configure this task to retry a few times within the first 5 minutes and then expire.
What's next
Your connector is now ready to use.
If you'd like, you can also implement unit tests and integration tests. Also, you can add monitoring to check that the connector is working correctly on an ongoing basis.