Runtime-Umgebung

Orbitype verfügt über eine gemeinsame Runtime-Umgebung, auf die Agenten über ihre Tools zugreifen können, Workflows über ihre Nodes, Artefakte über ihre Server Actions sowie Orbitype Intelligence im interaktiven Ausführungsmodus.

Orbitype Environment Injections

Orbi-Objekt

Workflow-Funktionen haben Zugriff auf ein injiziertes orbi-Objekt. Es repräsentiert den aktuellen Projekt-Kontext und ermöglicht dir einen konsistenten Zugriff auf Projekt-Metadaten, Connectors und konfigurierte Credentials.

async ({ orbi }) => {
  const { id, name } = orbi.project
  return { projectId: id, projectName: name }
}

Connectors

orbi.project.connectors listet alle Connectors im aktuellen Projekt (z.B. SQL, S3). Das ist hilfreich, um verfügbare Integrationen zu entdecken und Connector-IDs bei Bedarf zu referenzieren.

async ({ orbi }) => {
  const connectors = orbi.project.connectors.map(c => ({
    id: c.id,
    name: c.name,
    implementation: c.implementation
  }))

  return { connectors }
}

Credentials

orbi.project.credentials enthält konfigurierte Credential-Einträge für das aktuelle Projekt. Das ist der empfohlene Weg, um Credential-Values zu beziehen.

async ({ orbi, linkedin }) => {
  const accountId = orbi.project.credentials
    .find(x => x.name === 'linkedin')?.value

  if (!accountId) {
    throw new Error('Missing credential: linkedin')
  }

  const self = await linkedin.connect(accountId)
  return { providerId: self.provider_id }
}

API Keys

orbi.project.apiKeys enthält API-Key-Metadaten für das aktuelle Projekt. API-Keys sind Secrets: nicht loggen und in produktiven Workflows nicht als Output zurückgeben.

async ({ orbi }) => {
  const keys = orbi.project.apiKeys.map(k => ({
    name: k.name,
    connectorId: k.connectorId
  }))

  return { apiKeys: keys }
}

Leads-Datenbank

Nutze die Leads-Datenbank, um passende Personen zu finden und sie bei Bedarf mit Kontaktdaten anzureichern. Das Verhalten ist in Assistant-Tools und im Workflow-Code identisch.

Was möglich ist

  • Suchmodus: liefert Profil-/Firmen-/Kontextfelder (ohne direkte Kontaktfreigabe).
  • Enrich-Modus: liefert ausgewählte Kontaktfelder für bestimmte Leads.
  • Paginierung: unterstützt page/perPage und cursor-basierte Paginierung.
  • Idempotenz: unterstützt excludeIds, um bereits verarbeitete Leads zu überspringen.
  • Credit-bewusst: Kosten hängen vom Modus und den gewählten Enrich-Feldern ab.

Eingabemodell

Gemeinsame Eingaben:

{
  mode?: "search" | "enrich",      // Standard: "search"
  confirmed?: boolean,                // true nach expliziter Freigabe bei hohem Enrich-Preis
  page?: number,                      // Standard: 1
  perPage?: number,                   // max: 100
  cursor?: string,                    // Keyset-Paginierungs-Cursor
  ids?: string[],                     // meist für Enrich-Modus
  excludeIds?: string[],              // bereits verarbeitete Leads auslassen
  fields?: string[]                   // nur für Enrich
}

Typische Filter (alle optional):

{
  query?: string | string[],
  keywords?: string[],
  excludeKeywords?: string[],
  industries?: string[],
  jobTitles?: string[],
  companyNames?: string[],
  locations?: string[],
  locationCountries?: string[],
  skills?: string[],
  interests?: string[],
  countries?: string[],
  minYearsExperience?: number,
  maxYearsExperience?: number,
  minLinkedinConnections?: number,
  hasCompanyWebsite?: boolean,
  hasLinkedinUrl?: boolean
}

Query-Verhalten

  • query: "revops" trifft auf Datensätze zu, bei denen ein durchsuchbares Feld den Begriff enthält.
  • query: ["revops", "berlin"] nutzt AND zwischen den Begriffen; jeder Begriff wird über mehrere Felder gematcht.

Antworten in Search vs. Enrich

Search-Ausgabe (Beispiel):

{
  data: [
    {
      id, fullName, firstName, lastName,
      industry, jobTitle, subRole,
      companyName, companyIndustry, companyWebsite, companySize,
      location, locationCountry,
      yearsExperience, linkedinConnections,
      skills, countries, interests
    }
  ],
  hasMore, nextPage, cursor, nextCursor,
  enrichment: {
    count,
    fields,
    selectedFieldCostCredits,
    estimatedCostCredits,
    pricing,
    filters
  }
}

Enrich-Ausgabe (Beispiel):

{
  data: [
    {
      id,
      email,
      emailAddresses,
      mobileNumbers,
      phoneNumbers,
      linkedinUrl,
      facebookUrl,
      twitterUrl,
      githubUrl
    }
  ],
  rows,
  fields,
  selectedFieldCostCredits,
  costCredits,
  hasMore,
  nextPage,
  cursor,
  nextCursor
}

Verwendung im Workflow-Wrapper

