> ## Documentation Index
> Fetch the complete documentation index at: https://doc.lucidworks.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Call External Pipeline

> Index pipeline stage configuration specifications

export const schema = {
  "type": "object",
  "title": "Call External Pipeline",
  "description": "Invokes an external HTTP endpoint or microservice as part of the indexing pipeline, enabling integration with third-party APIs, data enrichment platforms, or custom services. Supports synchronous communication with configurable timeout and error handling.",
  "required": ["collection", "pipeline"],
  "properties": {
    "skip": {
      "type": "boolean",
      "title": "Skip This Stage",
      "description": "When `true`, this stage is bypassed and documents pass to the next stage unchanged. Use this to disable a stage temporarily without removing it from the pipeline. A skipped stage isn't initialized, so configuration errors in it aren't reported until you clear this option.",
      "default": false,
      "hints": ["advanced"]
    },
    "label": {
      "type": "string",
      "title": "Label",
      "description": "A descriptive name for this stage. The label appears in the pipeline editor, log messages, and stage metrics, so a clear label makes it easier to identify a stage when troubleshooting. For example, `Enrich product data`.",
      "hints": ["advanced"],
      "maxLength": 255
    },
    "condition": {
      "type": "string",
      "title": "Condition",
      "description": "JavaScript expression that determines whether this stage runs for each document. The stage runs when the expression returns `true` and is skipped when it returns `false`. The expression can use the `doc` (current document) and `ctx` (pipeline context) variables. For example, `doc.getFirstFieldValue('type') == 'premium'` runs this stage only for documents whose `type` field is `premium`. The expression must return a boolean. If it returns another value or throws an error, processing fails for that document.",
      "hints": ["code", "code/javascript", "advanced"]
    },
    "collection": {
      "type": "string",
      "title": "Collection"
    },
    "pipeline": {
      "type": "string",
      "title": "Pipeline ID"
    },
    "fusionURL": {
      "type": "string",
      "title": "Fusion URL"
    },
    "userName": {
      "type": "string",
      "title": "User name"
    },
    "userNameVaultLabel": {
      "type": "string",
      "title": "User name from Vault",
      "description": "Specifies the Vault secret label used to retrieve the username for authenticating the external pipeline request. When set, takes priority over the plain-text User name field.",
      "hints": ["enumUrl:/apps-manager/vault/labels?type=secret&category=credentials"]
    },
    "passwordVaultLabel": {
      "type": "string",
      "title": "Password from Vault",
      "description": "Specifies the Vault secret label used to retrieve the password for authenticating the external pipeline request. When set, takes priority over the plain-text Password field.",
      "hints": ["enumUrl:/apps-manager/vault/labels?type=secret&category=credentials"]
    },
    "password": {
      "type": "string",
      "title": "Password",
      "hints": ["secret"]
    },
    "batching": {
      "type": "boolean",
      "title": "Micro batching",
      "description": "Controls whether documents are collected in batches and sent together to the target pipeline. When enabled, documents are buffered and processed in chunks rather than individually, which can improve throughput for high-volume pipelines.",
      "default": false
    },
    "certificate": {
      "type": "string",
      "title": "Certificate",
      "description": "Specifies a self-signed or corporate CA certificate in PEM format for TLS authentication with the external endpoint. Required when the endpoint uses a certificate not trusted by the default Java truststore.",
      "hints": ["lengthy"]
    },
    "proxy": {
      "type": "string",
      "title": "Proxy",
      "description": "Specifies the proxy server hostname or IP address to route requests through when calling the external endpoint."
    },
    "proxyPort": {
      "type": "integer",
      "title": "Proxy Port",
      "description": "Specifies the port number of the proxy server configured in `proxy`."
    },
    "proxyUser": {
      "type": "string",
      "title": "Proxy User"
    },
    "proxyPassword": {
      "type": "string",
      "title": "Proxy Password",
      "hints": ["secret"]
    },
    "proxyUserVaultLabel": {
      "type": "string",
      "title": "Proxy User from Vault",
      "description": "Specifies the Vault secret label used to retrieve the proxy server username. When set, takes priority over the plain-text Proxy User field.",
      "hints": ["enumUrl:/apps-manager/vault/labels?type=secret&category=credentials"]
    },
    "proxyPasswordVaultLabel": {
      "type": "string",
      "title": "Proxy Password from Vault",
      "description": "Specifies the Vault secret label used to retrieve the proxy server password. When set, takes priority over the plain-text Proxy Password field.",
      "hints": ["enumUrl:/apps-manager/vault/labels?type=secret&category=credentials"]
    }
  },
  "category": "Advanced",
  "categoryPriority": 3,
  "unsafe": false
};

