snapshot of https://github.com/twentyhq/twenty.git (main, 2026-09-17; blobs > 131072B omitted)
Some checks failed
App Prod-Parity E2E Dispatch / dispatch (push) Failing after 10s
CD Storybook UI / build (push) Failing after 3m25s
CD Storybook UI / dispatch (push) Has been skipped
CD deploy main / website-changed-files (push) Successful in 18m8s
CI Agent Skills / changed-files-check (push) Successful in 18m9s
CI Create App E2E minimal / changed-files-check (push) Successful in 24s
CI Create App / changed-files-check (push) Successful in 26s
CI Docs / changed-files-check (push) Successful in 26s
CI Emails / changed-files-check (push) Successful in 28s
CI Example App Hello World / changed-files-check (push) Successful in 23s
CI Front / changed-files-check (push) Has been skipped
CI Example App Postcard / changed-files-check (push) Successful in 27s
CI UI / changed-files-check (push) Has been skipped
CI Utils Test / changed-files-check (push) Successful in 45s
CI Twenty Apps / discover (push) Successful in 1m3s
CD deploy main / deploy-main (push) Failing after 3s
CI Agent Skills / agent-skills-validate (push) Has been skipped
CI Create App / create-app-test (lint) (push) Has been skipped
CI Emails / emails-test (push) Has been skipped
CI Front / front-task (lingui:compile) (push) Has been skipped
CI Front / front-task (lint) (push) Has been skipped
CI Example App Postcard / example-app-postcard (push) Has been skipped
CI UI / ui-task (lint) (push) Has been skipped
CI UI / ui-task (pack-size) (push) Has been skipped
CI UI / ui-task (size) (push) Has been skipped
CI UI / ui-task (test) (push) Has been skipped
CI UI / ui-task (typecheck) (push) Has been skipped
CI Utils Test / utils-test (push) Has been skipped
CI Twenty Apps / ${{ matrix.app.name }} (push) Has been skipped
CI Emails / ci-emails-status-check (push) Successful in 2s
CI Example App Hello World / ci-example-app-hello-world-status-check (push) Successful in 2s
CI Example App Postcard / ci-example-app-postcard-status-check (push) Successful in 3s
CI UI / ui-sb-test (push) Has been skipped
CI Utils Test / ci-utils-test-status-check (push) Successful in 2s
CI Twenty Apps / ci-twenty-apps-status-check (push) Successful in 2s
CI UI / ci-ui-status-check (push) Successful in 2s
CI Desktop / desktop (push) Failing after 1m8s
Push docs to Crowdin / Push documentation to Crowdin (push) Failing after 55s
Push translations to Crowdin / Extract and upload translations (push) Failing after 5s
Push website translations to Crowdin / Extract and upload website translations (push) Failing after 5s
CI Create App / create-app-test (test) (push) Has been skipped
CI Create App / create-app-test (typecheck) (push) Has been skipped
CI Docs / docs-lint (push) Has been skipped
CI Example App Hello World / example-app-hello-world (push) Has been skipped
CI Front / front-task (lingui:extract) (push) Has been skipped
CI Front / front-task (test) (push) Has been skipped
CI Front / front-task (typecheck) (push) Has been skipped
CI UI / ui-sb-build (push) Failing after 1m32s
CI Twenty Apps / ${{ matrix.app.name }} (${{ matrix.server-source }}) (push) Has been skipped
CI Agent Skills / agent-skills-publish (push) Has been skipped
CI Create App / ci-create-app-status-check (push) Successful in 2s
CI Agent Skills / agent-skills-remote-source (push) Has been skipped
CI Create App E2E minimal / create-app-e2e-minimal (push) Has been cancelled
CI E2E Main / e2e-test (push) Has been cancelled
CI Front / front-sb-build (push) Has been cancelled
CI Front / front-build (push) Has been cancelled
CI Create App E2E minimal / ci-create-app-e2e-minimal-status-check (push) Has been cancelled
CI E2E Main / ci-e2e-main-status-check (push) Has been cancelled
CI E2E Main / notify-main-ci-failure (push) Has been cancelled
CI E2E Main / qa-scout-comment (push) Has been cancelled
CI Front / front-sb-test (push) Has been cancelled
CI Front / front-sb-screenshots (push) Has been cancelled
CI Front / ci-front-status-check (push) Has been cancelled
DPA Sub-Processor Sync / sync-subprocessors (push) Failing after 3s
AI Catalog Sync / sync-catalog (push) Failing after 2s

This commit is contained in:
upstream-mirror
2026-09-17 23:28:13 +05:00
commit e7da97194a
32688 changed files with 4208681 additions and 0 deletions

View File

@@ -0,0 +1,82 @@
---
title: Arrays in Code-Aktionen verarbeiten
description: Erfahren Sie, wie Sie Array-Eingaben in Code-Aktionen innerhalb von Workflows korrekt verarbeiten.
---
Bei der Arbeit mit Arrays in Code-Aktionen stoßen Sie möglicherweise auf zwei häufige Herausforderungen:
1. **Als Strings übergebene Arrays** — Daten aus externen Systemen oder vorherigen Schritten kommen als String statt als echtes Array an
2. **Einzelne Elemente nicht auswählbar** — Sie können nur das gesamte Array auswählen, nicht bestimmte Felder darin
Beides lässt sich mit einem Code-Knoten lösen.
## Arrays aus Strings parsen
Arrays werden zwischen Workflow-Schritten häufig als Strings oder JSON übergeben, statt als native Arrays. Dies geschieht, wenn:
* Empfangen von Daten aus externen APIs über HTTP Request
* Verarbeiten von Webhook-Payloads
* Weitergeben von Daten zwischen Workflow-Schritten
**Lösung**: Fügen Sie dieses Muster am Anfang Ihrer Code-Aktion hinzu:
```javascript
export const main = async (params: {
users: any;
}): Promise<object> => {
const { users } = params;
// Handle input that may come as a string or an array
const usersFormatted = typeof users === "string" ? JSON.parse(users) : users;
// Now you can safely work with usersFormatted as an array
return {
users: usersFormatted.map((user) => ({
...user,
activityStatus: String(user.activityStatus).toUpperCase(),
})),
};
};
```
Die entscheidende Zeile `typeof users === "string" ? JSON.parse(users) : users` prüft, ob die Eingabe ein String ist, parst sie bei Bedarf oder verwendet sie direkt, wenn sie bereits ein Array ist.
## Einzelne Felder aus Arrays extrahieren
Ein Webhook kann ein Array wie `answers: [...]` zurückgeben, aber in nachfolgenden Workflow-Schritten können Sie nur das **gesamte Array** auswählen — nicht einzelne Elemente darin.
**Lösung**: Fügen Sie einen Code-Knoten hinzu, um bestimmte Felder zu extrahieren und als strukturiertes Objekt zurückzugeben:
```javascript
export const main = async (params: {
answers: any;
}): Promise<object> => {
const { answers } = params;
// Handle input that may come as a string or an array
const answersFormatted = typeof answers === "string"
? JSON.parse(answers)
: answers;
// Extract specific fields from the array
const firstname = answersFormatted[0]?.text || "";
const name = answersFormatted[1]?.text || "";
return {
answer: {
firstname,
name
}
};
};
```
Der Code-Knoten gibt statt eines Arrays ein strukturiertes Objekt zurück. In den folgenden Schritten können Sie nun einzelne Felder wie `answer.firstname` und `answer.name` aus der Variablenauswahl auswählen.
<Tip>
**Möchten Sie über das Array iterieren, anstatt Felder zu extrahieren?** Wenn ein Code- oder Logikfunktionsschritt ein Array auf oberster Ebene zurückgibt, können Sie es direkt in einen [Iterator](/l/de/user-guide/workflows/capabilities/use-iterator) einspeisen: Wählen Sie die Option **Whole list** des Schritts als Eingabe des Iterators und verweisen Sie dann innerhalb der Schleife mit `{{iterator.currentItem}}` auf jedes Element. In diesem Fall müssen Sie das Array nicht in ein Objekt umstrukturieren.
</Tip>
<Tip>
Klicken Sie auf das quadratische Symbol oben rechts im Code-Editor, um ihn im Vollbild anzuzeigen — hilfreich, da die Standardbreite des Editors begrenzt ist.
</Tip>

View File

@@ -0,0 +1,182 @@
---
title: Produktdaten in Twenty importieren
description: Synchronisieren Sie Produktkatalogdaten nach Zeitplan aus einem Data Warehouse in Ihr CRM.
---
Verwenden Sie dieses Muster, um Twenty mit Produktdaten aus Ihrem Data Warehouse (z. B. Snowflake, BigQuery, PostgreSQL) synchron zu halten.
## Workflow-Struktur
1. **Auslöser**: Nach Zeitplan
2. **Code**: Ihr Data Warehouse abfragen
3. **Code** (optional): Daten als Array formatieren
4. **Iterator**: Jedes Produkt durchlaufen
5. **Upsert Record**: In Twenty erstellen oder aktualisieren
<img src="/images/user-guide/workflows/create_users_workflow.png" style={{width:'100%'}} />
## Schritt 1: Auslöser planen
Stellen Sie den Workflow so ein, dass er mit einer Häufigkeit läuft, die Ihren Anforderungen an die Datenaktualität entspricht:
* Alle 5 Minuten für eine nahezu Echtzeit-Synchronisierung
* Stündlich für weniger kritische Daten
* Täglich für Batch-Updates
## Schritt 2: Ihr Data Warehouse abfragen
Fügen Sie eine **Code**-Aktion hinzu, um aktuelle Daten abzurufen:
```javascript
export const main = async () => {
const intervalMinutes = 10; // Match your schedule frequency
const cutoffTime = new Date(Date.now() - intervalMinutes * 60 * 1000).toISOString();
// Replace with your actual data warehouse connection
const response = await fetch("https://your-warehouse-api.com/query", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
query: `
SELECT id, name, sku, price, stock_quantity, updated_at
FROM products
WHERE updated_at >= '${cutoffTime}'
`
})
});
const data = await response.json();
return { products: data.results };
};
```
<Tip>
Filtern Sie nach `updated_at >= last X minutes`, um nur kürzlich geänderte Datensätze abzurufen. So bleibt die Synchronisierung effizient.
</Tip>
## Schritt 3: Daten formatieren (optional)
Wenn Ihr Data Warehouse Daten in einem Format zurückgibt, das transformiert werden muss, fügen Sie eine weitere **Code**-Aktion hinzu. Häufige Transformationen umfassen Typkonvertierungen, Feldumbenennungen und Datenbereinigung.
### Beispiel: Benutzerdaten mit booleschen und Statusfeldern
```javascript
export const main = async (params: {
users: any;
}): Promise<object> => {
const { users } = params;
const usersFormatted = typeof users === "string" ? JSON.parse(users) : users;
// Convert string "true"/"false" to actual booleans
const toBool = (v: any) => v === true || v === "true";
return {
users: usersFormatted.map((user) => ({
...user,
activityStatus: String(user.activityStatus).toUpperCase(),
isActiveLast30d: toBool(user.isActiveLast30d),
isActiveLast7d: toBool(user.isActiveLast7d),
isActiveLast24h: toBool(user.isActiveLast24h),
isTwenty: toBool(user.isTwenty),
})),
};
};
```
### Beispiel: Produktdaten mit Typkonvertierungen
```javascript
export const main = async (params: { products: any }) => {
const products = typeof params.products === "string"
? JSON.parse(params.products)
: params.products;
return {
products: products.map(product => ({
externalId: product.id,
name: product.name,
sku: product.sku,
price: parseFloat(product.price), // String → Number
stockQuantity: parseInt(product.stock_quantity),
isActive: product.status === "active" // String → Boolean
}))
};
};
```
### Beispiel: Datums- und Währungsformatierung
```javascript
export const main = async (params: { deals: any }) => {
const deals = typeof params.deals === "string"
? JSON.parse(params.deals)
: params.deals;
return {
deals: deals.map(deal => ({
...deal,
// Convert Unix timestamp to ISO date
closedAt: deal.closed_timestamp
? new Date(deal.closed_timestamp * 1000).toISOString()
: null,
// Ensure amount is a number (remove currency symbols)
amount: parseFloat(String(deal.amount).replace(/[^0-9.-]/g, "")),
// Normalize stage names
stage: deal.stage?.toLowerCase().replace(/_/g, " ")
}))
};
};
```
### Häufige Transformationen
| Quellformat | Zielformat | Code |
| -------------------- | ---------------- | ---------------------------------------- |
| `"true"` / `"false"` | `true` / `false` | `v === true \|\| v === "true"` |
| `"123.45"` | `123.45` | `parseFloat(value)` |
| `"active"` | `"ACTIVE"` | `value.toUpperCase()` |
| `1704067200` (Unix) | ISO-Datum | `new Date(v * 1000).toISOString()` |
| `"$1,234.56"` | `1234.56` | `parseFloat(v.replace(/[^0-9.-]/g, ""))` |
| `null` / `undefined` | `""` | `value \|\| ""` |
## Schritt 4: Durch die Produkte iterieren
Fügen Sie eine **Iterator**-Aktion hinzu:
* Eingabe: `{{code.products}}`
Dies durchläuft jedes Produkt im Array.
## Schritt 5: Jeden Datensatz upserten
Fügen Sie innerhalb des Iterators eine **Upsert Record**-Aktion hinzu:
| Einstellung | Wert |
| --------------------- | -------------------------------------------- |
| **Objekt** | Ihr benutzerdefiniertes Produktobjekt |
| **Abgleichen anhand** | Externe ID oder SKU (eindeutiger Bezeichner) |
| **Name** | `{{iterator.item.name}}` |
| **SKU** | `{{iterator.item.sku}}` |
| **Preis** | `{{iterator.item.price}}` |
<Tip>
Verwenden Sie **Upsert** (aktualisieren oder erstellen), anstatt separate Verzweigungen für Erstellen vs. Aktualisieren zu bauen. Das ist schneller aufzubauen und leichter zu debuggen.
</Tip>
## Beispielanwendungsfälle
| Quelle | Daten |
| ----------------------------- | --------------------------------------------- |
| **ERP-System** | Produktkatalog, Preise, Bestand |
| **E-Commerce-Plattform** | Bestellungen, Kunden, Produktaktualisierungen |
| **Data Warehouse** | Aggregierte Metriken, angereicherte Daten |
| **Bestandsverwaltungssystem** | Bestandsmengen, Nachbestellwarnungen |
## Verwandt
* [Workflow-Trigger](/l/de/user-guide/workflows/capabilities/workflow-triggers)
* [Workflow-Aktionen](/l/de/user-guide/workflows/capabilities/workflow-actions)
* [Arrays in Code-Aktionen verarbeiten](/l/de/user-guide/workflows/how-tos/advanced-configurations/handle-arrays-in-code-actions)