async ({ leads }) => {
  const page1 = await leads.search({
    mode: "search",
    query: ["revops", "outbound"],
    locations: ["Berlin"],
    perPage: 50,
    excludeIds: ["already-processed-id"]
  })

  return {
    rows: page1.data,
    nextCursor: page1.nextCursor,
    credits: leads.getCredits()
  }
}
async ({ leads }) => {
  const enriched = await leads.search({
    mode: "enrich",
    confirmed: true,
    ids: ["lead-id-1", "lead-id-2"],
    fields: ["email", "linkedinUrl"]
  })

  return {
    rows: enriched.data,
    cost: enriched.costCredits,
    credits: leads.getCredits()
  }
}
async ({ leads }) => {
  const batch = await leads.searchMany(
    {
      mode: "search",
      query: "b2b saas",
      excludeIds: ["already-processed-id"]
    },
    { maxRows: 150 }
  )

  return {
    count: batch.count,
    rows: batch.data,
    limited: batch.limited,
    cost: batch.costCredits
  }
}

Empfohlener Ablauf

  1. Mit engen Filtern und kleinem perPage starten (10-25).
  2. Relevanz anhand der Ergebnisse prüfen.
  3. perPage erst erhöhen, wenn die Trefferqualität passt.
  4. Enrich nur für den wirklich benötigten Teil verwenden.
  5. Verarbeitete IDs speichern und bei Retries immer über excludeIds übergeben.
  6. Wenn eine Kostenbestätigung nötig ist: erst Freigabe einholen, dann mit confirmed: true erneut ausführen.

Apollo Integration

Apollo Integration in Orbitype

Diese Dokumentation beschreibt alle verfuegbaren Apollo Actions in Orbitype.
Sie erklaert was jede Action macht, welche Parameter erwartet werden, und enthaelt ein vollstaendiges Beispiel, das jede Apollo Action in einem logischen Ablauf verwendet.

Alle Apollo Funktionen sind ueber das Objekt apollo in der Orbitype Code-Umgebung verfuegbar.


Voraussetzungen

  • Ein Credential mit dem Namen apollo existiert im Projekt

  • Der Code laeuft in einer Orbitype Funktion oder einem Agent

  • Vor jeder weiteren Action muss Apollo verbunden werden


Grundmuster

Jeder Apollo Workflow folgt in der Regel dieser Reihenfolge:

  1. Apollo verbinden

  2. Personen suchen (raw oder normalisiert)

  3. Leads anreichern und Credits pruefen

Minimaler Setup:

async ({ orbi, apollo }) => {
  const credential = orbi.project.credentials.find(x => x.name === "apollo")
  if (!credential?.value) throw new Error("missing [apollo] credential")
  apollo.connect(credential.value)
}

Ohne connect() schlagen alle Request-Methoden fehl.


Verbindung

apollo.connect(accessToken)

Beschreibung
Verbindet Apollo mit einem Bearer Access Token.
Diese Methode muss immer zuerst aufgerufen werden.

Parameter

  • accessToken (string, required)
    Apollo Access Token aus dem Credential-Wert

Rueckgabe

{
  connected: true
}

Suche

apollo.search(params)

Beschreibung
Raw Personensuche ueber den Apollo mixed_people API Endpoint.

Parameter

  • params (object, optional)
    Raw Apollo Query-Parameter (z.B. q_keywords, page, per_page)

Rueckgabe

  • object raw Apollo Response (enthaelt typischerweise total_entries und people)


apollo.searchLeads(params)

Beschreibung
Normalisierte Suchantwort mit stabilen Lead-Feldern.

Parameter

  • params (object, optional)
    Gleiche Query-Form wie bei search()

Rueckgabe

{
  totalEntries: number,
  leads: [
    {
      id: string,
      fullName: string,
      title: string,
      linkedinUrl: string,
      hasEmail: boolean,
      companyName: string
    }
  ]
}

Enrichment

apollo.enrichPerson(params)

Beschreibung
Raw Enrichment-Call auf den Apollo people/match Endpoint.

Parameter

  • params (object, optional)
    Apollo Enrichment-Parameter (z.B. id, linkedin_url, reveal_personal_emails)

Rueckgabe

  • object raw Enrichment-Response (typischerweise mit person und request_id)


apollo.enrichById(personId, options)

Beschreibung
Reichert eine Person ueber die Apollo Person-ID an.

Parameter

  • personId (string, required)
    Apollo Person-ID

  • options (object, optional)
    Zusaetzliche Enrichment-Parameter

Rueckgabe

{
  person: object | undefined,
  request_id: number | undefined
}

apollo.enrichByLinkedinUrl(linkedinUrl, options)

Beschreibung
Reichert eine Person ueber die LinkedIn URL an.

Parameter

  • linkedinUrl (string, required)
    Vollstaendige LinkedIn URL

  • options (object, optional)
    Zusaetzliche Enrichment-Parameter

Rueckgabe

{
  person: object | undefined,
  request_id: number | undefined
}

Kombinierter Workflow-Helper

apollo.searchAndEnrich(input)

Beschreibung
Sucht Leads per Keywords und reichert einen Teil der Ergebnisse per ID an.

Parameter

  • input (object, required)

    • query (string, required): Suchbegriff

    • page (number, optional, default 1)

    • perPage (number, optional, default 10)

    • maxEnrich (number, optional, default 3, clamped to 0..25)

Rueckgabe

