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

# Invocation

> Call remote functions

## Overview

The invocation API allows you to call functions registered by other workers. All invocation methods automatically propagate trace context when the `otel` feature is enabled.

## Calling Functions

### call

Call a function and wait for the result (with default 30-second timeout).

```rust theme={null}
pub async fn call(
    &self,
    function_id: &str,
    data: impl serde::Serialize,
) -> Result<Value, IIIError>
```

<ParamField path="function_id" type="&str" required>
  ID of the function to call
</ParamField>

<ParamField path="data" type="impl serde::Serialize" required>
  Input data to pass to the function (will be serialized to JSON)
</ParamField>

<ResponseField name="Value" type="Result<Value, IIIError>">
  The function's return value, or an error if the call fails or times out
</ResponseField>

**Example:**

```rust theme={null}
use iii_sdk::III;
use serde_json::json;

let iii = III::new("ws://localhost:49134");
iii.connect().await?;

let result = iii.call("user.get", json!({
    "id": "user-123"
})).await?;

println!("User: {}", result);
```

### call\_with\_timeout

Call a function with a custom timeout.

```rust theme={null}
pub async fn call_with_timeout(
    &self,
    function_id: &str,
    data: Value,
    timeout: Duration,
) -> Result<Value, IIIError>
```

<ParamField path="function_id" type="&str" required>
  ID of the function to call
</ParamField>

<ParamField path="data" type="Value" required>
  Input data as a `serde_json::Value`
</ParamField>

<ParamField path="timeout" type="Duration" required>
  Maximum time to wait for a response
</ParamField>

<ResponseField name="Value" type="Result<Value, IIIError>">
  The function's return value, or `IIIError::Timeout` if the timeout is exceeded
</ResponseField>

**Example:**

```rust theme={null}
use std::time::Duration;
use serde_json::json;

// Call with 5-second timeout
let result = iii.call_with_timeout(
    "long_running_task",
    json!({ "task": "process" }),
    Duration::from_secs(5)
).await?;
```

### call\_void

Call a function without waiting for a response (fire-and-forget).

```rust theme={null}
pub fn call_void<TInput>(
    &self,
    function_id: &str,
    data: TInput,
) -> Result<(), IIIError>
where
    TInput: Serialize
```

<ParamField path="function_id" type="&str" required>
  ID of the function to call
</ParamField>

<ParamField path="data" type="TInput" required>
  Input data to pass to the function
</ParamField>

<ResponseField name="()" type="Result<(), IIIError>">
  Returns immediately after sending the invocation (does not wait for result)
</ResponseField>

**Example:**

```rust theme={null}
use serde_json::json;

// Fire-and-forget notification
iii.call_void("notifications.send", json!({
    "user_id": "user-123",
    "message": "Task completed"
}))?;

println!("Notification sent (not waiting for result)");
```

## Legacy Aliases

The SDK also provides `trigger`, `trigger_with_timeout`, and `trigger_void` methods that are aliases for the `call` methods:

```rust theme={null}
pub async fn trigger(&self, function_id: &str, data: impl serde::Serialize) -> Result<Value, IIIError>
pub async fn trigger_with_timeout(&self, function_id: &str, data: Value, timeout: Duration) -> Result<Value, IIIError>
pub fn trigger_void<TInput>(&self, function_id: &str, data: TInput) -> Result<(), IIIError>
```

These are functionally identical to `call`, `call_with_timeout`, and `call_void`.

## Error Handling

### Error Types

Function calls can fail with these errors:

```rust theme={null}
pub enum IIIError {
    NotConnected,           // Client is not connected to engine
    Timeout,                // Call exceeded timeout duration
    Remote {                // Function returned an error
        code: String,
        message: String,
    },
    Handler(String),        // Function handler panicked or failed
    Serde(String),          // Serialization/deserialization error
    WebSocket(String),      // WebSocket communication error
}
```

### Handling Errors

**Example:**

```rust theme={null}
use iii_sdk::IIIError;
use serde_json::json;

match iii.call("user.delete", json!({ "id": "user-123" })).await {
    Ok(result) => {
        println!("User deleted: {}", result);
    }
    Err(IIIError::Timeout) => {
        eprintln!("Request timed out");
    }
    Err(IIIError::Remote { code, message }) => {
        eprintln!("Remote error {}: {}", code, message);
    }
    Err(IIIError::NotConnected) => {
        eprintln!("Not connected to engine");
    }
    Err(e) => {
        eprintln!("Error: {}", e);
    }
}
```

## Trace Context Propagation

When the `otel` feature is enabled, trace context is automatically propagated with function calls:

```rust theme={null}
#[cfg(feature = "otel")]
{
    use iii_sdk::{III, with_span, SpanKind};
    use serde_json::json;
    
    let iii = III::new("ws://localhost:49134");
    iii.connect().await?;
    
    // Create a parent span
    let result = with_span(
        "process_order",
        None,
        Some(SpanKind::Internal),
        || async {
            // This call will be a child span of "process_order"
            let user = iii.call("user.get", json!({ "id": "user-123" })).await?;
            
            // This call will also be a child span
            let order = iii.call("order.create", json!({
                "user": user,
                "items": []
            })).await?;
            
            Ok(order)
        }
    ).await?;
}
```

The SDK automatically:

* Injects W3C `traceparent` and `baggage` headers into outbound calls
* Extracts these headers from inbound invocations
* Creates parent-child span relationships across function boundaries

## Calling Engine Functions

The III Engine provides built-in functions:

### List Functions

```rust theme={null}
let result = iii.call("engine::functions::list", json!({})).await?;
let functions = result.get("functions").unwrap();
```

Or use the convenience method:

```rust theme={null}
let functions = iii.list_functions().await?;
```

### List Workers

```rust theme={null}
let result = iii.call("engine::workers::list", json!({})).await?;
let workers = result.get("workers").unwrap();
```

Or use the convenience method:

```rust theme={null}
let workers = iii.list_workers().await?;
```

### Register Worker Metadata

```rust theme={null}
use iii_sdk::WorkerMetadata;

let metadata = WorkerMetadata {
    runtime: "rust".to_string(),
    version: "0.4.1".to_string(),
    name: "my-worker".to_string(),
    os: "linux".to_string(),
    telemetry: None,
};

iii.call_void("engine::workers::register", metadata)?;
```

<Note>
  Worker metadata is automatically registered when you call `connect()`, so you typically don't need to call this manually.
</Note>

### Create Channel

```rust theme={null}
let result = iii.call(
    "engine::channels::create",
    json!({ "buffer_size": 1000 })
).await?;
```

Or use the convenience method:

```rust theme={null}
let channel = iii.create_channel(Some(1000)).await?;
```

## Typed Invocations

For type-safe function calls, define request and response types:

```rust theme={null}
use serde::{Deserialize, Serialize};

#[derive(Serialize)]
struct CreateUserRequest {
    name: String,
    email: String,
}

#[derive(Deserialize)]
struct CreateUserResponse {
    id: String,
    name: String,
}

let request = CreateUserRequest {
    name: "Alice".to_string(),
    email: "alice@example.com".to_string(),
};

let result = iii.call("user.create", request).await?;
let response: CreateUserResponse = serde_json::from_value(result)?;

println!("Created user: {} ({})", response.name, response.id);
```

## See Also

* [Functions API](/rust/api/functions) - Register functions that can be called
* [Telemetry API](/rust/api/telemetry) - Configure distributed tracing
* [Context API](/rust/api/context) - Access context within function handlers