View File

@@ -0,0 +1,130 @@
---
title: Typeform-Formulareinsendungen in Twenty übernehmen
description: Verarbeiten Sie die Webhook-Payload von Typeform, um aus Formulareinsendungen Leads zu erstellen.
---
Für die Standard-Webhook-Einrichtung siehe [Webhook-Trigger einrichten](/l/de/user-guide/workflows/how-tos/connect-to-other-tools/set-up-a-webhook-trigger). Dieser Artikel behandelt die spezifische Verarbeitung, die für die benutzerdefinierte Payload-Struktur von Typeform erforderlich ist.
### Schritt 1: Webhook-Workflow erstellen
1. Gehen Sie zu **Einstellungen → Workflows**
2. Klicken Sie auf **+ Neuer Workflow**
3. Wählen Sie **Webhook** als Trigger
4. Kopieren Sie die Webhook-URL
### Schritt 2: Typeform konfigurieren
1. Öffnen Sie in Typeform Ihr Formular
2. Gehen Sie zu **Connect → Webhooks**
3. Fügen Sie Ihre Twenty-Webhook-URL ein
4. Speichern
### Schritt 3: Die Typeform-Payload verstehen
Typeform sendet eine verschachtelte JSON-Struktur. Hier ist ein vereinfachtes Beispiel:
```json
{
"event_type": "form_response",
"form_response": {
"form_id": "abc123",
"submitted_at": "2025-01-15T10:30:00Z",
"answers": [
{
"text": "Jane",
"type": "text",
"field": { "id": "field1", "type": "short_text", "title": "First Name" }
},
{
"text": "Smith",
"type": "text",
"field": { "id": "field2", "type": "short_text", "title": "Last Name" }
},
{
"text": "Acme Corp",
"type": "text",
"field": { "id": "field3", "type": "short_text", "title": "Company" }
},
{
"email": "jane@acme.com",
"type": "email",
"field": { "id": "field4", "type": "email", "title": "Email" }
},
{
"type": "choice",
"field": { "id": "field5", "type": "dropdown", "title": "Team Size" },
"choice": { "label": "10-50" }
}
]
}
}
```
Wichtige Hinweise:
* Formulardaten sind unter `form_response` verschachtelt
* **Antworten werden als Array zurückgegeben**, nicht als benannte Felder
* Jede Antwort enthält den Feldtyp und den Titel als Referenz
### Schritt 4: Felder aus dem `answers`-Array extrahieren
Da `answers` ein Array ist, können Sie in den folgenden Schritten nur das gesamte Array auswählen — nicht einzelne Felder. Fügen Sie eine **Code**-Aktion hinzu, um die benötigten Felder zu extrahieren:
```javascript
export const main = async (params: {
answers: any;
}): Promise<object> => {
const { answers } = params;
// Handle input that may come as a string or an array
const answersFormatted = typeof answers === "string"
? JSON.parse(answers)
: answers;
// Extract fields by position or by finding the field type
const firstName = answersFormatted[0]?.text || "";
const lastName = answersFormatted[1]?.text || "";
const company = answersFormatted[2]?.text || "";
const email = answersFormatted.find(a => a.type === "email")?.email || "";
const teamSize = answersFormatted.find(a => a.type === "choice")?.choice?.label || "";
return {
contact: {
firstName,
lastName,
company,
email,
teamSize
}
};
};
```
In den folgenden Schritten können Sie nun `contact.firstName`, `contact.email` usw. aus der Variablenauswahl auswählen.
<Tip>
Weitere Details zum Umgang mit Arrays in Code-Aktionen finden Sie unter [Arrays in Code-Aktionen verarbeiten](/l/de/user-guide/workflows/how-tos/advanced-configurations/handle-arrays-in-code-actions).
</Tip>
### Schritt 5: Datensatz erstellen
Fügen Sie die Aktion **Datensatz erstellen** hinzu:
| Feld | Wert |
| --------------- | ------------------------------------------------------------------ |
| **Objekt** | Personen |
| **Vorname** | `{{code.contact.firstName}}` |
| **Nachname** | `{{code.contact.lastName}}` |
| **E-Mail** | `{{code.contact.email}}` |
| **Unternehmen** | Suchen oder erstellen Sie basierend auf `{{code.contact.company}}` |
### Schritt 6: Testen und aktivieren
1. Senden Sie in Typeform eine Testantwort ab
2. Überprüfen Sie die Workflow-Ausführung, um zu bestätigen, dass die Daten erfasst wurden
3. Aktivieren Sie den Workflow
## Verwandt
* [Webhook-Trigger einrichten](/l/de/user-guide/workflows/how-tos/connect-to-other-tools/set-up-a-webhook-trigger)
* [Arrays in Code-Aktionen verarbeiten](/l/de/user-guide/workflows/how-tos/advanced-configurations/handle-arrays-in-code-actions)

View File