{
  search: {
    totalEntries: number,
    leads: ApolloLead[]
  },
  enriched: ApolloPerson[],
  errors: [
    {
      personId: string,
      message: string
    }
  ]
}

Credits

apollo.getCredits()

Beschreibung
Gibt die in dieser Apollo Integration Instanz verbrauchten Credit-Einheiten zurueck.

Parameter

  • keine

Rueckgabe

  • number


Vollstaendiges Beispiel mit allen Apollo Actions

Dieses Beispiel verwendet jede verfuegbare Apollo Action genau einmal in einem realistischen Ablauf.

async ({ orbi, apollo }) => {
  // 1) Apollo verbinden
  const credential = orbi.project.credentials.find(x => x.name === "apollo")
  if (!credential?.value) throw new Error("missing [apollo] credential")
  apollo.connect(credential.value)

  // 2) Raw Suche
  const rawSearch = await apollo.search({
    q_keywords: "founder saas zurich",
    page: 1,
    per_page: 5
  })

  // 3) Normalisierte Suche
  const normalized = await apollo.searchLeads({
    q_keywords: "founder saas zurich",
    page: 1,
    per_page: 5
  })

  // 4) Raw Enrichment (aus raw Suche)
  const firstRawPerson = rawSearch?.people?.[0]
  let rawEnrichment = null
  if (firstRawPerson?.linkedin_url) {
    rawEnrichment = await apollo.enrichPerson({
      linkedin_url: firstRawPerson.linkedin_url,
      reveal_personal_emails: true
    })
  }

  // 5) Enrichment per Apollo ID
  const firstLead = normalized.leads[0]
  let enrichById = null
  if (firstLead?.id) {
    enrichById = await apollo.enrichById(firstLead.id, {
      reveal_personal_emails: true
    })
  }

  // 6) Enrichment per LinkedIn URL
  let enrichByLinkedin = null
  if (firstLead?.linkedinUrl) {
    enrichByLinkedin = await apollo.enrichByLinkedinUrl(firstLead.linkedinUrl, {
      reveal_personal_emails: true
    })
  }

  // 7) Kombinierter Helper
  const searchAndEnrich = await apollo.searchAndEnrich({
    query: "founder saas zurich",
    page: 1,
    perPage: 10,
    maxEnrich: 2
  })

  // 8) Credits
  const credits = apollo.getCredits()

  return {
    totals: {
      rawTotalEntries: rawSearch?.total_entries ?? 0,
      normalizedTotalEntries: normalized.totalEntries
    },
    firstLead,
    rawEnrichment,
    enrichById,
    enrichByLinkedin,
    searchAndEnrich,
    credits
  }
}

Agency

In orbitype-Workflow-Funktionen wird agency automatisch injiziert. Damit kannst du über den Slug auf deine konfigurierten Agenten zugreifen.

Verwende agency.get(slug), um einen Agenten auszuwählen, und run(prompt), um ihn auszuführen.

  • agency.get(slug) wählt den gewünschten Agenten aus
  • agent.run(prompt) führt den Agenten aus und gibt das Ergebnis zurück

Beispiel:

async ({ agency }) => {
  const agent = agency.get("immo_research_agent")

  if (!agent) {
    return { error: "Agent nicht gefunden: immo_research_agent" }
  }

  try {
    const run = await agent.run("start prompt for my Agent")
    return { run }
  } catch (e) {
    return { error: String(e) }
  }
}

Agent

orbitype workflow functions haben Zugriff auf ein injiziertes agent-Objekt. Es ist ein vorkonfigurierter Wrapper um langchain mit zwei Methoden: addTool() registriert ein Tool, run() führt den Agent aus und gibt die finale Message zurück

Beispiel:

const func = async ({agent, zod}) => {
  const { z } = zod
  
  agent.addTool(
    (id) => {
      const url = `https://jsonplaceholder.typicode.com/todos/${id}`
      return fetch(url).then((x) => x.json())
    },
    {
      name: "fetch_todo",
      description: "Fetches a todo by ID from JSONPlaceholder",
      schema: z.string()
    },
  )
  
  agent.addTool(
    (text) => text.trim().split(/\s+/).length,
    {
      name: "count_words",
      description: "Counts the number of words in a given string",
      schema: z.string(),
      returnDirect: true,
    },
  )
  
  const data = await agent.run("number of words in todo with id 3")
  return data
}

SERP

orbitype workflow functions haben Zugriff auf ein injiziertes serp-Objekt. Dessen search-Methode führt eine Suchmaschinenabfrage aus und gibt ein Array von Ergebnis-URLs zurück (nach Relevanz sortiert).

Beispiel:

async ({serp}) => {
  return {output: await serp.search('orbitype')}
}

Output:

[
  "https://www.orbitype.com/",
  "https://uk.finance.yahoo.com/news/orbitype-com-launches-orbitype-intelligence-150000017.html",
  "https://www.orbitype.com/de",
  "https://app.orbitype.com/guest/register",
  "https://www.orbitype.com/posts",
  "https://www.globenewswire.com/news-release/2026/01/06/3213801/0/en/Orbitype-com-Launches-Orbitype-Intelligence-a-Chat-Based-Control-Layer-for-AI-Agent-Environments.html",
  "https://www.orbitype.com/vs",
  "https://www.crunchbase.com/organization/orbitype",
  "https://www.orbitype.com/vs/marketing-automation",
  "https://webcatalog.io/en/apps/orbitype"
]

