In diesem Abschnitt wird beschrieben, wie Sie zeitkritische Updates Ihrer Feeds an Google senden können. Mit der Incremental Updates API kannst du Entitäten in deinen Feeds nahezu in Echtzeit aktualisieren und löschen.
Diese Funktion ist in erster Linie für Updates vorgesehen, die nicht vorhersehbar sind, z. B. für Notfälle. In der Regel sollte jede Änderung, die über die API für inkrementelle Updates gesendet wird, nicht länger als eine Woche dauern. Wenn Ihre Änderung nicht sofort übernommen werden muss, können Sie stattdessen eine Batch-Aktualisierung verwenden. Inkrementelle Aktualisierungen werden in der Regel nicht länger als fünf Minuten verarbeitet.
Einrichtung
So implementieren Sie inkrementelle Updates:
- Folgen Sie der Anleitung unter Projekt erstellen und einrichten, um ein Projekt zu erstellen.
- Folgen Sie den Schritten unter Dienstkonto einrichten, um ein Dienstkonto zu erstellen. Sie müssen die Rolle „Inhaber“ des Projekts haben, um eine Rolle „Bearbeiter“ für das Dienstkonto hinzufügen zu können.
- Optional, aber empfohlen: Installieren Sie die Google-Clientbibliothek in der Sprache Ihrer Wahl, um den API-Zugriff beim Aufrufen der API zu vereinfachen. In den folgenden Codebeispielen werden diese Bibliotheken verwendet. Andernfalls müssen Sie den Austausch von Tokens manuell handhaben, wie unter Mit OAuth 2.0 auf Google APIs zugreifen beschrieben.
Endpunkt
Wenn Sie Google über eine Aktualisierung informieren möchten, senden Sie eine HTTP-POST-Anfrage an die Incremental Updates API und fügen Sie eine Nutzlast mit Updates und Ergänzungen hinzu. Das verwendete Inventarschema bestimmt, an welchen Endpunkt die Anfrage gesendet wird:
Inventar der Version 2
https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/TYPE/ENTITY_ID:push
Inventar der Version 1
https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/ENTITY_ID:push
Stellen Sie zum Entfernen einer Entität eine HTTP DELETE-Anfrage an den folgenden Endpunkt, der dem verwendeten Inventarschema entspricht:
Inventar der Version 2
https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/TYPE/ENTITY_ID?entity.vertical=FOODORDERING&delete_time=DELETE_TIME
Inventar der Version 1
https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/ENTITY_ID?entity.vertical=FOODORDERING&delete_time=DELETE_TIME
Ersetzen Sie in den obigen Anfragen Folgendes:
- PROJECT_ID: Die Google Cloud-Projekt-ID, die mit dem Projekt verknüpft ist, das Sie unter Projekt erstellen und einrichten erstellt haben.
- TYPE (nur Inventarschema v2): Der Entitätstyp (Property
@type
) des Objekts in Ihrem Datenfeed, den Sie aktualisieren möchten. - ENTITY_ID: ID der Entität, die in der Nutzlast enthalten ist. Die Entitäts-ID muss URL-codiert werden.
- DELETE_TIME (nur Endpunkt löschen): Optionales Feld, mit dem angegeben wird, wann die Entität auf Ihren Systemen gelöscht wurde (Standardeinstellung ist, wenn die Anfrage eingeht). Der Zeitwert darf nicht in der Zukunft liegen. Wenn Sie eine Entität über einen inkrementellen Aufruf senden, wird bei einem Löschaufruf auch das Feld
delete_time
verwendet. Formatieren Sie diesen Wert alsyyyy-mm-ddTHH:mm:ssZ
Angenommen, Sie haben ein Projekt mit der ID „delivery-provider-id“ und dem V2-Inventarschema. Sie möchten Änderungen am Restaurant mit dem Restaurant-Entitätstyp "MenuSection" und der Entitäts-ID "menuSection_122" vornehmen. Der Endpunkt für Aktualisierungen Ihrer Daten sieht so aus:
https://actions.googleapis.com/v2/apps/delivery-provider-id/entities/MenuSection/menuSection_122:push
Um diese Entität zu entfernen, führen Sie den folgenden HTTP DELETE API-Aufruf aus:
https://actions.googleapis.com/v2/apps/delivery-provider-id/entities/MenuSection/menuSection_122?entity.vertical=FOODORDERING
Sandbox-Anfragen
Folgen Sie bei Sandbox-Anfragen der Anleitung unter Endpunkt oben, senden Sie jedoch Anfragen an /v2/sandbox/apps/
statt an /v2/apps/
. Eine Sandbox-Löschanfrage für Inventarschema v2 sieht beispielsweise so aus:
https://actions.googleapis.com/v2/sandbox/apps/PROJECT_ID/entities/TYPE/ENTITY_ID?entity.vertical=FOODORDERING&delete_time=DELETE_TIME
Updates und Ergänzungen
Ihre täglichen Batch-Feeds sollten außerdem alle über diese API eingereichten Änderungen enthalten. Andernfalls werden die inkrementellen Änderungen durch Ihre Batch-Updates überschrieben.
Nutzlast
Jede POST-Anfrage muss die Anfrageparameter sowie die JSON-Nutzlast enthalten, die die strukturierten Daten eines beliebigen Entitätstyps im Inventarschema enthält.
Die JSON-Datei sollte wie im Batchfeed angezeigt werden. Es gibt jedoch folgende Unterschiede:
- Der Nutzlasttext darf nicht größer als 5 MB sein. Ähnlich wie bei Batch-Feeds empfehlen wir, Leerzeichen zu entfernen, um mehr Daten aufzunehmen.
- Der Briefumschlag sieht so aus:
{ "entity": { "data":"ENTITY_DATA", "vertical":"FOODORDERING" }, "update_time":"UPDATE_TIMESTAMP" }
Ersetzen Sie in der obigen Nutzlast Folgendes:
- ENTITY_DATA: Entität im JSON-Format, serialisiert als String. Die JSON-LD-Entität muss als String im Feld
data
übergeben werden. - UPDATE_TIMESTAMP (optional): Zeitstempel, der angibt, wann die Entität in Ihren Systemen aktualisiert wurde. Der Zeitwert darf nicht in der Zukunft liegen. Der Standardzeitstempel ist der Zeitpunkt, zu dem Google die Anfrage erhält. Beim Senden einer Entität über eine inkrementelle Anfrage verwendet die Entitätsversionsverwaltung auch im Fall einer Anfrage zum Hinzufügen/Aktualisieren das Feld
update_time
.
Entität aktualisieren
Beispiel 1: Restaurant aktualisieren
Angenommen, Sie müssen die Telefonnummer eines Restaurants dringend aktualisieren. Das Update enthält den JSON-Code für das gesamte Restaurant.
Ein Batchfeed könnte so aussehen:
{ "@type": "Restaurant", "@id": "restaurant12345", "name": "Some Restaurant", "url": "https://www.provider.com/somerestaurant", "telephone": "+16501234567", "streetAddress": "345 Spear St", "addressLocality": "San Francisco", "addressRegion": "CA", "postalCode": "94105", "addressCountry": "US", "latitude": 37.472842, "longitude": -122.217144 }
Dann würde Ihre inkrementelle Aktualisierung per HTTP POST folgendermaßen aussehen:
POST v2/apps/provider-project/entities/Restaurant/restaurant12345:push Host: actions.googleapis.com Content-Type: application/ld+json { "entity": { "data": { "@type": "Restaurant", "@id": "restaurant12345", "name": "Some Restaurant", "url": "https://www.provider.com/somerestaurant", "telephone": "+16501235555", "streetAddress": "345 Spear St", "addressLocality": "San Francisco", "addressRegion": "CA", "postalCode": "94105", "addressCountry": "US", "latitude": 37.472842, "longitude": -122.217144 }, "vertical": "FOODORDERING" } }
Beispiel 2: Preis einer Speisekarte aktualisieren
Angenommen, Sie müssen den Preis eines Menüpunkts ändern. Wie in Beispiel 1 muss Ihre Aktualisierung den JSON-Code für die gesamte übergeordnete Entität (das Menü) enthalten und der Feed verwendet das V1-Inventarschema.
Ein Batchfeed könnte so aussehen:
{ "@type": "MenuItemOffer", "@id": "menuitemoffer6680262", "sku": "offer-cola", "menuItemId": "menuitem896532", "price": 3.00, "priceCurrency": "USD" }
Die inkrementelle Aktualisierung per POST würde dann so aussehen:
POST v2/apps/provider-project/entities/MenuItemOffer/menuitemoffer6680262:push Host: actions.googleapis.com Content-Type: application/ld+json { "entity": { "data": { "@type": "MenuItemOffer", "@id": "menuitemoffer6680262", "sku": "offer-cola", "menuItemId": "menuitem896532", "price": 1.00, "priceCurrency": "USD" }, "vertical": "FOODORDERING" } }
Entität hinzufügen
Vermeiden Sie Inventaraktualisierungen, um Entitäten hinzuzufügen. Verwenden Sie stattdessen den Batchfeed-Prozess für das Inventarschema v2.
Entität entfernen
Wenn Sie Entitäten der obersten Ebene entfernen möchten, verwenden Sie einen leicht modifizierten Endpunkt und in der Anfrage HTTP DELETE anstelle von HTTP POST.
Verwenden Sie HTTP DELETE nicht zum Entfernen einer Unterentität innerhalb einer übergeordneten Entität, z. B. eines Menüelements in einem Menü. Stattdessen sollten Sie die Entfernung von Unterentitäten als Aktualisierung einer übergeordneten Entität behandeln, in der die Unterentität aus der entsprechenden Liste oder dem entsprechenden Parameter entfernt wird.
Beispiel 1: Element der obersten Ebene löschen
Angenommen, Sie möchten ein Restaurant in einem Feed löschen, der das Inventarschema von Version 1 verwendet. Sie müssen auch die zugehörigen Dienste und Menüs löschen.
Ein Beispielendpunkt für eine Menüentität mit der ID "https://www.provider.com/restaurant/menu/nr":
DELETE v2/apps/delivery-provider-id/entities/https%3A%2F%2Fwww.provider.com%2Frestaurant%2Fmenu%2Fnr?entity.vertical=FOODORDERING
Host: actions.googleapis.com
Beispielendpunkt für eine Restaurantentität mit der ID "https://www.provider.com/restaurant/nr":
DELETE v2/apps/delivery-provider-id/entities/https%3A%2F%2Fwww.provider.com%2Frestaurant%2Fnr?entity.vertical=FOODORDERING
Host: actions.googleapis.com
Beispielendpunkt für eine Dienstentität mit der ID "https://www.provider.com/restaurant/service/nr":
DELETE v2/apps/delivery-provider-id/entities/https%3A%2F%2Fwww.provider.com%2Frestaurant%2Fservice%2Fnr?entity.vertical=FOODORDERING
Host: actions.googleapis.com
}
Beispiel 2: Unterentitäten entfernen
Zum Entfernen einer Unterentität innerhalb einer übergeordneten Entität senden Sie die übergeordnete Entität, wobei die Unterentität aus dem entsprechenden Feld entfernt wird. Im folgenden Beispiel wird davon ausgegangen, dass der Feed das Inventarschema V1 verwendet.
Wenn Sie beispielsweise ein Einzugsgebiet entfernen möchten, entfernen Sie das Einzugsgebiet aus der Liste areaServed
.
POST v2/apps/delivery-provider-id/entities/https%3A%2F%2Fwww.provider.com%2Frestaurant%2Fservice%2Fnr:push
Host: actions.googleapis.com
Content-Type: application/ld+json
{
"entity": {
// Note: "data" is not serialized as a string in our example for readability.
"data": {
"@type": "Service",
"provider": {
"@type": "Restaurant",
"@id": "https://www.provider.com/restaurant/nr"
},
"areaServed": [
{
"@type": "GeoCircle",
"geoMidpoint": {
"@type": "GeoCoordinates",
"latitude": "42.362757",
"longitude": "-71.087109"
},
"geoRadius": "10000"
}
// area2 is removed.
]
...
},
"vertical": "FOODORDERING"
}
}
API-Antwortcodes
Ein erfolgreicher Aufruf bedeutet nicht, dass der Feed gültig oder korrekt ist, sondern nur, dass der API-Aufruf erfolgt ist. Erfolgreiche Aufrufe erhalten den HTTP-Antwortcode 200 sowie einen leeren Antworttext:
{}
Bei Fehlern ist der HTTP-Antwortcode nicht 200 und der Antworttext gibt an, was schiefgelaufen ist.
Wenn der Nutzer beispielsweise den Wert "vertical" im Envelope auf FAKE_VERTICAL
gesetzt hat, erhalten Sie die folgende Nachricht:
{
"error": {
"code": 400,
"message": "Invalid value at 'entity.vertical' (TYPE_ENUM), \"FAKE_VERTICAL\"",
"status": "INVALID_ARGUMENT",
"details": [
{
"@type": "type.googleapis.com/google.rpc.BadRequest",
"fieldViolations": [
{
"field": "entity.vertical",
"description": "Invalid value at 'entity.vertical' (TYPE_ENUM), \"FAKE_VERTICAL\""
}
]
}
]
}
}
Codebeispiel
Im Folgenden findest du einige Beispiele für die Verwendung der Incremental Updates API in verschiedenen Sprachen. In diesen Beispielen wird die Google-Authentifizierungsbibliotheken verwendet. Dabei wird davon ausgegangen, dass ein Feed das Inventarschema V1 verwendet. Alternative Lösungen finden Sie unter OAuth 2.0 für Server-zu-Server-Anwendungen verwenden.
Entitäten aktualisieren
Node.js
Dieser Code verwendet die Google-Authentifizierungsbibliothek für Node.js.
const {auth} = require('google-auth-library') const request = require('request'); // The service account client secret file downloaded from the Google Cloud Console const serviceAccountJson = require('./service-account.json') // entity.json is a file that contains the entity data in json format const entity = require('./entity.json') const ENTITY_ID = 'restaurant/http://www.provider.com/somerestaurant' const PROJECT_ID = 'your-project-id' /** * Get the authorization token using a service account. */ async function getAuthToken() { let client = auth.fromJSON(serviceAccountJson) client.scopes = ['https://www.googleapis.com/auth/assistant'] const tokens = await client.authorize() return tokens.access_token; } /** * Send an incremental update to update or add an entity */ async function updateEntity(entityId, entity) { const token = await getAuthToken() request.post({ headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, url: `https://actions.googleapis.com/v2/apps/${PROJECT_ID}/entities/${encodeURIComponent(entityId)}:push`, body: { entity: { data: JSON.stringify(entity), vertical: 'FOODORDERING', } }, json: true }, (err, res, body) => { if (err) { return console.log(err); } console.log(`Response: ${JSON.stringify(res)}`) }) } updateEntity(ENTITY_ID, entity)
Python
In diesem Code wird die Google-Authentifizierungsbibliothek für Python verwendet.
from google.oauth2 import service_account from google.auth.transport.requests import AuthorizedSession import json import urllib PROJECT_ID = 'your-project-id' ENTITY_ID = 'restaurant/http://www.provider.com/somerestaurant' ENDPOINT = 'https://actions.googleapis.com/v2/apps/%s/entities/%s:push' % ( PROJECT_ID, urllib.quote(ENTITY_ID, '')) # service-account.json is the service account client secret file downloaded from the # Google Cloud Console credentials = service_account.Credentials.from_service_account_file( 'service-account.json') scoped_credentials = credentials.with_scopes( ['https://www.googleapis.com/auth/assistant']) authed_session = AuthorizedSession(scoped_credentials) # Retrieving the entity update_file = open("entity.json") #JSON file containing entity data in json format. data = update_file.read() # Populating the entity with wrapper entity = {} entity['data'] = data #entity JSON-LD serialized as string entity['vertical'] = 'FOODORDERING' request = {} request['entity'] = entity response = authed_session.post(ENDPOINT, json=request) print(response.text) #if successful, will be '{}'
Java
Dieser Code verwendet die Google-Authentifizierungsbibliothek für Java.
private static final String PROJECT_ID = "your-project-id"; private static final String ENTITY_ID = "http://www.provider.com/somerestaurant"; /** * Get the authorization token using a service account. */ private static String getAuthToken() { InputStream serviceAccountFile = Example.class.getClassLoader().getResourceAsStream("service-account.json"); ServiceAccountCredentials.Builder credentialsSimpleBuilder = ServiceAccountCredentials.fromStream(serviceAccountFile).toBuilder(); credentialsSimpleBuilder.setScopes(ImmutableList.of("https://www.googleapis.com/auth/assistant")); AccessToken accessToken = credentialsSimpleBuilder.build().refreshAccessToken(); return accessToken.getTokenValue(); } /** * Send an incremental update to update or add an entity. * @param entityId The id of the entity to update. * @param entity the json of the entity to be updated. */ public void updateEntity(String entityId, JSONObject entity) { String authToken = getAuthToken(); String endpoint = String.format( "https://actions.googleapis.com/v2/apps/%s/entities/%s:push", PROJECT_ID, URLEncoder.encode(entityId, "UTF-8")); JSONObject data = new JSONObject(); data.put("data", entity.toString()); data.put("vertical", "FOODORDERING"); JSONObject jsonBody = new JSONObject(); jsonBody.put("entity", data); // Execute POST request executePostRequest(endpoint, authToken, jsonBody); }
Entitäten werden entfernt
Node.js
Dieser Code verwendet die Google-Authentifizierungsbibliothek für Node.js.
const {auth} = require('google-auth-library') const request = require('request'); // The service account client secret file downloaded from the Google Cloud Console const serviceAccountJson = require('./service-account.json') // entity.json is a file that contains the entity data in json format const entity = require('./entity.json') const ENTITY_ID = 'restaurant/http://www.provider.com/somerestaurant' const PROJECT_ID = 'your-project-id' /** * Get the authorization token using a service account. */ async function getAuthToken() { let client = auth.fromJSON(serviceAccountJson) client.scopes = ['https://www.googleapis.com/auth/assistant'] const tokens = await client.authorize() return tokens.access_token; } /** * Send an incremental update to delete an entity */ async function deleteEntity(entityId) { const token = await getAuthToken() request.delete({ headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, url: `https://actions.googleapis.com/v2/apps/${PROJECT_ID}/entities/${encodeURIComponent(entityId)}?entity.vertical=FOODORDERING`, body: {}, json: true }, (err, res, body) => { if (err) { return console.log(err); } console.log(`Response: ${JSON.stringify(res)}`) }) } deleteEntity(ENTITY_ID)
Python
In diesem Code wird die Google-Authentifizierungsbibliothek für Python verwendet.
from google.oauth2 import service_account from google.auth.transport.requests import AuthorizedSession import json import urllib # Service config PROJECT_ID = 'your-project-id' ENTITY_ID = 'restaurant/http://www.provider.com/somerestaurant' DELETE_TIME = '2018-04-07T14:30:00-07:00' ENDPOINT = 'https://actions.googleapis.com/v2/apps/%s/entities/%s?entity.vertical=FOODORDERING&delete_time=%s' % ( PROJECT_ID, urllib.quote(ENTITY_ID, ''), urllib.quote(DELETE_TIME, '')) # service-account.json is the service account client secret file downloaded from the # Google Cloud Console credentials = service_account.Credentials.from_service_account_file( 'service-account.json') scoped_credentials = credentials.with_scopes( ['https://www.googleapis.com/auth/assistant']) authed_session = AuthorizedSession(scoped_credentials) response = authed_session.delete(ENDPOINT) print(response.text) #if successful, will be '{}'
Java
Dieser Code verwendet die Google-Authentifizierungsbibliothek für Java.
private static final String PROJECT_ID = "your-project-id"; private static final String ENTITY_ID = "restaurant/http://www.provider.com/somerestaurant"; /** * Get the authorization token using a service account. */ private static String getAuthToken() { InputStream serviceAccountFile = Example.class.getClassLoader().getResourceAsStream("service-account.json"); ServiceAccountCredentials.Builder credentialsSimpleBuilder = ServiceAccountCredentials.fromStream(serviceAccountFile).toBuilder(); credentialsSimpleBuilder.setScopes(ImmutableList.of("https://www.googleapis.com/auth/assistant")); AccessToken accessToken = credentialsSimpleBuilder.build().refreshAccessToken(); return accessToken.getTokenValue(); } /** * Send an incremental update to delete an entity. * @param entityId The id of the entity to delete. */ public void deleteEntity(String entityId) { String authToken = getAuthToken(); String endpoint = String.format( "https://actions.googleapis.com/v2/apps/%s/entities/%s?entity.vertical=FOODORDERING", PROJECT_ID, URLEncoder.encode(entityId, "UTF-8")); // Execute DELETE request System.out.println(executeDeleteRequest(endpoint, authToken)); }
Anwendungsfälle
Die folgenden Anwendungsfälle sind Beispiele für inkrementelle Updates, vollständige Feedaktualisierungen und den allgemeinen Inhalt des API-Aufrufs:
Szenario | Entität auf oberster Ebene | Beschreibung und Effekte |
---|---|---|
Dienst deaktivieren | DisabledService |
Sie müssen einen Dienst aus unvorhergesehenen Gründen deaktivieren. Inkrementelle Aktualisierungen: Senden Sie die betreffende Vollständige Feeds:Du musst die Entität aus den vollständigen Feeds aktualisieren, damit |
Ein bestimmter Artikel ist nicht auf Lager | Menu |
Inkrementelle Aktualisierungen:Die kapselnde Menu -Entität wird gesendet, wobei offer.inventoryLevel für die angegebene MenuItem auf 0 gesetzt ist. Alle anderen Daten bleiben unverändert. |
Preisänderung für Menüpunkt | Menu |
Inkrementelle Aktualisierungen:Die kapselnde Menu -Entität wird gesendet, wobei offer.price auf den aktualisierten Preis für die angegebene MenuItem festgelegt ist. Alle anderen Daten bleiben unverändert. |
Neues Element auf oberster Ebene hinzufügen Gilt nur für die Entitätstypen vom Typ |
Menu , Restaurant , Service |
Beispielsweise müssen Sie einem Restaurant eine neue Speisekarte hinzufügen. Zusätzliche Updates:Die neue Speisekarte auf der Speisekarte wird zusammen mit der Restaurantentität mit dem Feld |
Entität auf oberster Ebene endgültig löschen Gilt nur für die Entitätstypen vom Typ |
Menu , Restaurant , Service |
Zusätzliche Updates: Sende eine explizite Löschung. Vollständige Feeds: Entfernen Sie die Entität vor dem nächsten Abruf durch Google aus den vollständigen Feeds. Andernfalls wird sie neu hinzugefügt. |
Einen neuen Lieferbereich für eine bestimmte Service hinzufügen |
Service |
Inkrementelle Feeds:Sendet die betreffende Service -Entität, wobei alle zugehörigen Felder intakt sind, wie in den vollständigen Feeds, wobei innerhalb von areaServed der Service ein neuer Lieferbereich angegeben wird. |
Voraussichtliche Ankunftszeit in Service aktualisieren |
Service |
Inkrementelle Feeds: Sendet die Service wie in den Feeds, außer dass hoursAvailable.deliveryHours entsprechend aktualisiert wird. |
Lieferpreise in Service aktualisieren |
Service |
Inkrementelle Feeds:Vollständige Service mit aktualisierter offers.priceSpecification.price senden. |
Liefer- oder Abholzeiten in Service aktualisieren |
Service |
Inkrementelle Feeds:Sendet die Service wie in den Feeds, außer dass hoursAvailable entsprechend aktualisiert wird. |
Service (Mindestbestellwert ändern) |
Service |
Inkrementelle Feeds: Vollständige Service mit aktualisiertem Service.offers.priceSpecification.eligibleTransactionVolume senden |
MenuItem endgültig löschen |
Menu |
Inkrementelle Feeds:Sendet die Menu wie in den Feeds, wobei dieses MenuItem jedoch aus der Liste hasMenuItems entfernt wird. |
SLO für die Verarbeitungszeit für Batchjobs und inkrementelle Updates
Eine Entität, die durch ein Batch- oder inkrementelles Update hinzugefügt wurde, wird in 1 bis 2 Tagen verarbeitet. Eine Entität, die über einen Batch aktualisiert oder gelöscht wird, wird in 2 Stunden verarbeitet, eine Entität, die durch ein inkrementelles Update aktualisiert wird, in 5 Minuten. Ein veraltetes Element wird in 7 Tagen gelöscht.
Dazu haben Sie folgende Möglichkeiten:
- Mehrere Batchjobs pro Tag, um Ihr Inventar auf dem neuesten Stand zu halten ODER
- Ein Batch-Job pro Tag und inkrementelle APIs, um Ihr Inventar auf dem neuesten Stand zu halten