export const SchemaParamFields = ({schema}) => {
  const sanitize = str => {
    if (typeof str !== "string") return str;
    return str.replace(/^"(.*)"$/s, "$1").replace(/\\/g, "").replace(/"/g, "'");
  };
  const renderMd = str => {
    const s = sanitize(str);
    const text = (/[.!?]\)*$/).test(s) ? s : `${s}.`;
    return text.split(/(\*\*[^*]+\*\*|_[^_]+_|`[^`]+`)/g).map((part, i) => {
      if (part.startsWith("**")) return <strong key={i}>{part.slice(2, -2)}</strong>;
      if (part.startsWith("_")) return <em key={i}>{part.slice(1, -1)}</em>;
      if (part.startsWith("`")) return <code key={i}>{part.slice(1, -1)}</code>;
      return part;
    });
  };
  const {description, properties = {}, required: requiredProps = []} = schema;
  const visibleProps = useMemo(() => Object.entries(properties).filter(([, prop]) => !prop.hints?.includes("hidden")), [properties]);
  const renderProp = ([name, prop]) => {
    const isRequired = requiredProps.includes(name);
    const hasDefault = prop.default !== undefined;
    const rawDefault = prop.default;
    const hints = prop.hints || [];
    const isComplexDefault = hasDefault && (typeof rawDefault === "object" || typeof rawDefault === "string" && (rawDefault.length > 20 || rawDefault.includes('"')));
    const postBadges = [];
    if (prop.title) {
      postBadges.push(<><span className="text-stone-400 dark:text-stone-500">API property: </span>{name}</>);
    }
    const constraints = [];
    if (prop.minimum !== undefined && prop.maximum !== undefined) {
      constraints.push(`Range: ${prop.minimum} – ${prop.maximum}`);
    } else if (prop.minimum !== undefined) {
      constraints.push(`Min: ${prop.minimum}`);
    } else if (prop.maximum !== undefined) {
      constraints.push(`Max: ${prop.maximum}`);
    }
    if (prop.minLength !== undefined && prop.maxLength !== undefined) {
      constraints.push(`Length: ${prop.minLength} – ${prop.maxLength}`);
    } else if (prop.minLength !== undefined) {
      constraints.push(`Min length: ${prop.minLength}`);
    } else if (prop.maxLength !== undefined) {
      constraints.push(`Max length: ${prop.maxLength}`);
    }
    const fieldProps = {
      key: name,
      body: prop.title || name,
      type: prop.type,
      ...postBadges.length > 0 && ({
        post: postBadges
      }),
      ...isRequired && ({
        required: true
      }),
      ...!isComplexDefault && hasDefault ? {
        default: sanitize(String(rawDefault))
      } : {}
    };
    const isObject = prop.type === "object" && prop.properties;
    const isArrayOfObjects = prop.type === "array" && prop.items?.type === "object" && prop.items.properties;
    return <ParamField {...fieldProps}>
        {prop.description && <p>{renderMd(prop.description)}</p>}

        {prop.enum && <p>
            Allowed values: 
            {prop.enum.map((v, i) => <>{i > 0 && ", "}<code key={i}>{String(v)}</code></>)}
          </p>}

        {constraints.length > 0 && <p className="text-stone-500 dark:text-stone-400 text-sm">
            {constraints.join(" · ")}
          </p>}

        {isComplexDefault && <div className="flex">
            <p>
              <strong>Default:</strong>
            </p>
            <pre className="!my-0">
              <code>
                {JSON.stringify(rawDefault, null, 2)}
              </code>
            </pre>
          </div>}

        {isArrayOfObjects && <Expandable title="item properties">
            <SchemaParamFields schema={{
      properties: prop.items.properties,
      required: prop.items.required
    }} />
          </Expandable>}

        {isObject && <Expandable title="properties">
            <SchemaParamFields schema={{
      properties: prop.properties,
      required: prop.required
    }} />
          </Expandable>}
      </ParamField>;
  };
  return <div>
      {description && <p>{renderMd(description)}</p>}

      {visibleProps.map(renderProp)}
    </div>;
};