Browser

orbitype workflow functions haben Zugriff auf ein injiziertes browser-Objekt. Dessen run-Methode führt Puppeteer-Code remote auf einem anderen Server aus. Die Funktion, die als erster Parameter übergeben wird, wird stringifiziert und via HTTP gesendet. Der zweite Parameter wird als JSON serialisiert und erlaubt es, Variablen von außen zu injizieren. Am Ende wird das Resultat zurückgegeben.

Beispiel:

async ({browser}) => {
  const url = "https://vuejs.org/guide/introduction.html"
  const clicks = 3
  const html = await browser.run(
    // puppeteer code
    async ({page, data}) => {
      await page.goto(data.url)
      const button = page.locator(".demo > button")
      for (let i = 0; i < data.clicks; i++)
        await button.click()
      return button.map((x) => x.textContent).wait()
    },
    // injected variables
    {url, clicks}
  )
  return html
}

KI

Nutze KI-Features ganz einfach in deinen Nodes:

async ({ai}) => {
  const text = await ai.chat("This is a test")
  // -> "this is an answer..."
  const json = await ai.chat("JSON for red rgb color", true)
  // -> {r: 255, g: 0, b: 0}
  return {text , json}
}

async ({ai}) => {
  return await ai.image("a red apple")
  // -> { base64: "iVBORw..." }
}

async ({ai}) => {
  return await ai.embedding("lorem ipsum")
  // -> [-0.0014445713,-0.021729672, ... ]
}

OCR

orbitype workflow functions haben Zugriff auf ein injiziertes ocr-Objekt. fileToText() gibt den reinen Text einer Datei zurück. fileToTable() gibt tabellarische Daten zurück, die aus der Datei extrahiert wurden. fileToForm() gibt Felder aus einem PDF-Formular zurück

Beispiele:

async ({ocr}) => {
  const url = "https://cdn.orbitype.com/sXbDwXihqsp0/pdfs/sample.pdf"
  const resp = await fetch(url)
  const blob = await resp.blob()
  const file = new File([blob], "dummmy.pdf", {type: "application/pdf"})
  const text = ocr.fileToText(file)
  return text
}

async ({ocr}) => {
  const url = "https://cdn.orbitype.com/sXbDwXihqsp0/pdfs/table.png"
  const resp = await fetch(url)
  const blob = await resp.blob()
  const file = new File([blob], "table.png", {type: "image/png"})
  const table = ocr.fileToTable(file)
  return table
}

async ({ocr}) => {
  const url = "https://cdn.orbitype.com/sXbDwXihqsp0/pdfs/table.png"
  const resp = await fetch(url)
  const blob = await resp.blob()
  const file = new File([blob], "table.png", {type: "image/png"})
  const table = ocr.fileToForm(file)
  return table
}

// tabular data is returned as a 2d array, e.g.
[
  ["name", "hex", "temperature"],
  ["red", "#FF0000", "warm"],
  ["blue", "#0000FF", "cold"],
  ["yellow", "#FFFF00", "warm"],
  ["cyan", "#00FFFF", "cold"]
]

LinkedIn (erweitert)

LinkedIn Integration in Orbitype

Diese Dokumentation beschreibt alle verfügbaren LinkedIn Aktionen in Orbitype.

Sie erklärt, was jede Aktion macht, welche Parameter benötigt werden, welche Rückgaben zu erwarten sind, und enthält vollständige Beispiele.

Alle LinkedIn Funktionen stehen über das Objekt linkedin in der Orbitype Code-Umgebung zur Verfügung.


Voraussetzungen

  • Ein Credential mit dem Namen linkedin existiert im Projekt

  • Der Code läuft in einer Orbitype Funktion oder einem Agent

  • Das LinkedIn Konto wird vor allen weiteren Aktionen verbunden


Grundmuster

  1. LinkedIn Konto verbinden

  2. Optional Daten abrufen (Profile, Suche, Chats, Posts)

  3. Aktionen ausführen (Einladungen, Nachrichten, Posts, Kommentare, Reaktionen, Analysen)

Minimales Setup:

async ({ orbi, linkedin }) => {
  const accountId = orbi.project.credentials.find(x => x.name === 'linkedin')?.value
  if (!accountId) throw new Error('Missing linkedin credential')

  await linkedin.connect(accountId)
}

Ohne connect() funktionieren keine weiteren Methoden.


Verbindung

linkedin.connect(accountId)

Beschreibung
Verbindet das LinkedIn Konto und initialisiert die Session.

Parameter

  • accountId (string, required)
    Credential-Wert aus orbi.project.credentials für den Namen linkedin

Rückgabe

{
  account_id: string,
  provider_id: string
}

provider_id identifiziert das eigene Profil und wird für Profil-/Post-Aktionen verwendet.


Profile und Suche

linkedin.getProfile(identifier, options?)

Beschreibung
Lädt ein LinkedIn Profil über den Identifier (Profil-Handle).

Parameter

  • identifier (string, required)
    Handle aus der LinkedIn URL, z.B. julian-vorraro

  • options (object, optional)
    Optionale provider-spezifische Optionen

Rückgabe (relevante Felder)

{
  first_name: string,
  last_name: string,
  provider_id: string
}