@@ -0,0 +1,263 @@
---
title: Ein PDF aus Twenty generieren
description: Erstellen Sie einen Workflow, um ein PDF (z. B. ein Angebot) zu generieren und an einen Datensatz anzuhängen.
---
Automatisch ein PDF generieren oder abrufen und an einen Datensatz in Twenty anhängen. Dies wird häufig verwendet, um Angebote, Rechnungen oder Berichte zu erstellen, die mit Companies, Opportunities oder anderen Objekten verknüpft sind.
## Übersicht
Dieser Workflow verwendet einen **Manuellen Auslöser**, damit Benutzer bei Bedarf für jeden ausgewählten Datensatz ein PDF generieren können. Eine **Logikfunktion** übernimmt:
1. Das Herunterladen des PDFs von einer URL (von einem PDF-Generierungsdienst)
2. Das Hochladen der Datei in Twenty
3. Das Erstellen eines Anhangs, der mit dem Datensatz verknüpft ist
## Voraussetzungen
Bevor Sie den Workflow einrichten:
1. **API-Schlüssel erstellen**: Gehen Sie zu **Einstellungen → APIs** und erstellen Sie einen neuen API-Schlüssel. Sie benötigen dieses Token für die Logic Funktion.
2. **Richten Sie einen PDF-Generierungsdienst ein** (optional): Wenn Sie PDFs dynamisch generieren möchten (z. B. Angebote), verwenden Sie einen Dienst wie Carbone, PDFMonkey oder DocuSeal, um das PDF zu erstellen und eine Download-URL zu erhalten.
## Schritt-für-Schritt-Einrichtung
### Schritt 1: Trigger konfigurieren
1. Gehen Sie zu **Workflows** und erstellen Sie einen neuen Workflow
2. Wählen Sie **Manueller Auslöser**
3. Wählen Sie das Objekt aus, dem Sie PDFs anhängen möchten (z. B. **Company** oder **Opportunity**)
<Tip>
Mit einem manuellen Trigger Benutzer können diesen Workflow mit einem Button ausführen, der rechts oben erscheint, sobald ein Datensatz ausgewählt ist — dies führt den Workflow aus, um eine PDF zu generieren und anzuhängen.
</Tip>
### Schritt 2: Logikfunktion hinzufügen
1. Füge eine **Code** Aktion (Logikfunktion) hinzu
2. Erstellen Sie eine neue Funktion mit dem folgenden Code
3. Konfigurieren Sie die Eingabeparameter
#### Eingabeparameter
| Parameter | Wert |
| ----------- | ----------------------- |
| `companyId` | `{{trigger.object.id}}` |
<Note>
Wenn Sie an ein anderes Objekt anhängen (Person, Opportunity usw.), benennen Sie den Parameter entsprechend um (z. B. `personId`, `opportunityId`) und aktualisieren Sie die Logikfunktion.
</Note>
#### Code der Logikfunktion
```typescript
export const main = async (
params: { companyId: string },
) => {
const { companyId } = params;
// Replace with your Twenty GraphQL endpoints (/metadata for metadata and files or /graphql for your records)
// Cloud: https://api.twenty.com/graphql
// Self-hosted: https://your-domain.com/graphql
const metadataGraphqlEndpoint = 'https://api.twenty.com/metadata';
const dataGraphqlEndpoint = 'https://api.twenty.com/graphql';
// Replace with your API key from Settings → APIs
const authToken = 'YOUR_API_KEY';
// Replace with your PDF URL
// This could be from a PDF generation service or a static URL
const pdfUrl = 'https://your-pdf-service.com/generated-quote.pdf';
const filename = 'quote.pdf';
// Step 1: Download the PDF file
const pdfResponse = await fetch(pdfUrl);
if (!pdfResponse.ok) {
throw new Error(`Failed to download PDF: ${pdfResponse.status}`);
}
const pdfBlob = await pdfResponse.blob();
const pdfFile = new File([pdfBlob], filename, { type: 'application/pdf' });
const fieldMetadataIdQuery = `
query FindUploadFileFieldMetadataId {
objects {
edges {
node {
nameSingular
fieldsList {
id
name
}
}
}
}
}
`;
// Step 2: Find a fieldMetadataId of "Attachment file" field in Attachments object with GraphQL API
const response = await fetch(metadataGraphqlEndpoint, {
method: 'POST',
headers: {
Authorization: `Bearer ${authToken}`
},
body: {
query: fieldMetadataIdQuery,
}
});
const result = await response.json();
const uploadFileFieldMetadataId = result.data.objects.edges.find(object => object.node.nameSingular === 'attachment').node.fieldsList.find(field => field.name === 'file').id;
// Step 3: Upload the file via GraphQL multipart upload
const uploadMutation = `
mutation UploadFilesFieldFile($file: Upload!, $fieldMetadataId: String!) {
uploadFilesFieldFile(file: $file, fieldMetadataId: $fieldMetadataId) {
id
}
}
`;
const uploadForm = new FormData();
uploadForm.append('operations', JSON.stringify({
query: uploadMutation,
variables: { file: null, fieldMetadataId: uploadFileFieldMetadataId },
}));
uploadForm.append('map', JSON.stringify({ '0': ['variables.file'] }));
uploadForm.append('0', pdfFile);
const uploadResponse = await fetch(metadataGraphqlEndpoint, {
method: 'POST',
headers: { Authorization: `Bearer ${authToken}` },
body: uploadForm,
});
const uploadResult = await uploadResponse.json();
if (uploadResult.errors?.length) {
throw new Error(`Upload failed: ${uploadResult.errors[0].message}`);
}
const fileId = uploadResult.data?.uploadFilesFieldFile?.id;
if (!fileId) {
throw new Error('No file id returned from upload');
}
// Step 4: Create the attachment linked to the company
const attachmentMutation = `
mutation CreateOneAttachment($data: AttachmentCreateInput!) {
createAttachment(data: $data) {
id
name
}
}
`;
const attachmentResponse = await fetch(dataGraphqlEndpoint, {
method: 'POST',
headers: {
Authorization: `Bearer ${authToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: attachmentMutation,
variables: {
data: {
name: filename,
targetCompanyId: companyId,
file: [
{
fileId: fileId,
label: filename
}
]
},
},
}),
});
const attachmentResult = await attachmentResponse.json();
if (attachmentResult.errors?.length) {
throw new Error(`Attachment creation failed: ${attachmentResult.errors[0].message}`);
}
return attachmentResult.data?.createAttachment;
};
```
### Schritt 3: An Ihren Anwendungsfall anpassen
#### An ein anderes Objekt anhängen
Ersetzen Sie `targetCompanyId` durch das entsprechende Feld:
| Objekt | Feldname |
| -------------------------- | -------------------------- |
| Unternehmen | `targetCompanyId` |
| Person | `targetPersonId` |
| Opportunity | `targetOpportunityId` |
| Benutzerdefiniertes Objekt | `targetYourCustomObjectId` |
Aktualisieren Sie sowohl den Funktionsparameter als auch das Objekt `variables.data` in der Attachment-Mutation.
#### So verwenden Sie eine dynamische PDF-URL
Wenn Sie einen PDF-Generierungsdienst verwenden, können Sie:
1. Führen Sie zuerst eine HTTP-Request-Aktion aus, um das PDF zu generieren
2. Übergeben Sie die zurückgegebene PDF-URL als Parameter an die Logikfunktion
```typescript
export const main = async (
params: { companyId: string; pdfUrl: string; filename: string },
) => {
const { companyId, pdfUrl, filename } = params;
// ... rest of the function
};
```
### Schritt 4: Testen und aktivieren
1. Speichern Sie den Workflow
2. Navigieren Sie zu einem Company-Datensatz
3. Klicken Sie auf das **⋮**-Menü und wählen Sie Ihren Workflow aus
4. Überprüfen Sie im Datensatz den Bereich **Attachments**, um zu verifizieren, dass das PDF angehängt wurde
5. Aktivieren Sie den Workflow
## Kombination mit PDF-Generierungsdiensten
Zum Erstellen dynamischer Angebote oder Rechnungen:
### Beispiel: Angebot generieren → PDF anhängen
| Schritt | Aktion | Zweck |
| ------- | ---------------------------- | ------------------------------------------------ |
| 1 | Manueller Auslöser (Company) | Benutzer initiiert am Datensatz |
| 2 | Datensatz suchen | Opportunity- oder Positionsdetails abrufen |
| 3 | HTTP-Anfrage | PDF-Generierungs-API mit Datensatzdaten aufrufen |
| 4 | Logikfunktion | Das generierte PDF herunterladen und anhängen |
### Beliebte PDF-Generierungsdienste
* **Carbone** – Vorlagenbasierte Dokumentenerstellung
* **PDFMonkey** – Dynamische PDF-Erstellung aus Vorlagen
* **DocuSeal** – Plattform für Dokumentenautomatisierung
* **Documint** – API-first-Dokumentenerstellung
Jeder Dienst stellt eine API zur Verfügung, die eine PDF-URL zurückgibt, die Sie dann an die Logic Funktion übergeben können.
## Fehlerbehebung
| Problem | Lösung |
| ----------------------------------------- | -------------------------------------------------------------------------------------- |
| "PDF konnte nicht heruntergeladen werden" | Prüfen Sie, ob die PDF-URL erreichbar ist und ein gültiges PDF zurückgibt |
| "Upload fehlgeschlagen" | Stellen Sie sicher, dass Ihr API-Schlüssel gültig ist und Schreibberechtigungen hat |
| "Anhangserstellung fehlgeschlagen" | Stellen Sie sicher, dass der Feldname der Objekt-ID mit Ihrem Zielobjekt übereinstimmt |
## Verwandt
* [Workflow-Trigger](/l/de/user-guide/workflows/capabilities/workflow-triggers)
* [Logikfunktionen](/l/de/user-guide/workflows/capabilities/workflow-actions#code)
* [Ein Angebot oder eine Rechnung aus Twenty generieren](/l/de/user-guide/workflows/how-tos/connect-to-other-tools/generate-quote-or-invoice-from-twenty)

View File

@@ -0,0 +1,144 @@
---
title: Ein Angebot oder eine Rechnung aus Twenty erstellen.
description: Rechnungen in externen Tools automatisch erstellen, wenn Deals abgeschlossen werden.
---
Deal-Daten automatisch an Ihr Rechnungsstellungssystem senden (Stripe, QuickBooks, Xero usw.) wenn eine Opportunity gewonnen wird.
## Workflow-Struktur
1. **Auslöser**: Datensatz wird aktualisiert (Opportunity)
2. **Filter**: Phase = Closed Won
3. **Datensatz suchen**: Unternehmensdetails abrufen
4. **Code** (optional): Nutzlast formatieren
5. **HTTP-Anfrage**: An Rechnungsstellungssystem senden
## Schritt 1: Auslöser einrichten
1. Erstellen Sie einen neuen Workflow
2. Wählen Sie den Auslöser **Datensatz wird aktualisiert** aus
3. Wählen Sie **Opportunity** als Objekt
## Schritt 2: Nach Closed Won filtern
Fügen Sie eine **Filter**-Aktion hinzu, damit nur fortgefahren wird, wenn der Deal gewonnen wurde:
| Einstellung | Wert |
| ------------- | ---------------------------------------- |
| **Feld** | Phase |
| **Bedingung** | Gleich |
| **Wert** | `CLOSED_WON` (oder der Name Ihrer Phase) |
<Tip>
Der Auslöser wird bei jeder Opportunity-Aktualisierung ausgelöst. Der Filter stellt sicher, dass der Workflow nur fortgesetzt wird, wenn die Phase auf Closed Won geändert wird.
</Tip>
## Schritt 3: Unternehmensdetails abrufen
Der Opportunity-Datensatz enthält möglicherweise nicht alle Unternehmensfelder, die Sie für die Rechnung benötigen. Fügen Sie eine **Datensatz suchen**-Aktion hinzu:
| Einstellung | Wert |
| --------------------- | -------------------------------------------- |
| **Objekt** | Unternehmen |
| **Abgleichen anhand** | ID entspricht `{{trigger.object.companyId}}` |
Dadurch wird der vollständige Unternehmensdatensatz mit Rechnungsadresse, Steuernummer usw. abgerufen.
## Schritt 4: Nutzlast formatieren (optional)
Wenn Ihr Rechnungsstellungssystem ein bestimmtes Format erwartet, fügen Sie eine **Code**-Aktion hinzu:
```javascript
export const main = async (params: {
opportunity: any;
company: any;
}): Promise<object> => {
const { opportunity, company } = params;
return {
invoice: {
// Customer info from Company
customer_name: company.name,
customer_email: company.email || "",
billing_address: {
line1: company.address?.street || "",
city: company.address?.city || "",
postal_code: company.address?.postalCode || "",
country: company.address?.country || ""
},
tax_id: company.taxId || null,
// Invoice details from Opportunity
amount: opportunity.amount,
currency: opportunity.currency || "USD",
description: `Invoice for ${opportunity.name}`,
due_days: 30,
// Reference back to Twenty
metadata: {
opportunity_id: opportunity.id,
company_id: company.id
}
}
};
};
```
## Schritt 5: An Rechnungsstellungssystem senden
Fügen Sie eine **HTTP-Anfrage**-Aktion hinzu:
| Einstellung | Wert |
| ----------- | ---------------------------------------------- |
| **Methode** | POST |
| **URL** | Ihr API-Endpunkt für die Rechnungsstellung |
| **Header** | `Authorization: Bearer YOUR_API_KEY` |
| **Inhalt** | `{{code.invoice}}` oder Felder direkt zuordnen |
### Beispiel: Stripe-Rechnung
```
POST https://api.stripe.com/v1/invoices
Headers:
Authorization: Bearer sk_live_xxx
Content-Type: application/x-www-form-urlencoded
Body:
customer: {{company.stripeCustomerId}}
collection_method: send_invoice
days_until_due: 30
```
### Beispiel: QuickBooks-Rechnung
```
POST https://quickbooks.api.intuit.com/v3/company/{realmId}/invoice
Headers:
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
Body: {{code.invoice}}
```
## Vollständige Workflow-Zusammenfassung
| Schritt | Aktion | Zweck |
| ------- | -------------------------------- | ------------------------------------------------------------------ |
| 1 | Auslöser: Datensatz aktualisiert | Wird ausgelöst, wenn sich eine beliebige Opportunity ändert |
| 2 | Filter | Nur fortfahren, wenn Phase = Closed Won |
| 3 | Datensatz suchen | Vollständige Unternehmensdetails für die Rechnungsstellung abrufen |
| 4 | Code | Daten für die Rechnungsstellungs-API formatieren |
| 5 | HTTP-Anfrage | Rechnung im externen System erstellen |
## Tipps
* **Externe IDs speichern**: Speichern Sie die von der API zurückgegebene Rechnungs-ID mithilfe einer **Datensatz aktualisieren**-Aktion in der Opportunity
* **Fehlerbehandlung**: Fügen Sie einen Zweig hinzu, um eine Benachrichtigung zu senden, wenn die HTTP-Anfrage fehlschlägt
* **Zuerst testen**: Verwenden Sie den Sandbox-/Testmodus Ihres Rechnungsstellungssystems, bevor Sie live gehen
## Verwandt
* [Ein PDF aus Twenty generieren](/l/de/user-guide/workflows/how-tos/connect-to-other-tools/generate-pdf-from-twenty) — generierte PDFs an Datensätze anhängen
* [Workflow-Trigger](/l/de/user-guide/workflows/capabilities/workflow-triggers)
* [Workflow-Aktionen](/l/de/user-guide/workflows/capabilities/workflow-actions)
* [Automatisierungen für Closed Won](/l/de/user-guide/workflows/how-tos/crm-automations/closed-won-automations)

View File

@@ -0,0 +1,170 @@
---
title: Webhook-Trigger einrichten
description: Empfangen Sie Daten von externen Diensten, um Workflows auszulösen.
---
Webhook-Trigger ermöglichen es externen Diensten, Ihre Workflows zu starten, indem sie Daten an eine eindeutige URL senden. Verwenden Sie sie, um Formulare, Drittanbieter-Apps und benutzerdefinierte Integrationen zu verbinden.
## Wann Sie Webhooks verwenden sollten
| Anwendungsfall | Beispiel |
| ------------------------------------ | ------------------------------------------------- |
| **Webformulare** | Einsendungen von Kontaktformularen erzeugen Leads |
| **Drittanbieter-Apps** | Stripe-Zahlung → Kundendatensatz erstellen |
| **Benutzerdefinierte Integrationen** | Ihre App → Twenty-Automatisierung |
| **No-Code-Tools** | Zapier-, Make- und n8n-Verbindungen |
## Schritt-für-Schritt-Einrichtung
### Schritt 1: Workflow erstellen
1. Gehen Sie zu **Einstellungen → Workflows**
2. Klicken Sie auf **+ Neuer Workflow**
3. Benennen Sie ihn (z. B. „Website-Formularübermittlung“)
### Schritt 2: Webhook-Trigger konfigurieren
1. Klicken Sie auf den Trigger-Block
2. Wählen Sie **Webhook** aus
3. Sie erhalten eine eindeutige Webhook-URL wie:
```
https://api.twenty.com/webhooks/workflow/abc123...
```
4. Kopieren Sie diese URL — Sie benötigen sie für Ihren externen Dienst
### Schritt 3: Erwartete Datenstruktur definieren
Bei **POST**-Anfragen die erwartete Body-Struktur definieren:
1. Klicken Sie auf **Erwarteten Body definieren**
2. Geben Sie ein Beispiel-JSON ein, das dem entspricht, was Ihr Dienst sendet:
```json
{
"firstName": "John",
"lastName": "Doe",
"email": "john@example.com",
"company": "Acme Inc",
"message": "Interested in your product"
}
```
3. Klicken Sie auf **Speichern** — dadurch werden Variablen erstellt, die Sie in den nächsten Schritten verwenden können.
### Schritt 4: Aktionen hinzufügen
Fügen Sie nun Aktionen hinzu, die die Webhook-Daten verwenden:
**Beispiel: Einen Personendatensatz erstellen**
1. Fügen Sie die Aktion **Datensatz erstellen** hinzu
2. Wählen Sie das Objekt **Personen** aus
3. Felder zuordnen:
| Feld | Wert |
| ----------- | ------------------------------------------------------------------ |
| Vorname | `{{trigger.body.firstName}}` |
| Nachname | `{{trigger.body.lastName}}` |
| E-Mail | `{{trigger.body.email}}` |
| Unternehmen | Suchen oder erstellen Sie basierend auf `{{trigger.body.company}}` |
### Schritt 5: Den Webhook testen
Testen Sie Ihren Webhook, bevor Sie ihn aktivieren:
**Mit cURL**:
```bash
curl -X POST https://api.twenty.com/webhooks/workflow/abc123... \
-H "Content-Type: application/json" \
-d '{"firstName":"Test","lastName":"User","email":"test@example.com"}'
```
**Mit Postman oder ähnlichen Tools**:
1. Erstellen Sie eine POST-Anfrage an Ihre Webhook-URL
2. Setzen Sie den Content-Type-Header auf `application/json`
3. Fügen Sie Ihren Test-JSON-Body hinzu
4. Senden und die Workflow-Ausführungen prüfen
### Schritt 6: Aktivieren
Nach dem Testen klicken Sie auf **Aktivieren**, um den Workflow live zu schalten.
## Umgang mit unterschiedlichen Datenstrukturen
### Verschachtelte Daten
Wenn Ihr Webhook verschachtelte Daten sendet:
```json
{
"contact": {
"name": "John Doe",
"email": "john@example.com"
},
"source": "website"
}
```
Referenzieren mit: `{{trigger.body.contact.email}}`
### Arrays
Wenn die Daten Arrays enthalten:
```json
{
"items": [
{"name": "Product A", "qty": 2},
{"name": "Product B", "qty": 1}
]
}
```
Wie Sie Arrays handhaben, hängt von Ihrem Anwendungsfall ab:
**Unbekannte Anzahl von Elementen → Iterator verwenden**
Wenn Sie jedes Element im Array verarbeiten müssen (z. B. für jedes einen Datensatz erstellen), fügen Sie eine **Code**-Aktion hinzu, um das Array zu parsen, und verwenden Sie anschließend **Iterator**:
```javascript
export const main = async (params: { items: any }) => {
const items = typeof params.items === "string"
? JSON.parse(params.items)
: params.items;
return { items };
};
```
Verwenden Sie dann Iterator, um zu iterieren: `{{code.items}}`
**Bekannte/spezifische Felder → In benannte Felder extrahieren**
Wenn das Array bestimmte Felder enthält, auf die Sie einzeln zugreifen möchten (z. B. Formularantworten, bei denen Position 0 immer „Vorname“ und Position 1 immer „Nachname“ ist), fügen Sie eine **Code**-Aktion hinzu, um sie zu extrahieren:
```javascript
export const main = async (params: { items: any }) => {
const items = typeof params.items === "string"
? JSON.parse(params.items)
: params.items;
return {
product: {
name: items[0]?.name || "",
qty: items[0]?.qty || 0
}
};
};
```
Jetzt können Sie `product.name` und `product.qty` in den folgenden Schritten jeweils einzeln auswählen.
<Tip>
Weitere Details zum Umgang mit Arrays finden Sie unter [Arrays in Code-Aktionen verarbeiten](/l/de/user-guide/workflows/how-tos/advanced-configurations/handle-arrays-in-code-actions).
</Tip>
## Verwandt
* [Workflow-Trigger](/l/de/user-guide/workflows/capabilities/workflow-triggers)
* [Workflow-Aktionen](/l/de/user-guide/workflows/capabilities/workflow-actions)

View File

@@ -0,0 +1,121 @@
---
title: Automatische Antwort auf eingehende E-Mails
description: Erstellen Sie einen Workflow, der KI nutzt, um eingehende E-Mails zu sichten und automatisch Antworten im Thread zu senden.
---
Antworten Sie auf eingehende E-Mails in Sekunden — nicht in Stunden. Dieser Workflow verwendet einen AI Agenten, um Rauschen (Newsletter, Spam, Auto-Antworten) zu filtern und eine personalisierte Antwort auf echte Nachrichten zu entwerfen. Dann sendet die KI sie als Thread-Antwort innerhalb der ursprünglichen Konversation.
## Wie E-Mail-Threading funktioniert
Jede E-Mail enthält einen verborgenen `Message-ID`-Header — einen eindeutigen Fingerabdruck, der vom Mailserver des Absenders zugewiesen wird. Wenn Sie auf eine E-Mail antworten, setzt Ihr E-Mail-Client einen `In-Reply-To`-Header, der auf diesen Fingerabdruck verweist. So gruppieren Gmail, Outlook und alle anderen Clients Nachrichten in Threads.
In Twenty wird dieser Fingerabdruck als `headerMessageId` am Message-Objekt gespeichert. Ihr Workflow greift ihn auf und übergibt ihn an das Feld In-Reply-To der Aktion Send Email.
## Den Workflow erstellen
### Schritt 1: Neuen Workflow erstellen
Gehen Sie zu **Settings -> Workflows** und klicken Sie auf **+ New Workflow**.
### Schritt 2: Bei eingehenden Nachrichten auslösen
Wählen Sie **When a Record is Created** und dann **Messages**.
Jedes Mal, wenn eine E-Mail in Twenty eingeht, wird dies ausgelöst.
<img src="/images/user-guide/workflows/auto-reply/workflow-overview.png" style={{width:'100%'}} />
### Schritt 3: Absender ermitteln
Fügen Sie eine **Datensätze suchen**-Aktion hinzu.
Die Absenderadresse befindet sich nicht in der Nachricht selbst — sie steht im zugehörigen Datensatz Message Participant.
| Feld | Wert |
| ---------- | -------------------------------- |
| **Objekt** | Nachrichtenteilnehmer |
| **Filter** | Message **ist** `{{trigger.id}}` |
| **Filter** | Rolle **ist** From |
| **Limit** | 1 |
Dadurch erhalten Sie die E-Mail-Adresse des Absenders in `handle` und den Namen in `displayName`.
<img src="/images/user-guide/workflows/auto-reply/find-sender.png" style={{width:'100%'}} />
### Schritt 4: Triage und Entwurf einer Antwort mit der KI
Fügen Sie eine **AI Agent**-Aktion hinzu. Dieser einzelne Schritt erledigt zwei Dinge: Er entscheidet, ob die E-Mail eine Antwort verdient, und falls ja, verfasst er eine.
Verwenden Sie einen Prompt wie:
```
You are an email triage assistant for a sales team. Read the following
inbound email and decide if it deserves a reply.
Subject: {{trigger.subject}}
Body: {{trigger.text}}
From: {{Find Sender.first.displayName}} ({{Find Sender.first.handle}})
If this email is spam, a newsletter, an automated notification, or
otherwise does not need a human reply, respond with exactly: SKIP
Otherwise, write a short, professional reply (3-4 sentences max) that:
- Acknowledges their specific message
- Lets them know someone from the team will follow up shortly
- Is warm but not overly casual
Respond with only the reply text, no subject line or greeting prefix.
```
Der AI Agent gibt seine Antwort in einem Feld `response` aus, auf das sich die nächsten Schritte beziehen können.
<img src="/images/user-guide/workflows/auto-reply/ai-triage.png" style={{width:'100%'}} />
### Schritt 5: Verzweigen anhand der KI-Entscheidung
Fügen Sie eine **If/Else**-Aktion hinzu, um zu prüfen, ob die KI sich entschieden hat zu antworten oder zu überspringen.
| Feld | Wert |
| ------------- | -------------------------------------------- |
| **Bedingung** | AI Agent `response` **enthält nicht** `SKIP` |
| **Wenn wahr** | Mit Send Email fortfahren |
| **Sonst** | Nichts tun (Workflow endet) |
Spam, Newsletter und automatisch erzeugte Nachrichten werden verworfen. Alles andere geht zum nächsten Schritt über.
<img src="/images/user-guide/workflows/auto-reply/should-reply.png" style={{width:'100%'}} />
### Schritt 6: Eine Antwort im Thread senden
Fügen Sie im "Wenn wahr"-Zweig eine **Send Email**-Aktion hinzu. Klicken Sie auf **Advanced options**, dann **Add In-Reply-To**.
| Feld | Wert |
| --------------- | -------------------------------------- |
| **An** | `{{Find Sender.first.handle}}` |
| **Betreff** | `Re: {{trigger.subject}}` |
| **Body** | `{{AI Triage & Draft Reply.response}}` |
| **In-Reply-To** | `{{trigger.headerMessageId}}` |
Das Feld In-Reply-To sorgt dafür, dass dies eine Antwort und keine neue Unterhaltung ist. Der Empfänger sieht sie als Teil des Threads unter der ursprünglichen E-Mail in Gmail, Outlook oder jedem anderen Client.
<img src="/images/user-guide/workflows/auto-reply/send-email.png" style={{width:'100%'}} />
<Tip>
**In-Reply-To** erwartet eine `message.headerMessageId` aus dem Trigger — das ist der eindeutige Fingerabdruck der E-Mail, keine Empfängeradresse. Wenn Sie es leer lassen, wird die E-Mail trotzdem gesendet, nur als eigenständige Nachricht.
</Tip>
<Warning>
Gmail verwendet die Betreffzeile, um Nachrichten in Threads zu gruppieren. Der Betreff **muss** mit `Re:` beginnen (einschließlich Doppelpunkt und Leerzeichen), damit Gmail die Antwort im ursprünglichen Thread anzeigt. Ohne dies erscheint die Antwort als separate Unterhaltung — selbst wenn der In-Reply-To-Header korrekt gesetzt ist.
</Warning>
### Schritt 7: Testen und aktivieren
Klicken Sie auf **Test**, und prüfen Sie dann Ihren E-Mail-Client. Die Antwort sollte unter der ursprünglichen Nachricht verschachtelt erscheinen.
Aktivieren Sie ihn, wenn Sie zufrieden sind.
## Ideen zum Ausbau
* **Nur an VIPs antworten** — fügen Sie einen Zweig hinzu, der die Domain des Absenders prüft oder ob er in Twenty als Kontakt existiert
* **Nach Absicht routen** — verwenden Sie separate AI Agent-Prompts, um Vertriebsanfragen anders zu bearbeiten als Supportanfragen
* **Vor der Antwort anreichern** — fügen Sie einen Schritt Search Records hinzu, um das Unternehmen oder die Deal-Historie des Absenders in den AI-Prompt zu übernehmen, für persönlichere Antworten

View File

@@ -0,0 +1,179 @@
---
title: Closed-Won-Automatisierungen
description: Automatisieren Sie Post-Win-Aktivitäten, wenn Opportunities abgeschlossen werden.
---
Wenn ein Deal abgeschlossen wird, müssen mehrere Dinge geschehen: Unternehmensstatus aktualisieren, Teammitglieder benachrichtigen, Onboarding-Aufgaben erstellen. Automatisieren Sie all das mit einem einzigen Workflow.
## Das Problem
Wenn eine Opportunity zu "Closed Won" wechselt:
* Der Unternehmenstyp muss von "Prospect" zu "Customer" geändert werden
* Onboarding-Aufgaben müssen erstellt werden
* Das Customer-Success-Team muss benachrichtigt werden
* Der Vertriebsmitarbeiter benötigt eine Bestätigung
Dies manuell zu erledigen ist zeitaufwendig und fehleranfällig.
## Die Lösung
Erstellen Sie einen Workflow, der alle Post-Win-Aktivitäten automatisch erledigt.
## Vollständige Workflow-Einrichtung
### Schritt 1: Workflow erstellen
1. Gehen Sie zu **Einstellungen → Workflows**
2. Klicken Sie auf **+ Neuer Workflow**
3. Benennen Sie ihn "Deal Won - Post-Win Automation"
### Schritt 2: Trigger konfigurieren
1. Wählen Sie **Datensatz wird aktualisiert** aus
2. Wählen Sie **Opportunities**
3. Wählen Sie unter "Fields to monitor" **Stage** aus
### Schritt 3: Stage-Filter hinzufügen
1. Fügen Sie eine **Filter**-Aktion hinzu
2. Bedingung: `{{trigger.object.stage}}` ist gleich "Closed Won"
### Schritt 4: Unternehmenstyp aktualisieren
1. Fügen Sie die Aktion **Datensatz aktualisieren** hinzu
2. Konfigurieren:
| Feld | Wert |
| -------------------------- | ------------------------------- |
| **Objekt** | Unternehmen |
| **Datensatz** | `{{trigger.object.company.id}}` |
| **Typ** | Kunde |
| **Datum des ersten Deals** | `{{trigger.object.closedAt}}` |
| **Kontoinhaber** | `{{trigger.object.owner.id}}` |
### Schritt 5: Onboarding-Aufgabe erstellen
1. Fügen Sie die Aktion **Datensatz erstellen** hinzu
2. Konfigurieren:
| Feld | Wert |
| --------------------------- | ------------------------------------------------------------------------------------------------ |
| **Objekt** | Aufgaben |
| **Titel** | `Onboarding: {{trigger.object.name}}` |
| **Zuständiger** | Mitglied des Customer-Success-Teams |
| **Fälligkeitsdatum** | In 3 Tagen |
| **Priorität** | Hoch |
| **Zugehöriges Unternehmen** | `{{trigger.object.company.id}}` |
| **Zugehörige Opportunity** | `{{trigger.object.id}}` |
| **Beschreibung** | `Neukunden-Onboarding für {{trigger.object.company.name}}. Deal-Wert: {{trigger.object.amount}}` |
### Schritt 6: Customer Success benachrichtigen
1. Fügen Sie eine **E-Mail senden**-Aktion hinzu
2. Konfigurieren:
| Feld | Wert |
| ----------- | ------------------------------------------------- |
| **An** | customer-success@yourcompany.com |
| **Betreff** | `🎉 Neuer Kunde: {{trigger.object.company.name}}` |
| **Inhalt** | Siehe Beispiel unten |
**Beispiel für den E-Mail-Text**:
```
Hi CS Team,
We have a new customer!
Company: {{trigger.object.company.name}}
Deal: {{trigger.object.name}}
Value: {{trigger.object.amount}}
Sales Rep: {{trigger.object.owner.name}}
Close Date: {{trigger.object.closedAt}}
An onboarding task has been created automatically.
Let's give them a great start!
```
### Schritt 7: Bestätigung an Vertriebsmitarbeiter senden
1. Fügen Sie eine weitere **E-Mail senden**-Aktion hinzu
2. Konfigurieren:
| Feld | Wert |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| **An** | `{{trigger.object.owner.email}}` |
| **Betreff** | `✅ Deal abgeschlossen: {{trigger.object.name}}` |
| **Inhalt** | Herzlichen Glückwunsch! Ihr Deal wurde verarbeitet. Das Customer-Success-Team wurde benachrichtigt und das Onboarding hat begonnen. |
### Schritt 8: Testen und aktivieren
1. Testen Sie, indem Sie eine Test-Opportunity auf "Closed Won" verschieben
2. Verifizieren:
* Unternehmenstyp auf "Customer" geändert
* Onboarding-Aufgabe erstellt
* CS-Team hat E-Mail erhalten
* Vertriebsmitarbeiter hat Bestätigung erhalten
3. Aktivieren Sie, sobald alles bereit ist
## Closed Lost behandeln
Erstellen Sie einen ähnlichen Workflow für verlorene Deals:
### Auslöser
* Datensatz wird aktualisiert (Opportunities, Stage = "Closed Lost")
### Aktionen
1. **Datensatz erstellen**: Aufgabe für "Lost Deal Analysis"
2. **Datensatz aktualisieren**: Grund für verlorenen Deal zum Unternehmensdatensatz hinzufügen
3. **E-Mail senden**: Manager über verlorenen Deal benachrichtigen
## Erweitert: Mehrstufiges Onboarding
Für komplexes Onboarding mehrere Aufgaben erstellen:
```javascript
export const main = async (params) => {
const tasks = [
{ title: "Welcome call", daysFromNow: 1, assignee: "CS" },
{ title: "Send onboarding materials", daysFromNow: 2, assignee: "CS" },
{ title: "Technical setup", daysFromNow: 5, assignee: "Support" },
{ title: "30-day check-in", daysFromNow: 30, assignee: "CS" }
];
return { tasks };
};
```
Verwenden Sie **Iterator**, um jede Aufgabe aus dem Array zu erstellen.
## Ideen zur Anpassung
### Halten Sie Ihre anderen Tools auf dem neuesten Stand
* Kunden im Abrechnungssystem per **HTTP Request** erstellen
### Bedingte Aktionen
Verwenden Sie **Filter**-Aktionen, um:
* Unterschiedliches Onboarding für Enterprise vs. SMB
* Unterschiedliche Zuständige je nach Region
* Benachrichtigungen für kleine Deals überspringen
### Deal-Details einbeziehen
Verwenden Sie die **Code**-Aktion, um zu formatieren:
* Dokumente zur Deal-Zusammenfassung
* Übergabenotizen für das CS-Team
* Individuelle Onboarding-Checklisten
## Verwandt
* [Workflow-Aktionen](/l/de/user-guide/workflows/capabilities/workflow-actions)
* [E-Mails aus Workflows senden](/l/de/user-guide/workflows/capabilities/send-emails-from-workflows)

View File

@@ -0,0 +1,136 @@
---
title: Ruhende Gelegenheiten erkennen
description: Manager automatisch benachrichtigen, wenn Gelegenheiten nicht aktualisiert wurden.
---
Halten Sie Ihre Pipeline gesund, indem Sie Manager benachrichtigen, wenn Gelegenheiten ruhend werden. Dieser Workflow prüft Gelegenheiten, die seit einer festgelegten Anzahl von Tagen nicht aktualisiert wurden.
## Das Problem
Nicht aktualisierte Gelegenheiten führen zu:
* Erkaltende Deals
* Unzuverlässige Prognosen
* Entgangener Umsatz
## Die Lösung
Erstellen Sie einen geplanten Workflow, der ruhende Gelegenheiten findet und deren Manager per E-Mail benachrichtigt.
## Schritt-für-Schritt-Einrichtung
### Schritt 1: Workflow erstellen
1. Gehen Sie zu **Einstellungen → Workflows**
2. Klicken Sie auf **+ Neuer Workflow**
3. Benennen Sie ihn "Benachrichtigung für ruhende Gelegenheiten"
### Schritt 2: Trigger konfigurieren
1. Wählen Sie **Nach Zeitplan**
2. Auf täglich festlegen (z. B. jeden Tag um 8 Uhr)
### Schritt 3: Nach ruhenden Gelegenheiten suchen
1. Fügen Sie die Aktion **Datensätze suchen** hinzu
2. Konfigurieren:
| Feld | Wert |
| ---------- | ---------------------------------------------------- |
| **Objekt** | Opportunities |
| **Filter** | Aktualisiert am ist vor (heute - 7 Tage) |
| **Filter** | Phase ist nicht "Closed Won" UND nicht "Closed Lost" |
| **Limit** | 100 |
### Schritt 4: Prüfen, ob Einträge gefunden wurden
1. Fügen Sie eine **Filter**-Aktion hinzu
2. Bedingung: `{{searchRecords.length}}` ist größer als 0
3. Wenn keine ruhenden Gelegenheiten vorhanden sind, endet der Workflow hier
### Schritt 5: Benachrichtigung formatieren (Code-Aktion)
Fügen Sie eine **Code**-Aktion hinzu, um die E-Mail zu formatieren:
```javascript
export const main = async (params) => {
const opportunities = params.opportunities;
// Group opportunities by owner
const byOwner = {};
opportunities.forEach(opp => {
const ownerEmail = opp.owner?.email || 'unassigned';
if (!byOwner[ownerEmail]) {
byOwner[ownerEmail] = [];
}
byOwner[ownerEmail].push({
name: opp.name,
amount: opp.amount,
lastUpdated: opp.updatedAt,
stage: opp.stage
});
});
// Format summary for manager
let summary = "Stale Opportunities Report\n\n";
Object.entries(byOwner).forEach(([owner, opps]) => {
summary += `${owner}: ${opps.length} stale opportunities\n`;
opps.forEach(opp => {
summary += ` - ${opp.name} (${opp.stage})\n`;
});
summary += "\n";
});
return {
summary,
totalCount: opportunities.length
};
};
```
### Schritt 6: Benachrichtigungs-E-Mail senden
Fügen Sie eine **E-Mail senden**-Aktion hinzu:
| Feld | Wert |
| ----------- | ----------------------------------------------------------------------- |
| **An** | sales-manager@yourcompany.com |
| **Betreff** | `🚨 {{code.totalCount}} ruhende Gelegenheiten erfordern Aufmerksamkeit` |
| **Inhalt** | `{{code.summary}}` |
### Schritt 7: Testen und aktivieren
1. Klicken Sie auf **Test**, um den Workflow auszuführen
2. Überprüfen Sie, dass die E-Mail die richtigen Daten enthält
3. Aktivieren Sie, sobald alles bereit ist
## Anpassungsoptionen
### Schwellenwert für Inaktivität ändern
Passen Sie den Filter der Aktion Datensätze suchen an, um statt 7 Tagen Ihren bevorzugten Zeitraum zu verwenden:
* 3 Tage für schnelllebige Verkäufe
* 14 Tage für Enterprise-Deals
* 30 Tage für lange Verkaufszyklen
### Einzelne Vertriebsmitarbeiter benachrichtigen
Verwenden Sie statt einer einzelnen Manager-E-Mail den **Iterator**, um jedem Vertriebsmitarbeiter personalisierte E-Mails zu seinen eigenen ruhenden Deals zu senden.
### Eskalation hinzufügen
Erstellen Sie mehrere Workflows mit zunehmender Dringlichkeit:
1. Tag 7: E-Mail an den Vertriebsmitarbeiter
2. Tag 14: E-Mail an Vertriebsmitarbeiter + Manager
3. Tag 21: Aufgabe für den Manager erstellen, um einzugreifen
### In Slack einbinden
Verwenden Sie **HTTP Request**, um an einen Slack-Webhook zu posten, anstelle von oder zusätzlich zu E-Mail.
## Verwandt
* [Workflow-Aktionen](/l/de/user-guide/workflows/capabilities/workflow-actions)
* [E-Mails aus Workflows senden](/l/de/user-guide/workflows/capabilities/send-emails-from-workflows)

View File

@@ -0,0 +1,69 @@
---
title: Anzahl empfangener E-Mails anzeigen
description: Erstellen Sie einen Workflow, der automatisch die Anzahl der von jedem Kontakt empfangenen E-Mails zählt und anzeigt.
---
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
<img src="/images/user-guide/workflows/workflow-number-of-emails-received.png" style={{width:'100%'}} />
## Übersicht
Dieser Workflow wird jedes Mal ausgelöst, wenn eine neue E-Mail eingeht, und aktualisiert ein benutzerdefiniertes Feld im Personendatensatz mit der Gesamtanzahl der E-Mails dieses Absenders.
## Voraussetzungen
Erstellen Sie vor der Einrichtung dieses Workflows ein benutzerdefiniertes Feld am Objekt **People**:
1. Gehen Sie zu **Einstellungen → Datenmodell → People**
2. Fügen Sie ein neues Feld vom Typ **Number** hinzu
3. Nennen Sie es etwa "Anzahl der von dieser Person empfangenen E-Mails"
## Schritt-für-Schritt-Einrichtung
<VimeoEmbed videoId="1148700336" title="Video-Demonstration" />
### Schritt 1: Trigger konfigurieren
1. Gehen Sie zu **Workflows** und erstellen Sie einen neuen Workflow
2. Wählen Sie **Record is Created** als Auslöser
3. Wählen Sie **Message Participants** (verfügbar unter Advanced objects)
<Note>
Ein Message Participant ist eine Kombination aus einer Nachrichten-ID und einer Personen-ID und erzeugt einen eindeutigen Datensatz pro Nachricht. Dies ist einfacher nachzuverfolgen als die Nachrichten direkt, da wir auf das Feld `handle` zugreifen können, das die E-Mail-Adresse des Absenders (oder Empfängers) enthält.
</Note>
### Schritt 2: Nach Rolle filtern
1. Fügen Sie eine **Filter**-Aktion hinzu
2. Legen Sie die Bedingung fest: **Role** ist gleich **FROM**
So stellen Sie sicher, dass Sie nur Nachrichten zählen, die von dieser Person gesendet wurden, nicht Nachrichten, die an sie gesendet wurden.
### Schritt 3: Alle Message Participants mit demselben Handle suchen
1. Fügen Sie eine **Datensätze suchen**-Aktion hinzu
2. Wählen Sie **Message Participants** als Objekt
3. Fügen Sie Filter hinzu: **Handle** entspricht dem Handle aus dem Trigger (der E-Mail-Adresse des Absenders) und **Role** ist gleich **FROM**
4. Erhöhen Sie das **Limit** von 1 auf **200** (das Maximum)
Dadurch werden alle Nachrichten von dieser E-Mail-Adresse gefunden, um die Gesamtanzahl zu erhalten.
<Note>
Die Aktion Datensätze suchen ist auf die Rückgabe von maximal 200 Datensätzen beschränkt. Da Sie jedoch nur den Wert `totalCount` verwenden (nicht die einzelnen Datensätze), liefert dieser Schritt die Gesamtanzahl der von dieser Person gesendeten E-Mails.
</Note>
### Schritt 4: Den Personendatensatz mit einer Create or Update Record-Aktion aktualisieren
1. Fügen Sie eine **Create or Update Record**-Aktion hinzu
2. Wählen Sie **People** als Objekt
3. Finden Sie die Person, indem Sie ihre E-Mail-Adresse mit dem `handle` des Message Participant abgleichen.
4. Setzen Sie Ihr benutzerdefiniertes Feld "Anzahl empfangener E-Mails" auf `{{searchRecords.totalCount}}`
Der Wert `totalCount` aus der Aktion Datensätze suchen steht für die Gesamtanzahl der von dieser Person empfangenen E-Mails.
## Verwandt
* [Workflow-Aktionen](/l/de/user-guide/workflows/capabilities/workflow-actions)
* [Benutzerdefinierte Felder erstellen](/l/de/user-guide/data-model/how-tos/customize-your-data-model)
* [Aktion Datensätze suchen](/l/de/user-guide/workflows/capabilities/workflow-actions#search-records)

View File

@@ -0,0 +1,170 @@
---
title: Daten verknüpfter Datensätze anzeigen
description: Zeigen Sie mithilfe von Workflows Daten aus verknüpften Datensätzen an (z. B. Unternehmensinformationen in Opportunities).
---
Zeigen Sie Daten aus verknüpften Datensätzen direkt in Ihren Datensätzen an — zum Beispiel die Mitarbeiterzahl eines Unternehmens in dessen Opportunities. Dieser Workflow-Workaround ist hilfreich, bis verschachtelte Felder nativ verfügbar sind.
## Häufige Anwendungsfälle
| Quelle | Ziel | Zu kopierende Felder |
| ----------- | ----------- | --------------------------------------------------- |
| Unternehmen | Opportunity | Branche, Unternehmensgröße, ARR |
| Person | Opportunity | E-Mail, Telefon, Position |
| Opportunity | Unternehmen | Betrag des letzten Deals, Datum des letzten Gewinns |
## Einfache Feldkopie
### Beispiel: Kontakt-E-Mail in die Opportunity kopieren
**Ziel**: Wenn bei einer Opportunity ein Ansprechpartner festgelegt wird, soll dessen E-Mail für den schnellen Zugriff in die Opportunity kopiert werden.
### Voraussetzung
Erstellen Sie die Zielfelder in **Settings → Data Model → Opportunities**, bevor Sie den Workflow erstellen:
* Kontakt-E-Mail (Typ: E-Mail)
* Kontakt-Telefon (Typ: Telefon)
### Einrichtung
1. **Auslöser**: Datensatz wird aktualisiert (Opportunities, Feld Ansprechpartner)
2. **Filter**: Prüfen, dass der Ansprechpartner nicht leer ist
3. **Datensätze durchsuchen**: Verknüpfte Person finden
* Objekt: People
* Filter: ID entspricht `{{trigger.object.pointOfContact.id}}`
4. **Datensatz aktualisieren**:
* Objekt: Opportunities
* Datensatz: `{{trigger.object.id}}`
* Kontakt-E-Mail: `{{searchRecords[0].email}}`
* Kontakt-Telefon: `{{searchRecords[0].phone}}`
## Mehrere Felder kopieren
### Beispiel: Unternehmensinformationen mit allen verknüpften Opportunities synchronisieren
**Ziel**: Wenn sich Unternehmensdetails ändern, alle verknüpften Opportunities aktualisieren.
### Einrichtung
1. **Auslöser**: Datensatz wird aktualisiert (Companies)
* Felder: Branche, Unternehmensgröße, Jahresumsatz
2. **Datensätze durchsuchen**: Alle Opportunities für dieses Unternehmen finden
* Objekt: Opportunities
* Filter: Unternehmens-ID entspricht `{{trigger.object.id}}`
3. **Iterator**: Jede Opportunity durchlaufen
4. **Datensatz aktualisieren** (innerhalb des Iterators):
* Objekt: Opportunities
* Datensatz: `{{iterator.currentItem.id}}`
* Unternehmensbranche: `{{trigger.object.industry}}`
* Unternehmensgröße: `{{trigger.object.companySize}}`
* Unternehmens-ARR: `{{trigger.object.annualRevenue}}`
## Kopieren bei der Datensatzerstellung
### Beispiel: Opportunity mit Unternehmensdaten vorbefüllen
**Ziel**: Beim Erstellen einer Opportunity, die mit einem Unternehmen verknüpft ist, werden wichtige Unternehmensinformationen automatisch kopiert.
### Voraussetzung
Erstellen Sie die Zielfelder in **Settings → Data Model → Opportunities**:
* Unternehmensbranche (Typ: Text)
* Unternehmensgröße (Typ: Zahl)
### Einrichtung
1. **Auslöser**: Datensatz wird erstellt (Opportunities)
* Filter: Unternehmen ist nicht leer
2. **Datensätze durchsuchen**: Details des verknüpften Unternehmens abrufen
* Objekt: Companies
* Filter: ID entspricht `{{trigger.object.company.id}}`
3. **Datensatz aktualisieren**:
* Objekt: Opportunities
* Datensatz: `{{trigger.object.id}}`
* Unternehmensbranche: `{{searchRecords[0].industry}}`
* Unternehmensgröße: `{{searchRecords[0].employees}}`
<Note>
**Einschränkung bei Aufgaben und Notizen**: Beziehungen bei Aufgaben und Notizen sind fest als Viele-zu-Viele implementiert und stehen in Workflow-Auslösern oder -Aktionen noch nicht zur Verfügung. Um auf diese Beziehungen zuzugreifen, verwenden Sie stattdessen die [API](/l/de/developers/extend/api).
</Note>
## Bidirektionale Synchronisierung
### Beispiel: Hauptansprechpartner synchron halten
**Ziel**: Wenn sich der Hauptansprechpartner eines Unternehmens ändert, den Kontakt aktualisieren. Wenn eine Person zum Hauptansprechpartner wird, das Unternehmen aktualisieren.
### Workflow 1: Unternehmen → Person
1. **Auslöser**: Datensatz wird aktualisiert (Companies, Feld Hauptansprechpartner)
2. **Datensatz aktualisieren**: Beim Kontakt "Is Primary Contact" auf true setzen
3. **Datensätze durchsuchen**: Vorherigen Hauptansprechpartner finden
4. **Datensatz aktualisieren**: Beim vorherigen Kontakt "Is Primary Contact" auf false setzen
### Workflow 2: Person → Unternehmen
1. **Auslöser**: Datensatz wird aktualisiert (People, Is Primary Contact = true)
2. **Datensatz aktualisieren**: Den Hauptansprechpartner des Unternehmens auf diese Person setzen
<Note>
Seien Sie bei bidirektionalen Synchronisierungen vorsichtig, um Endlosschleifen zu vermeiden. Verwenden Sie Filter, um vor dem Aktualisieren zu prüfen, ob sich der Wert tatsächlich geändert hat.
</Note>
## Code für komplexe Zuordnungen verwenden
### Beispiel: Daten beim Kopieren transformieren
**Ziel**: Telefonnummer von Person zur Opportunity kopieren und formatieren.
```javascript
export const main = async (params) => {
const { phone } = params;
if (!phone) return { formattedPhone: null };
// Remove non-numeric characters
const digits = phone.replace(/\D/g, '');
// Format as (XXX) XXX-XXXX
const formatted = digits.length === 10
? `(${digits.slice(0,3)}) ${digits.slice(3,6)}-${digits.slice(6)}`
: phone;
return { formattedPhone: formatted };
};
```
## Beste Praktiken
### Schleifen vermeiden
* Erstellen Sie keine Workflows, die sich gegenseitig endlos auslösen
* Spezifische Feldbedingungen verwenden
* Prüfungen hinzufügen, ob sich der Wert tatsächlich geändert hat
### Fehlende Daten behandeln
* Vor dem Kopieren stets prüfen, ob der Quelldatensatz existiert
* Standardwerte für optionale Felder bereitstellen
* Filter verwenden, um zu überspringen, wenn das Quellfeld leer ist
### Leistung
* Updates bündeln, wenn in viele Datensätze kopiert wird
* Geplante Workflows für Massensynchronisierungen verwenden
* Erwägen Sie die Verwendung von Iterator für mehrere Datensatzaktualisierungen
## Verwandt
* [Workflow-Aktionen](/l/de/user-guide/workflows/capabilities/workflow-actions)
* [Workflow-Trigger](/l/de/user-guide/workflows/capabilities/workflow-triggers)

View File

@@ -0,0 +1,202 @@
---
title: Formelfelder
description: Erstellen Sie Formelfelder mithilfe von Workflows, bis native Unterstützung verfügbar ist.
---
Zwanzig unterstützen noch keine Formelfelder (ab 2026), aber Sie können das gleiche Ergebnis mit Workflows erzielen. Mit diesem Workaround können Sie Feldwerte automatisch berechnen und ausfüllen – von einfachen Verkettungen bis hin zu komplexer Geschäftslogik.
## Häufige Anwendungsfälle
| Anwendungsfall | Formelbeispiel |
| --------------------------- | --------------------------------------- |
| **Vollständiger Name** | Vorname + " " + Nachname |
| **Erwarteter Betrag** | Betrag × Wahrscheinlichkeit |
| **Tage bis zur Fälligkeit** | Fälligkeitsdatum - Heute |
| **Tage in der Phase** | Heute - Phaseneintrittsdatum |
| **Lead-Score** | Punkte basierend auf mehreren Kriterien |
<Tip>
Ein vollständiges Beispiel für das Nachverfolgen der Zeit in Pipeline-Phasen finden Sie unter [Verfolgen, wie lange Chancen in jeder Phase bleiben](/l/de/user-guide/views-pipelines/how-tos/track-time-in-stage).
</Tip>
## Einfache Formel: Verkettung
### Beispiel: Vollständigen Namen automatisch ausfüllen
**Ziel**: Vor- und Nachname automatisch zu einem Feld für den vollständigen Namen kombinieren.
### Einrichtung
1. **Auslöser**: Datensatz wird aktualisiert oder erstellt (Personen)
2. **Filter**: Prüfen, ob sich Vorname oder Nachname geändert hat
3. **Code-Aktion**:
```javascript
export const main = async (params) => {
const { firstName, lastName } = params;
const fullName = [firstName, lastName]
.filter(Boolean)
.join(' ');
return { fullName };
};
```
4. **Datensatz aktualisieren**: Vollständigen Namen auf `{{code.fullName}}` setzen
## Numerische Formel: Erwarteter Betrag
### Beispiel: Erwarteten Umsatz berechnen
**Ziel**: Den Chancenbetrag mit der Wahrscheinlichkeit multiplizieren, um den erwarteten Betrag zu erhalten.
Den vollständigen Workflow finden Sie unter [Erwarteten Betrag in der Pipeline anzeigen](/l/de/user-guide/views-pipelines/how-tos/show-expected-amount-in-pipeline).
### Einrichtung
1. **Auslöser**: Datensatz wird aktualisiert (Chancen, Feld Betrag ODER Wahrscheinlichkeit)
2. **Code-Aktion**:
```javascript
export const main = async (params) => {
const { amount, probability } = params;
const expectedAmount = (amount || 0) * (probability || 0) / 100;
return { expectedAmount };
};
```
3. **Datensatz aktualisieren**: Erwarteten Betrag auf `{{code.expectedAmount}}` setzen
## Datumsformel: Tagesberechnung
### Beispiel: Tage bis zur Fälligkeit einer Aufgabe
**Ziel**: Berechnen, wie viele Tage bis zum Fälligkeitsdatum einer Aufgabe verbleiben.
### Einrichtung
1. **Auslöser**: Datensatz wird aktualisiert oder erstellt (Aufgaben, Feld Fälligkeitsdatum)
2. **Code-Aktion**:
```javascript
export const main = async (params) => {
const { dueDate } = params;
if (!dueDate) {
return { daysUntilDue: null };
}
const due = new Date(dueDate);
const today = new Date();
const diffTime = due - today;
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
return { daysUntilDue: diffDays };
};
```
3. **Datensatz aktualisieren**: Tage bis zur Fälligkeit auf `{{code.daysUntilDue}}` setzen
<Note>
Negative Werte weisen auf überfällige Aufgaben hin. Sie können dieses Feld verwenden, um Aufgaben nach Dringlichkeit zu filtern oder zu sortieren.
</Note>
## Bedingte Formel: Lead-Score
### Beispiel: Lead-Score anhand von Kriterien berechnen
**Ziel**: Leads anhand von Unternehmensgröße, Branche und Engagement bewerten.
### Einrichtung
1. **Auslöser**: Datensatz wird aktualisiert (Personen oder Unternehmen)
2. **Code-Aktion**:
```javascript
export const main = async (params) => {
const { companySize, industry, hasEmail, hasPhone, source } = params;
let score = 0;
// Company size scoring
if (companySize === 'Enterprise') score += 30;
else if (companySize === 'Mid-Market') score += 20;
else if (companySize === 'SMB') score += 10;
// Industry scoring
const targetIndustries = ['Technology', 'Finance', 'Healthcare'];
if (targetIndustries.includes(industry)) score += 25;
// Contact info scoring
if (hasEmail) score += 10;
if (hasPhone) score += 15;
// Source scoring
if (source === 'Referral') score += 20;
else if (source === 'Website') score += 10;
return { leadScore: score };
};
```
3. **Datensatz aktualisieren**: Lead-Score auf `{{code.leadScore}}` setzen
## Textformel: Domain-Extraktion
### Beispiel: Domain aus E-Mail extrahieren
**Ziel**: Die E-Mail-Domain automatisch extrahieren und speichern.
### Einrichtung
1. **Auslöser**: Datensatz wird aktualisiert (Personen, E-Mail-Feld)
2. **Code-Aktion**:
```javascript
export const main = async (params) => {
const { email } = params;
if (!email) return { domain: null };
const domain = email.split('@')[1]?.toLowerCase();
return { domain };
};
```
3. **Datensatz aktualisieren**: Feld Domain auf `{{code.domain}}` setzen
## Beste Praktiken
### Leistung
* Nur bei relevanten Feldänderungen auslösen
* Filter verwenden, um Datensätze ohne Berechnungsbedarf zu überspringen
* Komplexe Berechnungen in Workflows mit hohem Volumen vermeiden
### Fehlerbehandlung
* Vor Berechnungen auf null/undefined-Werte prüfen
* Standardwerte verwenden, wenn Daten fehlen
* Klare Fehlermeldungen zurückgeben, wenn Berechnungen fehlschlagen
### Tests
* Mit Randfällen testen (leere Felder, Nullwerte)
* Berechnungen vor der Aktivierung manuell überprüfen
* Workflow-Ausführungen auf unerwartete Ergebnisse überwachen
## Verwandt
* [Erwarteten Betrag in der Pipeline anzeigen](/l/de/user-guide/views-pipelines/how-tos/show-expected-amount-in-pipeline)
* [Zeit in der Phase nachverfolgen](/l/de/user-guide/views-pipelines/how-tos/track-time-in-stage)
* [Workflow-Aktionen](/l/de/user-guide/workflows/capabilities/workflow-actions)

View File

@@ -0,0 +1,127 @@
---
title: Teammitglieder über eine zu prüfende Notiz benachrichtigen
description: Senden Sie automatische E-Mail-Benachrichtigungen, wenn Sie einem Kollegen die Überprüfung einer Notiz zuweisen.
---
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
<Note>
**Das direkte Taggen von Teammitgliedern in Notizen wird noch nicht unterstützt.** Diese Funktion ist für die zweite Jahreshälfte 2026 geplant. In der Zwischenzeit bietet dieser Workflow einen praktischen Workaround.
</Note>
## Die Herausforderung
Sie möchten einen Kollegen in einer Notiz taggen, damit er eine Benachrichtigung zur Überprüfung erhält. Derzeit unterstützt Twenty keine @-Erwähnungen in Notizen oder Aufgaben.
## Der Workaround
Anstatt im Notiztext zu taggen, können Sie:
1. Erstellen Sie ein **Reviewer**-Beziehungsfeld im Objekt Notizen
2. Weisen Sie den Reviewer beim Erstellen oder Bearbeiten der Notiz zu
3. Lassen Sie einen Workflow automatisch eine E-Mail an den Prüfer mit einem Link zur Notiz senden
<Warning>
**Einschränkung**: Mit diesem Ansatz kann pro Feld nur ein Reviewer zugewiesen werden. Wenn Sie mehrere Personen benachrichtigen müssen, erstellen Sie zusätzliche Beziehungsfelder (z. B. Reviewer 1, Reviewer 2). Das skaliert nicht gut, wenn Sie viele Teammitglieder auf einmal taggen müssen.
</Warning>
## Schritt-für-Schritt-Einrichtung
### Schritt 1: Reviewer-Feld erstellen
<img src="/images/user-guide/workflows/reviewer-field-for-note.png" style={{width:'100%'}} />
1. Gehen Sie zu **Einstellungen → Datenmodell → Notizen**
2. Klicken Sie auf **Feld hinzufügen**
3. Konfigurieren:
| Einstellung | Wert |
| ---------------------- | ------------------------------------------- |
| **Name** | Reviewer |
| **Typ** | Beziehung |
| **Verknüpftes Objekt** | Arbeitsbereichsmitglied |
| **Beziehungstyp** | Viele Notizen → Ein Arbeitsbereichsmitglied |
4. Speichern Sie das Feld
### Schritt 2: Workflow erstellen
<VimeoEmbed videoId="1151897168" title="Video-Demonstration" />
#### Workflow-Trigger erstellen
1. Gehen Sie zur Hauptansicht und erstellen Sie einen neuen Workflow
2. Wählen Sie **Record Updated** als Auslöser
3. Wählen Sie **Note** als Objekt und geben Sie das Reviewer-Feld an.
4. Dadurch wird der Workflow immer dann ausgelöst, wenn der Reviewer einer Notiz aktualisiert wird.
#### Filter hinzufügen, um zu prüfen, ob der Reviewer gerade zugewiesen wurde
Fügen Sie eine **Filter**-Aktion hinzu, damit der Workflow nur fortgesetzt wird, wenn ein Reviewer zugewiesen ist:
| Bedingung | Wert |
| ------------ | -------------- |
| **Reviewer** | ist nicht leer |
#### Nach dem Arbeitsbereichsmitglied suchen
1. Fügen Sie eine **Datensätze suchen**-Aktion hinzu
2. Wählen Sie **Arbeitsbereichsmitglied** (unter Erweiterten Objekten)
3. Fügen Sie einen Filter hinzu:
| Bedingung | Wert |
| --------- | -------------------------------- |
| **ID** | entspricht `{{note.reviewerId}}` |
Dadurch wird der vollständige Datensatz des Arbeitsbereichsmitglieds abgerufen, einschließlich der E-Mail-Adresse und des Namens.
#### Benachrichtigungs-E-Mail senden
1. Fügen Sie eine **E-Mail senden**-Aktion hinzu
2. Konfigurieren:
| Feld | Wert |
| ----------- | ------------------------------------------------------------------- |
| **An** | Datensatz suchen → Erstes Arbeitsbereichsmitglied → Benutzer-E-Mail |
| **Betreff** | Eine Notiz benötigt Ihre Überprüfung |
| **Inhalt** | Siehe Beispiel unten |
**Beispiel für den E-Mail-Text:**
```text
Hi {{searchRecord.firstWorkspaceMember.name.firstName}},
You've been assigned to review a note.
View the note here:
https://yourSubDomain.twenty.com/object/note/{{recordIsUpdated.id}}
Best,
Twenty
```
<Note>
Ersetzen Sie `yourSubDomain` durch die tatsächliche Subdomain Ihres Twenty-Arbeitsbereichs.
</Note>
#### Testen und Aktivieren
1. Klicken Sie auf **Test**, um den Workflow manuell auszuführen
2. Erstellen oder bearbeiten Sie eine Notiz und weisen Sie einen Reviewer zu
3. Prüfen Sie den Posteingang des Reviewers auf die Benachrichtigungs-E-Mail
4. Aktivieren Sie den Workflow
## Verwendung
Sobald eingerichtet, kann Ihr Team diesen Workflow wie folgt verwenden:
1. Erstellen einer neuen Notiz (oder Bearbeiten einer bestehenden)
2. Auswählen eines Kollegen im Feld **Reviewer**
3. Der Kollege erhält automatisch eine E-Mail mit einem direkten Link zur Notiz
## Verwandt
* [Workflow-Trigger](/l/de/user-guide/workflows/capabilities/workflow-triggers)
* [E-Mails aus Workflows senden](/l/de/user-guide/workflows/capabilities/send-emails-from-workflows)
* [Benutzerdefinierte Felder erstellen](/l/de/user-guide/data-model/how-tos/create-custom-fields)
* [Beziehungsfelder erstellen](/l/de/user-guide/data-model/how-tos/create-relation-fields)

View File

@@ -0,0 +1,106 @@
---
title: E-Mail-Benachrichtigungen zu fälligen Aufgaben senden
description: Benachrichtigen Sie Teammitglieder automatisch über ihre anstehenden oder überfälligen Aufgaben.
---
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
<img src="/images/user-guide/workflows/email_tasks_due.png" style={{width:'100%'}} />
Senden Sie tägliche E-Mail-Erinnerungen an jedes Teammitglied zu den heute fälligen Aufgaben.
## Übersicht
Dieser Workflow läuft nach einem Zeitplan und:
1. Ruft alle Mitglieder des Arbeitsbereichs ab
2. Durchläuft jedes Mitglied
3. Ermittelt deren heute fällige Aufgaben
4. Formatiert und sendet eine personalisierte E-Mail
## Schritt-für-Schritt-Einrichtung
<VimeoEmbed videoId="1147463514" title="Video-Demonstration" />
### Schritt 1: Trigger konfigurieren
1. Gehen Sie zu **Einstellungen → Workflows** und erstellen Sie einen neuen Workflow
2. Wählen Sie **Nach Zeitplan** als Trigger
3. Verwenden Sie einen Cron-Ausdruck für täglich um 8:00 Uhr: `0 8 * * *`
### Schritt 2: Nach allen Arbeitsbereichsmitgliedern suchen
1. Fügen Sie eine **Datensätze suchen**-Aktion hinzu
2. Wählen Sie **Arbeitsbereichsmitglieder** (unter Erweiterten Objekten)
3. Keine Filter erforderlich — dadurch werden alle Mitglieder zurückgegeben
### Schritt 3: Einen Iterator hinzufügen
1. Fügen Sie eine **Iterator**-Aktion hinzu
2. Setzen Sie das Eingabearray auf die Arbeitsbereichsmitglieder aus dem vorherigen Schritt
3. Alle Aktionen innerhalb des Iterators werden einmal pro Mitglied ausgeführt
### Schritt 4: Nach heute fälligen Aufgaben suchen (im Iterator)
1. Fügen Sie im Iterator eine **Datensätze suchen**-Aktion hinzu
2. Wählen Sie **Aufgaben** als Objekt
3. Filter hinzufügen:
* **Zuständige Person** = aktuelles Arbeitsbereichsmitglied (aus dem Iterator)
* **Fälligkeitsdatum** = heute
### Schritt 5: Aufgaben in E-Mail-Inhalt formatieren (im Iterator)
Fügen Sie eine **Code**-Aktion hinzu, um die Aufgaben in eine lesbare Liste mit Links zu formatieren:
```javascript
export const main = async (params: {
tasksDue?: Array<{ id: string; title: string }> | null | string;
}) => {
const tasksDue =
typeof params.tasksDue === "string"
? JSON.parse(params.tasksDue)
: params.tasksDue;
if (!Array.isArray(tasksDue) || tasksDue.length === 0) {
return {
formattedTasks: "No tasks due today."
};
}
const formattedTasks = tasksDue
.map(
t =>
`${t.title}\nhttps://yourSubDomain.twenty.com/object/task/${t.id}`
)
.join("\n\n");
return { formattedTasks };
};
```
<Note>
Ersetzen Sie `yourSubDomain` durch die tatsächliche Twenty-Arbeitsbereichs-Subdomain.
</Note>
### Schritt 6: E-Mail senden (im Iterator)
1. Fügen Sie eine **E-Mail senden**-Aktion hinzu (weiterhin im Iterator)
2. Konfigurieren:
| Feld | Wert |
| ----------- | ---------------------------------------------------------------------------------- |
| **An** | `{{iterator.currentItem.userEmail}}` (E-Mail-Adresse des Arbeitsbereichsmitglieds) |
| **Betreff** | Ihre heute fälligen Aufgaben |
| **Inhalt** | `{{code.formattedTasks}}` |
### Schritt 7: Testen und aktivieren
1. Klicken Sie auf **Test**, um den Workflow manuell auszuführen
2. Überprüfen Sie die Posteingänge auf E-Mails
3. Aktivieren Sie den Workflow
## Verwandt
* [Workflow-Aktionen](/l/de/user-guide/workflows/capabilities/workflow-actions)
* [E-Mails aus Workflows senden](/l/de/user-guide/workflows/capabilities/send-emails-from-workflows)
* [Arrays in Code-Aktionen verarbeiten](/l/de/user-guide/workflows/how-tos/advanced-configurations/handle-arrays-in-code-actions)

View File

@@ -0,0 +1,21 @@
---
title: Professionelle Dienstleistungen
description: Holen Sie sich professionelle Hilfe beim Aufbau komplexer Workflows und Automatisierungen vom Team und den zertifizierten Partnern von Twenty.
---
## Wann benötigen Sie professionelle Hilfe?
Erwägen Sie professionelle Dienstleistungen für:
* Komplexe Multi-System-Integrationen
* Erweiterte Geschäftslogik und Automatisierungsregeln
* Datenverarbeitungs-Workflows im großen Maßstab
* Entwicklung benutzerdefinierter APIs
* Schulung des Teams und Optimierung der Workflows
* Wenn Ihnen interne Ressourcen fehlen
## Dienstleistungsoptionen
### Implementierungspartner
Arbeiten Sie mit zertifizierten Partnern für erweiterte Anpassungen. Kontaktieren Sie uns unter [contact@twenty.com](mailto:contact@twenty.com), um mit unseren [Implementierungspartnern](https://twenty.com/partners) in Kontakt zu treten.

View File

@@ -0,0 +1,170 @@
---
title: Workflow-Fehlerbehebung
description: Häufige Workflow-Probleme und wie Sie sie beheben.
---
## Häufige Probleme und Lösungen
### Workflow wird nicht ausgelöst
**Symptome**: Ihr Workflow wird nicht ausgeführt, wenn Sie es erwarten.
**Mögliche Ursachen**:
1. **Workflow nicht aktiviert**: Stellen Sie sicher, dass der Workflow auf "Active" und nicht auf "Draft" gesetzt ist
2. **Trigger-Bedingungen nicht erfüllt**: Überprüfen Sie, ob der Trigger Ihrem erwarteten Ereignis entspricht
3. **Feld nicht überwacht**: Bei "Record is Updated"-Triggern stellen Sie sicher, dass das betreffende Feld überwacht wird
4. **Berechtigungen**: Prüfen Sie, ob Sie die Berechtigung haben, Workflows auszuführen
**Lösungen**:
* Überprüfen Sie den Workflow-Status in der Workflow-Liste
* Testen Sie mit der spezifischen Aktion, von der Sie erwarten, dass sie ihn auslöst
* Überprüfen Sie die Trigger-Konfiguration
* Wenden Sie sich wegen der Berechtigungen an Ihren Administrator
### Workflow-Trigger zu früh (leere Felder)
**Symptome**: Beim manuellen Erstellen eines Datensatzes in der UI wird Ihr Workflow ausgelöst, bevor Sie alle Felder ausfüllen konnten. Der Workflow läuft mit überwiegend leeren Feldwerten.
**Warum das passiert**: Twenty speichert alles in Echtzeit — es gibt keinen separaten "edit"- vs. "read"-Modus. Wenn Sie einen Datensatz erstellen, wird er sofort gespeichert und löst das Ereignis "Record is created" aus, bevor Sie weitere Felder ausfüllen können.
**Wann "Record is created" gut funktioniert**:
* Über API-Aufrufe erstellte Datensätze (Felder werden in einer einzigen Anfrage befüllt)
* Über Import erstellte Datensätze
* Automatisches Erstellen von Datensätzen aus anderen Workflows
**Lösung**: Für Datensätze, die manuell in der UI erstellt werden, verwenden Sie stattdessen **"Record is created or updated"** als Trigger. Auf diese Weise:
* Der Workflow wird ausgelöst, nachdem der Benutzer das Ausfüllen und Speichern der Felder abgeschlossen hat
* Sie erhalten die vollständigen Daten statt leerer Werte
<Tip>
Wenn der Workflow nur einmal pro Datensatz ausgeführt werden soll, fügen Sie eine Filter-Aktion hinzu, um ein Feld wie `createdAt equals updatedAt` (erste Speicherung) zu prüfen, oder verwenden Sie ein benutzerdefiniertes Kontrollkästchen, um zu verfolgen, ob der Workflow bereits ausgeführt wurde.
</Tip>
### Fehlgeschlagene Aktionen
**Symptome**: Der Workflow wird ausgeführt, aber einige Aktionen schlagen fehl.
**Mögliche Ursachen**:
1. **Fehlende Daten**: Erforderliche Felder sind leer
2. **Ungültige Verweise**: Variablen aus vorherigen Schritten existieren nicht
3. **API-Fehler**: Externe Dienste liefern Fehler zurück
4. **Berechtigungsprobleme**: Die Aktion erfordert Berechtigungen, die Sie nicht haben
**Lösungen**:
* Überprüfen Sie die Details der Workflow-Ausführung auf Fehlermeldungen
* Stellen Sie sicher, dass alle Pflichtfelder Werte haben
* Testen Sie die API-Verbindungen separat
* Überprüfen Sie die Rollenberechtigungen
### Fehler bei HTTP-Anfragen
**Symptome**: HTTP-Request-Aktionen schlagen fehl oder liefern unerwartete Ergebnisse.
**Häufige Fehlercodes**:
* **400**: Ungültige Anfrage - überprüfen Sie das Format des Request-Body
* **401**: Nicht autorisiert - überprüfen Sie den API-Schlüssel
* **403**: Verboten - überprüfen Sie die API-Berechtigungen
* **404**: Nicht gefunden - überprüfen Sie die Endpunkt-URL
* **429**: Zu viele Anfragen - implementieren Sie eine Ratenbegrenzung
* **500**: Serverfehler - Problem mit dem externen Dienst
**Lösungen**:
* Überprüfen Sie die API-Endpunkt-URL
* Überprüfen Sie die Authentifizierungs-Header
* Testen Sie den API-Aufruf zunächst außerhalb von Twenty
* Fügen Sie Fehlerbehandlung in Code-Aktionen hinzu
### Fehler in Code-Aktionen
**Symptome**: JavaScript-Code wird nicht ausgeführt.
**Häufige Probleme**:
1. **Syntaxfehler**: Tippfehler oder ungültiges JavaScript
2. **Undefinierte Variablen**: Verweise auf Variablen, die nicht existieren
3. **Typfehler**: Operationen auf falschen Datentypen
4. **Timeouts**: Code benötigt zu lange zur Ausführung
**Lösungen**:
* Verwenden Sie die integrierte Validierung des Code-Editors
* Testen Sie die Code-Logik zuerst in einer JavaScript-Konsole
* Fügen Sie console.log-Anweisungen zum Debuggen hinzu
* Vereinfachen Sie komplexe Operationen
### E-Mail wird nicht gesendet
**Symptome**: Die Aktion "Send Email" liefert keine E-Mails aus.
**Mögliche Ursachen**:
1. **Kein E-Mail-Konto verbunden**: Prüfen Sie Settings → Accounts
2. **Ungültige E-Mail-Adresse**: Die E-Mail-Adresse des Empfängers ist fehlerhaft
3. **Sendelimits**: Ratenbegrenzung des E-Mail-Anbieters erreicht
4. **Spamfilter**: E-Mails werden blockiert
**Lösungen**:
* Überprüfen Sie die Verbindung des E-Mail-Kontos
* Validieren Sie die E-Mail-Adressen der Empfänger
* Überprüfen Sie die Limits des E-Mail-Anbieters
* Überprüfen Sie den E-Mail-Inhalt auf Spam-Auslöser
## Workflows debuggen
### Workflow-Läufe verwenden
1. Gehen Sie zum Workflow-Editor
2. Öffnen Sie das Panel **Runs**
3. Finden Sie den fehlgeschlagenen Lauf
4. Klicken Sie, um die Details Schritt für Schritt zu sehen
5. Überprüfen Sie Fehlermeldungen und Ausgabedaten
### Einzelschritte testen
1. Für Code-Aktionen verwenden Sie die Schaltfläche **Test**
2. Für HTTP-Anfragen testen Sie den Endpunkt separat
3. Erstellen Sie Testdatensätze, um Workflows auszulösen
4. Verwenden Sie manuelle Trigger für kontrollierte Tests
### Häufige Debugging-Muster
**Logging hinzufügen**:
Verwenden Sie Code-Aktionen, um Zwischenwerte zum Debuggen zu protokollieren.
**Schritte isolieren**:
Testen Sie jeden Schritt unabhängig, um Fehler zu identifizieren.
**Datenfluss prüfen**:
Stellen Sie sicher, dass jeder Schritt die erwarteten Eingabedaten erhält.
## Bewährte Verfahren zur Vermeidung von Problemen
### Vor der Aktivierung
* Testen Sie im Entwurfsmodus gründlich
* Validieren Sie alle API-Verbindungen
* Überprüfen Sie die Trigger-Bedingungen sorgfältig
* Dokumentieren Sie das erwartete Verhalten
### Während der Entwicklung
* Verwenden Sie aussagekräftige Schrittnamen
* Fügen Sie Kommentare in Code-Aktionen hinzu
* Testen Sie mit realistischen Daten
* Planen Sie für Randfälle
### Nach der Aktivierung
* Überwachen Sie die ersten Läufe genau
* Richten Sie Benachrichtigungen für Fehler ein
* Überprüfen Sie den Ausführungsverlauf regelmäßig
* Halten Sie Workflows nach Möglichkeit einfach

View File

@@ -0,0 +1,236 @@
---
title: FAQ zu Workflows
description: Häufig gestellte Fragen zu Workflows in Twenty.
---
<AccordionGroup>
<Accordion title="Warum kann ich einen Workflow nicht aktivieren?">
Dies ist wahrscheinlich ein Berechtigungsproblem. Sie benötigen Zugriff auf Workflows, um sie zu erstellen und zu aktivieren.
**Lösung**: Wenden Sie sich an Ihren Workspace-Administrator, damit er Ihnen unter **Einstellungen → Mitglieder → Rollen** Zugriff auf Workflows gewährt.
Wenn Sie den Bereich Workflows in Ihrer Seitenleiste überhaupt nicht sehen, bestätigt dies ein Berechtigungsproblem.
</Accordion>
<Accordion title="Warum sehe ich die Schaltfläche für manuelle Workflows nicht in der oberen Navigationsleiste?">
Manuelle Workflows erscheinen nur in der Navigationsleiste, wenn sie korrekt konfiguriert sind:
1. Der Workflow muss **aktiviert** sein (nicht im Entwurfsmodus)
2. Die Platzierung in der Navigationsleiste muss auf **Pinned** gesetzt sein
3. Für Single-/Bulk-Trigger müssen Sie sich auf der richtigen Objektseite befinden
**Zum Überprüfen**: Öffnen Sie den Workflow → klicken Sie auf den Trigger → prüfen Sie, dass "Navbar placement" auf "Pinned" gesetzt ist.
Unabhängig von den Navbar-Einstellungen können Sie manuelle Workflows jederzeit über **Cmd + K** (oder **Ctrl + K**) aufrufen.
</Accordion>
<Accordion title="Was ist der Unterschied zwischen manuellen Single-, Global- und Bulk-Triggern?">
| Typ | Erforderliche Datensätze | Workflow-Läufe |
| --- | ------------------------ | -------------- |
\| **Global** | Keine | Einmal, ohne Datensatzeingabe |
\| **Single** | Ein oder mehrere ausgewählte Datensätze | Einmal pro ausgewähltem Datensatz |
\| **Bulk** | Ein oder mehrere ausgewählte Datensätze | Einmal, mit allen Datensätzen als Array |
* **Global**: Verwenden Sie dies, wenn der Workflow keinen Datensatzkontext benötigt (z. B. einen Bericht erzeugen)
* **Single**: Verwenden Sie dies, wenn Sie jeden ausgewählten Datensatz unabhängig verarbeiten möchten (z. B. einzelne E-Mails senden)
* **Bulk**: Verwenden Sie dies, wenn Sie Datensätze gemeinsam verarbeiten oder den Credit-Verbrauch optimieren möchten (erfordert die Iterator-Aktion)
Siehe [Workflow-Trigger](/l/de/user-guide/workflows/capabilities/workflow-triggers) für Details.
</Accordion>
<Accordion title="Ich sehe keinen If/Else-Knoten. Was sollte ich tun?">
Ein expliziter If/Else-Knoten ist noch nicht verfügbar, steht aber auf unserer Roadmap.
**Aktuelle Problemumgehung**: Erstellen Sie mehrere Verzweigungen von Ihrem Schritt aus, die jeweils mit einer **Filter**-Aktion beginnen:
```
Step 1
│
├── Branch A: Filter (condition = true) → Actions...
│
└── Branch B: Filter (condition = false) → Actions...
```
Nur die Verzweigung, deren Filterbedingung erfüllt ist, führt die nachfolgenden Aktionen aus.
Siehe [Verzweigungen verwenden](/l/de/user-guide/workflows/capabilities/workflow-branches) für eine Schritt-für-Schritt-Anleitung.
</Accordion>
<Accordion title="Laufen Workflow-Verzweigungen parallel?">
**Ja**, Verzweigungen laufen standardmäßig parallel.
Wenn nur eine Verzweigung ausgeführt werden soll:
* Fügen Sie am Anfang jeder Verzweigung eine **Filter**-Aktion hinzu
* Legen Sie gegensätzliche Bedingungen fest (z. B., Verzweigung A: status = "Open", Verzweigung B: status ≠ "Open")
Verzweigungen, deren Filterbedingung fehlschlägt, werden nicht weiter ausgeführt; andere laufen weiter.
</Accordion>
<Accordion title="Kann ich Verzweigungen wieder zusammenführen?">
**Ja**. Nachdem Ihre parallelen Verzweigungen abgeschlossen sind, können Sie einen Schritt hinzufügen, mit dem beide Verzweigungen verbunden werden.
Im Workflow-Editor:
1. Schließen Sie Ihre verzweigten Aktionen ab
2. Fügen Sie nach den Verzweigungen einen neuen Schritt hinzu
3. Ziehen Sie Verbindungen vom Ende jeder Verzweigung zu diesem neuen Schritt
Der zusammengeführte Schritt wird ausgeführt, nachdem alle verbundenen Verzweigungen abgeschlossen sind.
</Accordion>
<Accordion title="Wie lautet das Limit für die Ergebnisse von Search Records?">
**Search Records gibt maximal 200 Datensätze zurück.**
Wenn Sie mehr verarbeiten müssen:
* Fügen Sie spezifischere Filter hinzu, um die Ergebnisse zu reduzieren
* Verwenden Sie geplante Workflows, um in Batches zu verarbeiten
* Ziehen Sie die Verwendung der API für Massenoperationen in Betracht
Für die meisten Workflows sind 200 Datensätze ausreichend. Wenn Sie dieses Limit regelmäßig erreichen, sollten Sie Ihre Automatisierung neu strukturieren.
</Accordion>
<Accordion title="Kann ich Personen in Workflow-E-Mails in CC setzen?">
**Noch nicht.** CC- und BCC-Felder für die Aktion "Send Email" stehen auf unserer Roadmap.
**Aktuelle Problemumgehung**: Fügen Sie mehrere "Send Email"-Aktionen hinzu, um an zusätzliche Empfänger zu senden, oder verwenden Sie einen HTTP Request, um über einen externen E-Mail-Dienst zu senden, der CC unterstützt.
</Accordion>
<Accordion title="Wie verwende ich Ausgaben aus vorherigen Schritten?">
Jede Aktion erzeugt Ausgabedaten, die in nachfolgenden Schritten verwendet werden können.
**So verweisen Sie auf Daten aus vorherigen Schritten**:
* Verwenden Sie den Variablenauswähler, wenn Sie ein Feld konfigurieren
* Oder geben Sie `{{stepName.fieldName}}` direkt ein
**Beispiele**:
* Trigger-Daten: `{{trigger.object.email}}`
* Suchergebnisse: `{{searchRecords[0].name}}`
* Code-Ausgabe: `{{code.calculatedValue}}`
Fahren Sie in der Aktionskonfiguration mit der Maus über ein beliebiges Feld, um verfügbare Variablen aus vorherigen Schritten zu sehen.
</Accordion>
<Accordion title="Warum schlägt mein Iterator fehl?">
**Iterator erfordert eine Array-Eingabe.** Häufige Probleme:
1. **Eingabe ist kein Array**: Stellen Sie sicher, dass Sie Ergebnisse von Search Records oder einer anderen Aktion übergeben, die ein Array zurückgibt
2. **Array ist leer**: Fügen Sie vor Iterator einen Filter hinzu, um `{{searchRecords.length}} > 0` zu prüfen
3. **Falsche Variable ausgewählt**: Stellen Sie sicher, dass Sie das Array selbst auswählen, nicht einen einzelnen Datensatz
**Korrekte Einrichtung**:
1. Search Records (gibt ein Array zurück)
2. Filter: length > 0
3. Iterator: Wählen Sie `{{searchRecords}}` aus
4. Aktionen innerhalb des Iterators verwenden `{{iterator.currentItem.fieldName}}`
</Accordion>
<Accordion title="Wie lang ist die maximale Ausführungszeit für Code-Aktionen?">
Code-Aktionen (Logikfunktionen) haben ein **Standard-Timeout von 5 Minuten** (300 Sekunden).
Das maximal konfigurierbare Timeout beträgt **15 Minuten** (900 Sekunden).
Wenn Ihr Code dieses Limit überschreitet, schlägt die Aktion mit einem Timeout-Fehler fehl.
**Tipps zur Vermeidung von Timeouts**:
* Zerlegen Sie große Operationen mithilfe des Iterators in kleinere Teile
* Vermeiden Sie rechenintensive Vorgänge; verwenden Sie für aufwändige Verarbeitung externe Dienste über HTTP Request
* Optimieren Sie Ihren Code, um die Ausführungszeit zu reduzieren
* Wenn Sie längere Verarbeitung benötigen, sollten Sie geplante Workflows verwenden, die Daten in Batches verarbeiten
</Accordion>
<Accordion title="Wie lese ich Workflow-Ausführungen?">
Workflow-Ausführungen zeigen die Ausführungshistorie und helfen beim Debuggen von Problemen.
**Auf Ausführungen zugreifen**:
* Im Workflow-Editor → **Runs**-Bereich auf der rechten Seite
* Oder gehen Sie in der Seitenleiste zu **Workflow Runs**
**Eine Ausführung verstehen**:
* **Status**: Running, Completed, Failed, Waiting
* **Schritte**: Sehen Sie, welche Schritte ausgeführt wurden und deren Ausgabe
* **Fehler**: Klicken Sie auf fehlgeschlagene Schritte, um Fehlermeldungen zu sehen
* **Daten**: Betrachten Sie Eingabe-/Ausgabedaten in jedem Schritt
Siehe [Workflow-Ausführungen](/l/de/user-guide/workflows/capabilities/workflow-runs) für Details.
</Accordion>
<Accordion title="Warum sehe ich meine Workflow-Ausführungen nicht?">
Workflow-Ausführungen schlagen möglicherweise aufgrund von Rate Limits sofort fehl. Twenty erzwingt ein hartes Limit von 5.000 Ausführungen pro Stunde und Workspace.
Wenn Sie dieses Limit überschreiten, werden Workflows sofort als fehlgeschlagen markiert und erscheinen nicht in Ihrer Ausführungsliste.
**Häufige Szenarien, die dieses Limit erreichen**:
* Auswahl von mehr als 5.000 Datensätzen mit einem manuellen Single-Trigger
* Mehrere Workflows, die gleichzeitig in Ihrem Workspace ausgeführt werden
* Hochfrequente automatisierte Trigger (z. B. Record Updated bei einem stark genutzten Objekt)
**Lösungen**:
* Verwenden Sie **Bulk**-Trigger statt Single, um viele Datensätze in einer Ausführung zu verarbeiten
* Staffeln Sie große Batch-Vorgänge zeitlich
* Verwenden Sie Filter, um die Triggerfrequenz zu reduzieren
* Planen Sie umfangreiche Workflows außerhalb der Stoßzeiten
</Accordion>
<Accordion title="Wie lauten die Workflow-Rate-Limits?">
Twenty hat zwei Rate-Limits, um die Systemstabilität sicherzustellen:
| Limit | Wert | Verhalten |
| ----- | ---- | --------- |
\| **Weiches Limit** | 100 Ausführungen/Minute | Ausführungen werden im Status "Not Started" in die Warteschlange gestellt und nach und nach verarbeitet |
\| **Hartes Limit** | 5.000 Ausführungen/Stunde | Ausführungen schlagen sofort fehl |
**Weiches Limit (100/Min.)**: Ihre Workflows schlagen nicht fehl – sie warten lediglich in der Warteschlange und werden mit der Zeit verarbeitet. Sie können mehr als 100 Datensätze auslösen; die Ausführung wird langsamer sein.
**Hartes Limit (5.000/Stunde)**: Dies gilt für Ihren gesamten Workspace. Wenn alle Ihre Workflows zusammen in einer Stunde mehr als 5.000 Ausführungen erreichen, schlagen zusätzliche Ausführungen sofort fehl.
**Tipps, um innerhalb der Limits zu bleiben**:
* Verwenden Sie für große Batches Bulk-Trigger mit Iterator statt Single-Triggern
* Kombinieren Sie verwandte Automatisierungen in weniger Workflows
* Verwenden Sie geplante Workflows, um die Last über die Zeit zu verteilen
</Accordion>
<Accordion title="Kann ich eine fehlgeschlagene Workflow-Ausführung erneut ausführen?">
**Nein, derzeit gibt es keine automatische Wiederholungsfunktion.**
Wenn eine Workflow-Ausführung fehlschlägt, müssen Sie:
1. Den Fehler prüfen unter **Einstellungen → Workflows → [Ihr Workflow] → Runs**
2. Das Problem beheben (Daten, Konfiguration oder externer Dienst)
3. Den Workflow erneut manuell für die betroffenen Datensätze auslösen
**Tipps zur Reduzierung von Fehlschlägen**:
* Fügen Sie **Filter**-Knoten hinzu, um Daten vor Aktionen zu validieren
* Verwenden Sie **Search Records**, um zu prüfen, ob verknüpfte Datensätze existieren
* Testen Sie gründlich mit einigen Datensätzen, bevor Sie Massenoperationen durchführen
Eine automatische Wiederholungsfunktion steht auf unserer Roadmap für eine zukünftige Version.
</Accordion>
<Accordion title="Sollte ich Workflows vor CSV-Importen deaktivieren?">
**Ja, wenn Ihre Workflows durch das Erstellen oder Aktualisieren von Datensätzen ausgelöst werden.**
Wenn Sie Daten per CSV importieren, kann jeder erstellte oder aktualisierte Datensatz Workflows auslösen. Ein großer Import (Tausende von Datensätzen) könnte:
* Das Limit von 5.000 Ausführungen/Stunde erreichen
* Erhebliche Workflow-Credits verbrauchen
* Unerwartete E-Mails oder Benachrichtigungen senden
* Doppelte Aufgaben oder Datensätze erstellen
**Vor einem Massenimport**:
1. Gehen Sie zu **Einstellungen → Workflows**
2. Identifizieren Sie Workflows, die durch das Objekt ausgelöst werden, das Sie importieren
3. **Deaktivieren** Sie diese vorübergehend
4. Führen Sie Ihren CSV-Import aus
5. **Reaktivieren** Sie die Workflows, wenn Sie fertig sind
**Alternative**: Wenn die Workflows für importierte Daten ausgeführt werden sollen, importieren Sie in kleineren Batches, um innerhalb der Rate-Limits zu bleiben.
</Accordion>
<Accordion title="Wie bereinige ich mein Workflow-Layout?">
Wenn Ihre Workflow-Canvas unübersichtlich aussieht, mit verstreuten Knoten, können Sie sie automatisch organisieren:
1. Klicken Sie mit der rechten Maustaste irgendwo auf der Workflow-Canvas
2. Klicken Sie auf **Tidy up workflow**
Dadurch werden alle Knoten automatisch in ein übersichtliches, organisiertes Layout gebracht.
</Accordion>
</AccordionGroup>