export const LwTemplate = ({title = "Key questions to get you started", icon = "sparkles", cta = "Powered by Agent Studio", linkHref = "https://lucidworks.com/demo/?utm_source=docs&utm_medium=referral&utm_campaign=docs_cta_ai"}) => {
  const [isLoaded, setIsLoaded] = useState(false);
  useEffect(() => {
    const timer = setTimeout(() => {
      setIsLoaded(true);
    }, 500);
    return () => clearTimeout(timer);
  }, []);
  return <div className="lw-template-container">
      <Card title={title} icon={icon}>
        {isLoaded && <span dangerouslySetInnerHTML={{
    __html: `<lw-template id="a029c1a9-28be-427e-b0e1-5d918920246a"></lw-template
            >`
  }} />}
        <Link href={linkHref} className="agent-studio-link text-left text-gray-600 gap-2 dark:text-gray-400 text-sm font-medium flex flex-row items-center hover:text-primary dark:hover:text-primary-light group-hover:text-primary group-hover:dark:text-primary-light">Powered by Lucidworks Agent Studio</Link>
      </Card>
    </div>;
};

[localhost link]: http://localhost:3000/docs/lucidworks-search/09-developer-documentation/config-specs/index-pipeline-stages/call-external-pipeline

[mintlify link]: https://doc.lucidworks.com/docs/lucidworks-search/09-developer-documentation/config-specs/index-pipeline-stages/call-external-pipeline

The Call External Pipeline index stage sends each document to an index pipeline on another Lucidworks Search or Fusion instance.
For example, you can use one instance to crawl and parse content, then send the documents to a different instance for indexing.

<Note>
  This stage is different from the [Call Pipeline index stage](/docs/lucidworks-search/09-developer-documentation/config-specs/index-pipeline-stages/call-pipeline), which calls another index pipeline in the same Fusion environment.
</Note>

<LwTemplate />

The stage sends each document to this endpoint on the target instance, using the user name and password for HTTP basic authentication:

```
FUSION_URL/api/index-pipelines/PIPELINE_ID/collections/COLLECTION/index
```

The target pipeline processes the document and indexes it in the target collection.
The stage doesn't receive any data back, so changes that the target pipeline makes to the document don't return to the local pipeline.

After sending the document, the stage passes the original, unchanged document to the next stage in the local pipeline.
If the local pipeline includes a [Solr Indexer stage](/docs/lucidworks-search/09-developer-documentation/config-specs/index-pipeline-stages/solr-indexer), the document is also indexed locally, so a copy exists in both instances.

Use a dedicated user with the minimum required permissions on the target instance, not an admin user.

## Micro batching

By default, the stage sends one document at a time and waits for each request to finish.
When you enable **Micro batching**, the stage buffers documents and sends them in batches.
Batched documents are sent asynchronously and in no particular order.

In batch mode, a failed request doesn't necessarily cause the original document to fail in the local pipeline.
Check the indexing logs for errors.

## Proxy and certificate settings

To reach the target instance through an HTTP proxy, set **Proxy** and **Proxy Port**.
If you leave **Proxy Port** blank, the stage uses port 80.
If the proxy requires authentication, set both **Proxy User** and **Proxy Password**.
The stage fails validation if only one of them is set.

If the target instance uses a self-signed or corporate CA certificate, paste the certificate in PEM format in the **Certificate** field.

## Configuration

<Tip>
  When entering configuration values in the UI, use *unescaped* characters, such as `\t` for the tab character. When entering configuration values in the API, use *escaped* characters, such as `\\t` for the tab character.
</Tip>

<SchemaParamFields schema={schema} />


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.