In diesem Abschnitt wird beschrieben, wie Sie zeitkritische Aktualisierungen Ihrer Inventarelemente an Google senden. Mit der Incremental Update API können Sie Aktualisierungen pushen und Entitäten in Ihrem Sandbox- oder Produktionsinventar nahezu in Echtzeit löschen.
Diese Funktion ist in erster Linie für Aktualisierungen gedacht, die Sie nicht vorhersehen können, z. B. Schließungen aufgrund von Notfällen. Änderungen, die über die Incremental Update API eingereicht werden, sollten in der Regel innerhalb einer Stunde veröffentlicht werden. Wenn die Änderung nicht sofort übernommen werden muss, können Sie stattdessen die Batchaufnahme verwenden. Inkrementenelle Updates werden innerhalb von maximal fünf Minuten verarbeitet.
Vorbereitung
Bevor Sie inkrementelle Updates implementieren, sind die folgenden Elemente erforderlich:
- Es wird ein Dienstkonto mit der Rolle „Bearbeiter“ für Ihr Actions-Projekt erstellt. Weitere Informationen finden Sie unter Projekt erstellen und einrichten.
- Produktions- oder Sandbox-Datenfeeds werden gehostet und aufgenommen. Weitere Informationen finden Sie unter Batch-Aufnahme.
- Optional, aber empfohlen: Installieren Sie die Google-Clientbibliothek in der Sprache Ihrer Wahl, um die Verwendung von OAuth 2.0 beim Aufrufen der API zu vereinfachen. In den folgenden Codebeispielen werden diese Bibliotheken verwendet. Andernfalls müssen Sie den Token-Austausch manuell vornehmen, wie unter OAuth 2.0 für den Zugriff auf Google APIs verwenden beschrieben.
Endpunkte
Ersetzen Sie in den folgenden 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: Der Entitätstyp (
@type
-Property) des Objekts in Ihrem Datenfeed, das Sie aktualisieren möchten. - ENTITY_ID (nur Endpunkt zum Löschen): ID der zu löschenden Entität. Die Entitäts-ID muss URL-codiert sein.
- DELETE_TIME (nur Löschendpunkt): Optionales Feld, das angibt, wann die Entität in Ihren Systemen gelöscht wurde. Standardmäßig ist das der Zeitpunkt, an dem die Anfrage empfangen wurde. Der Zeitwert darf nicht in der Zukunft liegen. Wenn eine Entität über einen inkrementellen Aufruf gesendet wird, wird bei der Entitätsversionierung auch das Feld
delete_time
für einen Löschaufruf verwendet. Diesen Wert alsyyyy-mm-ddTHH:mm:ssZ
formatieren
Endpunkt aktualisieren
Wenn Sie eine Entität ändern möchten, senden Sie eine HTTP-POST-Anfrage an den folgenden Endpunkt und fügen Sie eine Nutzlast mit Änderungen und Ergänzungen ein. Sie können mit einem einzigen API-Aufruf bis zu 1.000 Entitäten aktualisieren.
https://actions.googleapis.com/v2/apps/PROJECT_ID/entities:batchPush
Wenn Sie beispielsweise Entitäten in einem Projekt mit der ID „delivery-provider-id“ aktualisieren möchten, lautet der Endpunkt:
https://actions.googleapis.com/v2/apps/delivery-provider-id/entities:batchpush
Endpunkt löschen
Wenn du eine Entität in deinem Inventar löschen möchtest, sende eine HTTP-DELETE-Anfrage an den folgenden Endpunkt.
https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/TYPE/ENTITY_ID?entity.vertical=FOODORDERING&delete_time=DELETE_TIME
Wenn Sie beispielsweise eine „Menübereich“-Entität mit der ID „menuSection_122“ aus Ihrem Projekt „delivery-provider-id“ löschen möchten, senden Sie einen HTTP DELETE API-Aufruf an:
https://actions.googleapis.com/v2/apps/delivery-provider-id/entities/MenuSection/menuSection_122?entity.vertical=FOODORDERING
Sandbox-Umgebung
Wenn Sie die API für inkrementelle Updates in Ihrem Sandbox-Inventar verwenden möchten, folgen Sie der Anleitung unter Endpunkte, senden Sie aber Anfragen an /v2/sandbox/apps/
statt an /v2/apps/
.
https://actions.googleapis.com/v2/sandbox/apps/PROJECT_ID/entities:batchPush
https://actions.googleapis.com/v2/sandbox/apps/PROJECT_ID/entities/TYPE/ENTITY_ID?entity.vertical=FOODORDERING&delete_time=DELETE_TIME
Entitäten aktualisieren
Jede POST-Anfrage muss die Anfrageparameter sowie die JSON-Nutzlast mit den strukturierten Daten aller im Inventarschema aufgeführten Entitätstypen enthalten.
Nutzlast aktualisieren
Die JSON-Datei sollte wie im Batchfeed aussehen, mit den folgenden Unterschieden:
- Der Payload-Body darf nicht größer als 5 MB sein. Ähnlich wie bei Batchfeeds empfehlen wir, Lücken zu entfernen, damit mehr Daten passen.
- Der Umschlag sieht so aus:
{ "requests": [ { "entity": { "data":"ENTITY_DATA", "name": "apps/project_id>/entities/type/entity_id" }, "update_time":"UPDATE_TIMESTAMP" }, ], "vertical": "FOODORDERING" }
Ersetzen Sie in der obigen Nutzlast Folgendes:
- ENTITY_DATA: Entität im JSON-Format, die als String serialisiert ist. Die JSON-LD-Entität muss als String im Feld
data
übergeben werden. - UPDATE_TIMESTAMP (optional): Zeitstempel, zu dem 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. Wenn eine Entität über eine inkrementelle Anfrage gesendet wird, wird bei der Entitätsversionierung auch das Feld
update_time
für eine Anfrage zum Hinzufügen oder Aktualisieren verwendet.
Beispiele
Beispiel 1: Restaurant aktualisieren
Angenommen, Sie müssen dringend die Telefonnummer eines Restaurants aktualisieren. Ihre Aktualisierung enthält die JSON-Datei für das gesamte Restaurant.
Angenommen, Sie haben einen Batchfeed, der so aussieht:
{ "@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 }
Die inkrementelle Aktualisierung per HTTP POST würde dann so aussehen:
POST v2/sandbox/apps/provider-project/entities:batchPush Host: actions.googleapis.com Content-Type: application/ld+json { "requests": [ { "entity": { "name": "apps/provider-project/entities/restaurant/restaurant12345", "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: Mehrere Restaurants aktualisieren
Wenn Sie zwei Restaurantentitäten in einem einzigen API-Aufruf aktualisieren möchten, sieht die HTTP-POST-Anfrage so aus:
POST v2/sandbox/apps/provider-project/entities:batchPush Host: actions.googleapis.com Content-Type: application/ld+json { "requests": [ { "entity": { "name": "apps/provider-project/entities/restaurant/restaurant12345", "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 } } }, { "entity": { "name": "apps/provider-project/entities/restaurant/restaurant123", "data": { "@type": "Restaurant", "@id": "restaurant123", "name": "Some Other Restaurant", "url": "https://www.provider.com/somerestaurant", "telephone": "+16501231235", "streetAddress": "385 Spear St", "addressLocality": "San Mateo", "addressRegion": "CA", "postalCode": "94115", "addressCountry": "US" } } } ] "vertical": "FOODORDERING" }
Beispiel 3: Preis eines Menüpunkts aktualisieren
Angenommen, Sie möchten den Preis eines Menüpunkts ändern. Wie in Beispiel 1 muss Ihre Aktualisierung die JSON-Datei für die gesamte Entität der obersten Ebene (das Menü) enthalten und der Feed muss das Inventarschema v1 verwenden.
Angenommen, Sie haben einen Batchfeed, der so aussieht:
{ "@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/sandbox/apps/provider-project/entities:batchPush Host: actions.googleapis.com Content-Type: application/ld+json { "requests": [ { "entity": { "name": "apps/provider-project/entities/menuitemoffer/menuitemoffer6680262", "data": { "@type": "MenuItemOffer", "@id": "menuitemoffer6680262", "sku": "offer-cola", "menuItemId": "menuitem896532", "price": 1.00, "priceCurrency": "USD" }, "vertical": "FOODORDERING" } } ] "vertical": "FOODORDERING" }
Entität hinzufügen
Verwenden Sie zum Hinzufügen von Entitäten keine Inventaraktualisierungen. Verwenden Sie stattdessen den Batchfeed-Prozess, wie für das Inventarschema v2 beschrieben.
Entität entfernen
Wenn Sie Entitäten der obersten Ebene entfernen möchten, verwenden Sie einen leicht geänderten Endpunkt und HTTP DELETE anstelle von HTTP POST in der Anfrage.
Entität der obersten Ebene löschen
Angenommen, Sie möchten ein Restaurant in einem Feed löschen. Außerdem müssen Sie die zugehörigen Dienste und Menüs löschen.
Beispiel für einen Endpunkt für eine Menüentität mit der ID „provider/restaurant/menu/nr“:
DELETE v2/apps/delivery-provider-id/entities/menu/provider%2Frestaurant%2Fmenu%2Fnr?entity.vertical=FOODORDERING
Host: actions.googleapis.com
Beispiel für einen Endpunkt für eine Restaurantentität mit der ID „https://www.provider.com/restaurant/nr“:
DELETE v2/apps/delivery-provider-id/entities/restaurant/provider%2Frestaurant%2Fnr?entity.vertical=FOODORDERING
Host: actions.googleapis.com
Beispiel für einen Endpunkt für eine Dienstentität mit der ID „https://www.provider.com/restaurant/service/nr“:
DELETE v2/apps/delivery-provider-id/entities/service/provider%2Frestaurant%2Fservice%2Fnr?entity.vertical=FOODORDERING
Host: actions.googleapis.com
}
Untergeordnete Entitäten entfernen
Verwenden Sie HTTP DELETE nicht, um eine untergeordnete Entität innerhalb einer übergeordneten Entität zu entfernen, z. B. ein Menüelement in einem Menü. Behandeln Sie das Entfernen von untergeordneten Entitäten stattdessen als Aktualisierung einer Entität auf oberster Ebene, bei der die untergeordnete Entität aus der entsprechenden Liste oder reverseReference entfernt wird.
API-Antwortcodes
Ein erfolgreicher Aufruf bedeutet nicht, dass der Feed gültig oder korrekt ist, sondern nur, dass der API-Aufruf erfolgt ist. Bei erfolgreichen Aufrufen wird der HTTP-Antwortcode 200 zusammen mit einem leeren Antworttext zurückgegeben:
{}
Bei Fehlern ist der HTTP-Antwortcode nicht 200 und im Antworttext wird angegeben, was schiefgelaufen ist.
Wenn der Nutzer beispielsweise den Wert „vertical“ im Umschlag auf FAKE_VERTICAL
festgelegt 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
Unten finden Sie einige Beispiele für die Verwendung der Incremental Update API in verschiedenen Sprachen. In diesen Beispielen werden die Google Auth-Bibliotheken verwendet und es wird davon ausgegangen, dass ein Feed das Inventarschema v1 verwendet. Informationen zu alternativen Lösungen finden Sie unter OAuth 2.0 für Server-zu-Server-Anwendungen verwenden.
Entitäten aktualisieren
Node.js
In diesem Code wird die Google Auth-Bibliothek für Node.js verwendet.
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 = 'your/entity/id' const PROJECT_ID = 'type/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(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:batchPush`, body: { requests: [ { entity: { data: JSON.stringify(entity) name: `apps/${PROJECT_ID}/entities/${ENTITY_ID}` } } ], vertical: 'FOODORDERING' }, json: true }, (err, res, body) => { if (err) { return console.log(err); } console.log(`Response: ${JSON.stringify(res)}`) }) } updateEntity(entity)
Python
In diesem Code wird die Google Auth-Bibliothek 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 = 'type/your/entity/id' ENDPOINT = 'https://actions.googleapis.com/v2/apps/%s/entities:batchPush' % ( PROJECT_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() entity = {} entity['data'] = data #entity JSON-LD serialized as string entity['name'] = 'apps/%s/entities/%s' % (PROJECT_ID, urllib.quote(ENTITY_ID, '') ) # Populating the request request = {} request['entity'] = entity requestArray = [request] # Populating the payload payload = {} payload['requests'] = requestArray payload['vertical'] = 'FOODORDERING' response = authed_session.post(ENDPOINT, json=payload) print(response.text) #if successful, will be '{}'
Java
In diesem Code wird die Google Auth-Bibliothek für Java verwendet.
private static final String PROJECT_ID = "your-project-id"; private static final String ENTITY_ID = "type/your-entity-id"; /** * 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 data) { String authToken = getAuthToken(); String endpoint = String.format("https://actions.googleapis.com/v2/apps/%s/entities/:batchPush", PROJECT_ID); JSONObject entity = new JSONObject(); entity.put("data", data.toString()); entity.put("name", String.format("apps/%s/entities/%s", PROJECT_ID, URLEncoder.encode(ENTITY_ID, "UTF-8"))); JSONObject request = new JSONObject(); request.put("entity", entity); JSONArray requestArray = new JSONArray(); requestArray.put(request); JSONObject payload = new JSONObject(); payload.put("requests", requestArray); payload.put("vertical", FOODORDERING); // Execute POST request executePostRequest(endpoint, authToken, payload); }
Entitäten entfernen
Node.js
In diesem Code wird die Google Auth-Bibliothek für Node.js verwendet.
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 Auth-Bibliothek 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
In diesem Code wird die Google Auth-Bibliothek für Java verwendet.
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 Aktualisierungen, vollständige Feedaktualisierungen und den Inhalt auf hoher Ebene im API-Aufruf:
Szenario | Zu aktualisierende Entität | Beschreibung und Auswirkungen |
---|---|---|
Dienst deaktivieren | Service |
Sie müssen einen Dienst aus unvorhergesehenen Gründen deaktivieren. Inkrementelle Updates:Aktualisieren Sie die betreffende Vollständige Feeds:Aktualisieren Sie die Entität aus den vollständigen Feeds, damit |
Bestimmter Artikel nicht auf Lager | MenuItemOffer |
Inkrementelle Updates:Senden Sie die umschließende MenuItemOffer -Entität mit inventoryLevel = 0 für die angegebene MenuItem und alle anderen Daten unverändert. |
Preisänderung für Menüpunkt | MenuItemOffer |
Inkrementelle Aktualisierungen: Senden Sie die umschließende MenuItemOffer -Entität, wobei price auf den aktualisierten Preis für die angegebene MenuItem festgelegt ist und alle anderen Daten unverändert bleiben. |
Neue Entität der obersten Ebene hinzufügen Nur für Entitäten der Typen |
Menu , Restaurant , Service |
Beispiel: Sie müssen einem Restaurant ein neues Menü hinzufügen. Vollständige Feeds:Fügen Sie die Entität Ihren Datenfeeds hinzu und warten Sie auf die Batchaufnahme. |
Entität der obersten Ebene endgültig löschen Nur für Entitäten der Typen |
Menu , Restaurant , Service |
Inkrementelle Aktualisierungen:Senden Sie ein explizites Löschen. Vollständige Feeds:Entfernen Sie die Entität vor dem nächsten Abruf durch Google aus den vollständigen Feeds. Andernfalls wird sie wieder hinzugefügt. |
Neues Liefergebiet in einer bestimmten Service hinzufügen |
ServiceArea |
Inkrementelle Feeds:Senden Sie die betreffende ServiceArea -Entität mit allen ihren Feldern wie gewohnt in den vollständigen Feeds, wobei das neue Auslieferungsgebiet in polygon , geoRadius oder postalCode angegeben wird. |
Voraussichtliche Zustellung am Service aktualisieren |
ServiceHours |
Inkrementelle Feeds:Senden Sie den ServiceHours wie in den Feeds, mit der Ausnahme, dass sein leadTimeMin entsprechend aktualisiert wird. |
Lieferpreise in Service aktualisieren |
Fee |
Inkrementelle Feeds:Senden Sie die vollständige Übermittlung Fee mit aktualisiertem price . |
Liefer- oder Abholzeiten in Service aktualisieren |
ServiceHours |
Inkrementelle Feeds:Senden Sie die ServiceHours genau wie in den Feeds, mit der Ausnahme, dass die opens - und closes -Properties entsprechend aktualisiert werden. |
Service (Mindestbestellwert ändern) |
Fee |
Inkrementelle Feeds:Senden Sie den vollständigen Fee mit minPrice aktualisiert. |
MenuItem endgültig löschen |
Menu |
Inkrementelle Feeds:Geben Sie MenuItem wie in den Feeds an, aber lassen Sie parentMenuSectionId leer.
|
SLO für die Verarbeitungszeit von Batchjobs und inkrementellen Updates
Ein über einen Batch aktualisierter oder gelöschter Rechtssubjekt wird im Best-Effort-Verfahren innerhalb von zwei Stunden verarbeitet. Ein über eine inkrementelle Aktualisierung aktualisierter Rechtssubjekt wird innerhalb von fünf Minuten verarbeitet. Ein veraltete Entität wird nach 7 Tagen gelöscht.
Sie können Google Folgendes senden:
- Mehrere Batchjobs pro Tag, um Ihr Inventar auf dem neuesten Stand zu halten, ODER
- Ein Batchjob pro Tag und inkrementelle APIs, um Ihr Inventar auf dem neuesten Stand zu halten.