linkedin.search(params, limit?)

Beschreibung
Sucht auf LinkedIn mit flexiblen Kriterien und Pagination.

Parameter

  • params (object, required)
    Suchkriterien, z.B. { keywords: 'Webentertainer GmbH' }

  • limit (number, optional, default 10)
    Maximale Anzahl an Treffern

Standardverhalten

  • Wenn nicht in params gesetzt: category = 'people' und api = 'classic'

Rückgabe

  • Array<object> Liste mit Suchtreffern


Einladungen

linkedin.sendInvitation(providerId, message)

Beschreibung
Sendet eine Kontaktanfrage an ein Profil.

Parameter

  • providerId (string, required)
    Profil-ID aus getProfile() oder search()

  • message (string, required)
    Einladungstext


linkedin.getInvitations()

Beschreibung
Liefert gesendete Kontaktanfragen.

Parameter

  • keine

Rückgabe

  • object mit Einladungseinträgen


linkedin.cancelInvitation(invitationId)

Beschreibung
Bricht eine gesendete Einladung ab.

Parameter

  • invitationId (string, required)
    ID aus getInvitations()


Chats und Nachrichten

linkedin.startChat(text, attendeesIds?)

Beschreibung
Startet einen neuen Chat und setzt ihn als aktiven Chat.

Parameter

  • text (string, required)
    Erste Nachricht

  • attendeesIds (string[], optional)
    Liste von Teilnehmer-Profil-IDs

Verhalten

  • Das eigene Profil wird automatisch hinzugefügt

  • Doppelte Teilnehmer werden automatisch entfernt


linkedin.resumeChat(chatId)

Beschreibung
Setzt einen bestehenden Chat als aktiv.

Parameter

  • chatId (string, required)


linkedin.getChats()

Beschreibung
Listet bestehende Chats.

Parameter

  • keine

Verhalten

  • Verwendet intern ein festes Limit von 20 Chats pro Aufruf


linkedin.getMessages()

Beschreibung
Lädt Nachrichten aus dem aktiven Chat.

Voraussetzung

  • Ein aktiver Chat muss gesetzt sein (startChat oder resumeChat)


linkedin.sendMessage(text)

Beschreibung
Sendet eine Nachricht im aktiven Chat.

Parameter

  • text (string, required)


Posts und Kommentare

linkedin.createPost(text, attachments?)

Beschreibung
Erstellt einen LinkedIn Beitrag. Unterstützt Text-Beiträge, Bild-Beiträge (einzeln oder Karussell), Video-Beiträge (ein Video) und Dokument-Beiträge (PDF, DOC/DOCX, PPT/PPTX).

Parameter

  • text (string, required)
    Beitragstext. Für reine Medien-Beiträge '' verwenden.

  • attachments (optional)
    Ein Anhang oder ein Array von Anhängen. Jeder Anhang kann sein:

    • URL String — z.B. 'https://.../photo.jpg'

    • { url, filename? } — URL mit optionalem Dateinamen

    • { buffer, filename? } — Binärdaten mit optionalem Dateinamen (empfohlen)

    • { base64, filename? } — Base64-Inhalt (plain base64 oder data:<mime>;base64,...) mit optionalem Dateinamen (empfohlen)

Unterstützte Endungen

  • Bilder: jpg, jpeg, png, gif, webp

  • Videos: mp4, mov, webm

  • Dokumente: pdf, doc, docx, ppt, pptx

Einschränkungen und Hinweise

  • Bilder und Video nicht im selben Beitrag kombinieren.

  • Dokument-Beiträge sollten genau ein Dokument enthalten und nicht mit anderen Medien kombiniert werden.

  • Für Bild-Karussells nur Bild-Anhänge übergeben.

  • Bei Binär-/Base64-Uploads möglichst immer Dateinamen mitgeben.

Beispiele

// nur Text
await linkedin.createPost('hello from orbitype')

// einzelnes Bild per URL
await linkedin.createPost(
  'new product launch',
  'https://cdn.example.com/launch.jpg'
)

// Bild-Karussell
await linkedin.createPost('event recap', [
  'https://cdn.example.com/1.jpg',
  'https://cdn.example.com/2.jpg',
  'https://cdn.example.com/3.jpg'
])

// einzelnes Video
await linkedin.createPost('short demo', {
  url: 'https://cdn.example.com/demo.mp4',
  filename: 'demo.mp4'
})

// einzelnes PDF
await linkedin.createPost('our latest whitepaper', {
  url: 'https://cdn.example.com/whitepaper.pdf',
  filename: 'Orbitype Whitepaper 2026.pdf'
})

// PDF aus vorherigem Schritt
await linkedin.createPost('monthly report', {
  buffer: input.pdfBuffer,
  filename: 'report-2026-04.pdf'
})

// Bild aus base64
await linkedin.createPost('ai-generated cover', {
  base64: input.coverBase64,
  filename: 'cover.png'
})

linkedin.getPosts(identifier)

Beschreibung
Lädt Beiträge eines LinkedIn Profils.

Parameter

  • identifier (string, required)
    Typischerweise die eigene provider_id aus connect()


linkedin.sendComment(postId, text)

Beschreibung
Kommentiert einen LinkedIn Beitrag.

Parameter

  • postId (string, required)

  • text (string, required)


Reaktionen

linkedin.reactToPost(postId, reaction?)

Beschreibung
Sendet eine Reaktion auf einen Beitrag.

Parameter

  • postId (string, required)

  • reaction (string, optional, default 'LIKE')


linkedin.likePost(postId)

Beschreibung
Komfortmethode für reactToPost(postId, 'LIKE').

Parameter

  • postId (string, required)


Posting-Identitäten

linkedin.getPostingIdentities()

Beschreibung
Liefert verfügbare Posting-Identitäten des verbundenen Kontos (Member + ggf. Organization/Page).

Rückgabe

[
  {
    id: string,
    type: 'member' | 'organization' | 'page' | 'unknown',
    name: string | null,
    provider: 'linkedin',
    mailbox_id?: string | null,
    raw: unknown
  }
]

linkedin.createPostAs(identityId, text, attachments?)

Beschreibung
Erstellt einen Beitrag als bestimmte Identität.

Parameter

  • identityId (string, required)
    ID aus getPostingIdentities()

  • text (string, required)

  • attachments (optional)
    Gleiches Format wie bei createPost()

Rückgabe

  • Post-Payload inklusive Identity-Metadaten (posting_identity_id, posting_identity_field)


linkedin.createOrganizationPost(organizationId, text, attachments?)

Beschreibung
Alias für Organization/Page-Posting.

Entspricht

await linkedin.createPostAs(organizationId, text, attachments)

Post-Engagement-Analysen

linkedin.getPostComments(postId, options?)

Beschreibung
Lädt eine paginierte Kommentar-Seite für einen Beitrag.

Parameter

  • postId (string, required)

  • options (object, optional)

    • cursor (string, optional)

    • limit (number, optional, begrenzt auf 1..100)

    • sort_by (string, optional): 'MOST_RECENT' oder 'MOST_RELEVANT'

    • comment_id (string, optional)

Rückgabe

{
  items: any[],
  cursor: string | null,
  raw: any
}

linkedin.getAllPostComments(postId, options?)

Beschreibung
Paginierung automatisch bis zum Ende oder bis zum gesetzten Limit.

Parameter

  • postId (string, required)

  • options (object, optional)

    • limitPerPage (number, optional)

    • maxItems (number, optional)

    • sort_by (string, optional)

    • comment_id (string, optional)

Rückgabe

  • any[] flache Kommentar-Liste


linkedin.getPostReactions(postId, options?)

Beschreibung
Lädt eine paginierte Reaktions-Seite für einen Beitrag.

Parameter

  • postId (string, required)

  • options (object, optional)

    • cursor (string, optional)

    • limit (number, optional, begrenzt auf 1..100)

    • comment_id (string, optional)

Rückgabe

{
  items: any[],
  cursor: string | null,
  raw: any
}

linkedin.getAllPostReactions(postId, options?)

Beschreibung
Paginierung automatisch bis zum Ende oder bis zum gesetzten Limit.

Parameter

  • postId (string, required)

  • options (object, optional)

    • limitPerPage (number, optional)

    • maxItems (number, optional)

    • comment_id (string, optional)

Rückgabe

  • any[] flache Reaktions-Liste


linkedin.getPostEngagedPersons(postId, options?)

Beschreibung
Kombiniert Kommentar- und Reaktions-Akteure zu einer deduplizierten Engagement-Ansicht.

Parameter

  • postId (string, required)

  • options (object, optional)

    • includeComments (boolean, optional, default true)

    • includeReactions (boolean, optional, default true)

    • commentSort (string, optional)

    • limitPerPage (number, optional)

    • maxComments (number, optional)

    • maxReactions (number, optional)

Rückgabe

{
  people: [
    {
      id: string | null,
      provider_id: string | null,
      name: string | null,
      headline: string | null,
      profile_url: string | null,
      sources: Array<'comment' | 'reaction'>,
      comments_count: number,
      reactions_count: number,
      raw_examples: any[]
    }
  ],
  comments: any[],
  reactions: any[]
}

linkedin.getCompanyActiveEngagers(companyIdentifier, options?)

Beschreibung
Lädt Company-Posts und aggregiert aktive Engager über mehrere Beiträge.

Parameter

  • companyIdentifier (string, required)

  • options (object, optional)

    • postsLimit (number, optional, default 20)

    • includeComments (boolean, optional)

    • includeReactions (boolean, optional)

    • commentSort (string, optional)

    • limitPerPage (number, optional)

    • maxCommentsPerPost (number, optional)

    • maxReactionsPerPost (number, optional)

Rückgabe

{
  company_identifier: string,
  posts_scanned: Array<{ id: string, raw: any }>,
  engagers: Array<{
    id: string | null,
    provider_id: string | null,
    name: string | null,
    headline: string | null,
    profile_url: string | null,
    posts_count: number,
    comments_count: number,
    reactions_count: number,
    engagement_types: Array<'comment' | 'reaction'>,
    post_ids: string[],
    comment_texts: string[],
    reaction_types: string[],
    raw_examples: any[]
  }>,
  errors: Array<{ scope: 'company' | 'post', message: string, post_id?: string }>
}

Credits

linkedin.getCredits()

Beschreibung
Liefert gerundete verbrauchte Credits für die aktuelle LinkedIn Session innerhalb der aktuellen Ausführung.


Vollständiges Beispiel

async ({ orbi, linkedin }) => {
  // 1) verbinden
  const accountId = orbi.project.credentials.find(x => x.name === 'linkedin')?.value
  if (!accountId) throw new Error('Missing linkedin credential')
  const self = await linkedin.connect(accountId)

  // 2) suche + profil
  const searchResults = await linkedin.search({ keywords: 'Webentertainer GmbH' }, 10)
  const profile = await linkedin.getProfile('julian-vorraro')

  // 3) einladungen
  await linkedin.sendInvitation(profile.provider_id, 'Hallo Julian, kurze Vernetzung?')
  const invitations = await linkedin.getInvitations()
  if (invitations.items?.length) {
    await linkedin.cancelInvitation(invitations.items[0].invitation_id)
  }

  // 4) chat + nachrichten
  await linkedin.startChat('Danke fürs Vernetzen 👋', [profile.provider_id])
  await linkedin.sendMessage('Kurzer Austausch zu Automatisierung?')
  const chats = await linkedin.getChats()
  if (chats.items?.length) await linkedin.resumeChat(chats.items[0].id)
  const messages = await linkedin.getMessages()

  // 5) beitrag erstellen
  const createdPost = await linkedin.createPost('Automatisierung direkt aus Orbitype 🚀', {
    url: 'https://cdn.example.com/post-cover.jpg',
    filename: 'cover.jpg'
  })

  // 6) identitäten + als organization/page posten
  const identities = await linkedin.getPostingIdentities()
  const orgIdentity = identities.find(x => x.type === 'organization' || x.type === 'page')
  if (orgIdentity) {
    await linkedin.createPostAs(orgIdentity.id, 'Posted as organization via createPostAs')
    await linkedin.createOrganizationPost(orgIdentity.id, 'Posted as organization via alias')
  }

  // 7) posts + kommentar + reaktion
  const posts = await linkedin.getPosts(self.provider_id)
  const firstPostId = posts.items?.[0]?.id || posts.items?.[0]?.post_id || createdPost?.id || createdPost?.post_id

  if (firstPostId) {
    await linkedin.sendComment(firstPostId, 'Danke fürs Lesen')
    await linkedin.reactToPost(firstPostId, 'LIKE')
    await linkedin.likePost(firstPostId)

    // 8) engagement-analysen
    const commentsPage = await linkedin.getPostComments(firstPostId, {
      limit: 20,
      sort_by: 'MOST_RECENT'
    })

    const allComments = await linkedin.getAllPostComments(firstPostId, {
      maxItems: 100,
      sort_by: 'MOST_RECENT'
    })

    const reactionsPage = await linkedin.getPostReactions(firstPostId, {
      limit: 20
    })

    const allReactions = await linkedin.getAllPostReactions(firstPostId, {
      maxItems: 100
    })

    const engaged = await linkedin.getPostEngagedPersons(firstPostId, {
      includeComments: true,
      includeReactions: true,
      commentSort: 'MOST_RECENT',
      maxComments: 200,
      maxReactions: 200
    })

    console.log('comments page:', commentsPage.items?.length)
    console.log('all comments:', allComments.length)
    console.log('reactions page:', reactionsPage.items?.length)
    console.log('all reactions:', allReactions.length)
    console.log('engaged persons:', engaged.people?.map(x => x.name))
  }

  // 9) company-level aktive engagers
  const companyEngagers = await linkedin.getCompanyActiveEngagers('webentertainer', {
    postsLimit: 10,
    includeComments: true,
    includeReactions: true,
    commentSort: 'MOST_RECENT',
    maxCommentsPerPost: 150,
    maxReactionsPerPost: 150
  })

  // 10) credits
  const credits = linkedin.getCredits()

  return {
    self,
    searchResultsCount: searchResults.length,
    messagesCount: messages.items?.length ?? 0,
    identitiesCount: identities.length,
    companyEngagersCount: companyEngagers.engagers.length,
    credits
  }
}

Fehlerbehebung

  • Not connected Fehler: Sicherstellen, dass linkedin.connect(accountId) zuerst läuft.

  • Keine Nachrichten: Sicherstellen, dass ein aktiver Chat gesetzt wurde.

  • Upload-Fehler bei Posts: Dateiendung, Typ, Größe und Dateiname prüfen.

  • Wenig/keine Analytics Daten: Engagement kann gering sein oder durch Sichtbarkeit begrenzt sein.

  • Fehler bei Company-Engagers: Gültigen Company-Identifier nutzen und Zugriffsrechte prüfen.


Bibliotheken

orbitype workflow functions haben Zugriff auf einige injizierte npm-Bibliotheken.

  • cheerio

  • imapflow

  • lodash

  • nodemailer

  • pdf-lib (verfügbar als PDFLib)

  • pdfkit (verfügbar als PDFDocument)

  • unpdf

  • swissqrbill

  • zod

zusätzliches manuelles Importieren/Requiren weiterer Libraries wird NICHT unterstützt

Beispiele:

const func = async ({lodash}) => {
  await new Promise((res) => setTimeout(res, 100))
  const output = lodash.random(0,9)
  return {output}
}

const func = async ({config, input, nodemailer}) => { 
  const transporter = nodemailer.createTransport({
    host: "smtp.ethereal.email",
    port: 587,
    auth: {
      user: config.user,
      pass: config.pass,
    },
  })
  const mail = {
    from: config.user,
    to: input.email,
    subject: config.subject,
    text: config.text,
  }
  await transporter.sendMail(mail)
  return mail
}

const func = async ({ImapFlow}) => {
  const client = new ImapFlow({
    host: 'smtp.ethereal.email',
    port: 993,
    secure: true,
    auth: {
      user: "nathanial.oreilly@ethereal.email",
      pass: "BnK2wAJtg4P1Efu5zp",
    }
  })
  await client.connect()
  await client.mailboxOpen('INBOX')
  const message = await client.fetchOne('*', { source: true })
  await client.logout()
  return message.source.toString()
}

const func = async ({unpdf}) => {
  const url = 'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf'
  const res = await fetch(url)
  const buffer = await res.arrayBuffer()
  const pdf = await unpdf.getDocumentProxy(new Uint8Array(buffer))
  const { text } = await unpdf.extractText(pdf, { mergePages: true })
  return text
}

const func = async ({PDFLib}) => {
  const pdfDoc = await PDFLib.PDFDocument.create()
  const page = pdfDoc.addPage()
  page.drawText('lorem ipsum')
  const base64 = await pdfDoc.saveAsBase64({ dataUri: true })
  return base64
}

const func = async ({SwissQRBill, PDFDocument}) => {
  return new Promise((resolve, reject) => {
    const doc = new PDFDocument({ size: 'A4' });
    const chunks = [];
    doc.on('data', (chunk) => chunks.push(chunk));
    doc.on('end', () => resolve(Buffer.concat(chunks).toString('base64')));
    doc.on('error', reject);

    doc.fontSize(20).text('Invoice #12345', 50, 50);
    doc.fontSize(12).text('Lorem ipsum...', 50, 100);

    const data = {
      amount: 1994.75,
      creditor: {
        account: "CH44 3199 9123 0008 8901 2",
        address: "Musterstrasse",
        buildingNumber: 7,
        city: "Musterstadt",
        country: "CH",
        name: "SwissQRBill",
        zip: 1234
      },
      currency: "CHF",
      debtor: {
        address: "Musterstrasse",
        buildingNumber: 1,
        city: "Musterstadt",
        country: "CH",
        name: "Peter Muster",
        zip: 1234
      },
      reference: "21 00000 00003 13947 14300 09017"
    };

    const qrBill = new SwissQRBill(data);
    qrBill.attachTo(doc);
    doc.end();
  });
}

SheetJS (XLSX): Tabellenverarbeitung

XLSX ist SheetJS, eine leistungsstarke Library zur Tabellenverarbeitung, die in Orbitype-Workflows per Dependency Injection verfügbar ist. Damit kannst du Spreadsheets und tabellarische Daten in vielen Formaten lesen, erstellen, bearbeiten und exportieren. Das ist ideal für Imports, Exports, Reporting und Daten-Transformationen.

Was SheetJS alles kann

  • Lesen von Spreadsheets und tabellarischen Daten (zum Beispiel: XLSX, XLS, CSV und mehr) aus Strings, ArrayBuffers und anderen unterstützten Inputs.

  • Erstellen und bearbeiten von Workbooks und Worksheets per Code.

  • Konvertieren zwischen Formaten (zum Beispiel: CSV zu XLSX, XLSX zu CSV).

  • Transformieren von Datenstrukturen: Sheet zu JSON, JSON zu Sheet, Arrays zu Sheet und mehr.

  • Schreiben/Exportieren von Dateien (zum Beispiel: XLSX/CSV Output generieren für Downloads, E-Mails oder Storage).

  • Arbeiten mit Zellen: Werte setzen, Zahlenformate, Datumswerte, Formeln und grundlegende Worksheet-Metadaten.

  • Utility-Helper für Ranges, Header, Spalten-Mappings und typische Spreadsheet-Operationen.

Beispiel:

async ({ XLSX }) => {
  const csv = 
    `name, age, city, email
    John Doe, 30, New York, john@example.com
    Jane Smith, 25, Los Angeles, jane@example.com
    Bob Johnson, 35, Chicago, bob@example.com`;

  const workbook = XLSX.read(csv, { type: "string" });
  const sheet = workbook.Sheets['Sheet1'];
  const json = XLSX.utils.sheet_to_json(sheet);

  return json;
};

Hinweise:

  • Die Header-Zeile des CSV wird zu den Objekt-Keys im resultierenden JSON-Array.

  • XLSX.read parst den Input in eine Workbook-Struktur.

  • XLSX.utils.sheet_to_json wandelt Worksheet-Zeilen in JSON-Objekte um.

Learn more

Konto kündigen

Wir möchten sicherstellen, dass du Orbitype problemlos nutzen kannst. Falls du Fragen hast oder auf Schwierigkeiten stößt, zögere nicht, uns zu kontaktieren. Wir sind für dich da – schreib uns einfach eine Nachricht an support@orbitype.com, und wir helfen dir gerne weiter.

Wenn du nicht handelst, tun es deine Wettbewerber.

|
page-logo

Orbitype lernt dein Unternehmen kennen, analysiert Wettbewerber, findet potenzielle Kund:innen und baut sowie betreibt autonom agentische Wachstumssysteme, die auf dein Unternehmen zugeschnitten sind.

Kostenlos starten

2026 Orbitype. All rights reserved.