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

# gRPC (Protocol Buffers)

export const MintTable = ({columns = [], rows = [], columnWidths = []}) => {
  const pushTextWithLineBreaks = (parts, text, keyBase) => {
    const segments = String(text).split(/\\n|\n/);
    segments.forEach((segment, idx) => {
      if (segment) {
        parts.push(<span key={`${keyBase}-text-${idx}`}>{segment}</span>);
      }
      if (idx < segments.length - 1) {
        parts.push(<br key={`${keyBase}-br-${idx}`} />);
      }
    });
  };
  const parseMarkdown = text => {
    if (text === null || text === undefined) return "";
    const str = String(text);
    const parts = [];
    let lastIndex = 0;
    const pattern = /(`[^`]+`|\*\*[^*]+\*\*|\*[^*]+\*|\[([^\]]+)\]\(([^)]+)\))/g;
    let match;
    while (true) {
      match = pattern.exec(str);
      if (match === null) {
        break;
      }
      if (match.index > lastIndex) {
        pushTextWithLineBreaks(parts, str.substring(lastIndex, match.index), `before-${lastIndex}`);
      }
      const fullMatch = match[0];
      if (fullMatch.startsWith("`") && fullMatch.endsWith("`")) {
        parts.push(<code key={match.index}>{fullMatch.slice(1, -1)}</code>);
      } else if (fullMatch.startsWith("**") && fullMatch.endsWith("**")) {
        parts.push(<strong key={match.index}>{fullMatch.slice(2, -2)}</strong>);
      } else if (fullMatch.startsWith("*") && fullMatch.endsWith("*")) {
        parts.push(<em key={match.index}>{fullMatch.slice(1, -1)}</em>);
      } else if (fullMatch.startsWith("[")) {
        const linkText = match[2];
        const linkUrl = match[3];
        parts.push(<a key={match.index} href={linkUrl} className="text-black-600 dark:text-black-400">
            {linkText}
          </a>);
      }
      lastIndex = pattern.lastIndex;
    }
    if (lastIndex < str.length) {
      pushTextWithLineBreaks(parts, str.substring(lastIndex), `tail-${lastIndex}`);
    }
    if (parts.length > 0) {
      return parts;
    }
    const plainParts = [];
    pushTextWithLineBreaks(plainParts, str, "plain");
    return plainParts.length ? plainParts : str;
  };
  const safeColumns = Array.isArray(columns) ? columns : [];
  const safeRows = Array.isArray(rows) ? rows : [];
  const safeColumnWidths = Array.isArray(columnWidths) ? columnWidths : [];
  const hasColumnWidths = safeColumnWidths.some(w => w !== null && w !== undefined && w !== "");
  const toCssWidth = width => typeof width === "number" ? `${width}px` : String(width);
  const getColumnStyle = idx => {
    const rawWidth = safeColumnWidths[idx];
    if (rawWidth === null || rawWidth === undefined || rawWidth === "") {
      return undefined;
    }
    const width = toCssWidth(rawWidth);
    return {
      width,
      minWidth: width
    };
  };
  const containerStyle = hasColumnWidths ? undefined : {
    overflowX: "auto"
  };
  const tableStyle = hasColumnWidths ? {
    tableLayout: "fixed",
    width: "100%"
  } : {
    width: "max-content",
    minWidth: "100%"
  };
  if (!Array.isArray(columns) || !Array.isArray(rows) || !Array.isArray(columnWidths)) {
    console.warn("MintTable received invalid props:", {
      columns,
      rows,
      columnWidths
    });
  }
  if (!safeColumns.length && !safeRows.length) {
    return null;
  }
  return <div className="mint-table-container" style={containerStyle}>
      <table style={tableStyle}>
        {hasColumnWidths && <colgroup>
            {safeColumns.map((_, idx) => {
    const style = getColumnStyle(idx);
    return <col key={idx} style={style} />;
  })}
          </colgroup>}
        <thead>
          <tr>
            {safeColumns.map((col, idx) => <th key={idx} className="text-left" style={getColumnStyle(idx)}>
                <b>{parseMarkdown(col)}</b>
              </th>)}
          </tr>
        </thead>
        <tbody>
          {safeRows.map((row, rIdx) => {
    const safeRow = Array.isArray(row) ? row : [];
    return <tr key={rIdx}>
                {safeRow.map((cell, cIdx) => <td key={cIdx} style={getColumnStyle(cIdx)}>
                    {parseMarkdown(cell)}
                  </td>)}
              </tr>;
  })}
        </tbody>
      </table>
    </div>;
};

Sift's gRPC API is designed for high-frequency telemetry ingestion and real-time analysis, offering optimized performance and scalability. It uses **Protocol Buffers** for defining services and messages, enabling efficient, high-throughput communication. You can interact with Sift's gRPC API in multiple ways:

* Directly using standard tools like [`grpcurl`](https://github.com/fullstorydev/grpcurl) or by writing your own gRPC clients.
* Using Sift's pre-built client libraries, available for select programming languages to simplify setup.

<Callout type="info">
  - Sift's client libraries internally use the gRPC API. If a client library is not available for your preferred language, you can manually generate client code from Sift's Protocol Buffers or use command-line tools to interact with the gRPC API.
  - To learn how to authenticate with the gRPC API, see [Authenticate with the gRPC API](../../api/how-to-guides/grpc/authenticate-with-the-grpc-api).
  - Client libraries use [gRPC interceptors](https://grpc.io/docs/guides/interceptors/) to automate authentication and request handling.
</Callout>

## Listing services from the command line

You can use [`grpcurl`](https://github.com/fullstorydev/grpcurl) to explore Sift's available gRPC services directly from the command line.

<Tabs>
  <Tab title="List all available services">
    ```bash theme={null}
      grpcurl $SIFT_GRPC_BASE_URL:$PORT_NUM list
    ```
  </Tab>

  <Tab title="List all endpoints of a particular service (for example, AssetService)">
    ```bash theme={null}
    grpcurl $SIFT_GRPC_BASE_URL:$PORT_NUM list sift.assets.v1.AssetService
    ```
  </Tab>
</Tabs>

<Callout type="info">
  * Replace `$SIFT_GRPC_BASE_URL` and `$PORT_NUM` with your actual gRPC endpoint and port.
  * When running a `grpcurl` command, do not include `https://` in the base URL. The base URL should consist only of the hostname without any protocol prefix.
  * The `$PORT_NUM` placeholder should be replaced with `443`, which is the required port for the gRPC base URL in all environments.
</Callout>

## Official client libraries to connect with Sift's gRPC API

Sift provides pre-built client libraries for select programming languages, designed to simplify and accelerate integration with Sift's gRPC API. Sift's official client libraries internally use the gRPC API. These libraries offer helpful utilities and reduce the boilerplate required to get started. All libraries are open source and maintained in the [Sift GitHub repository](https://github.com/sift-stack/sift). Supported languages:

<MintTable
  columns={['Language', 'Library', 'Quickstart', 'Documentation']}
  columnWidths={['15%', '35%', '20%', '30%']}
  rows={[
['**Python**', '[sift-stack-py](https://pypi.org/project/sift-stack-py/)', '[Example](#python)', '[Python documentation](https://sift-stack.github.io/sift/python/latest/)'],
['**Rust**', '[sift_rs](https://crates.io/crates/sift_rs)', '[Example](#rust)', '[Rust documentation](https://docs.rs/sift_rs/0.1.0-rc.2/sift_rs/)'],
['**Go**', '[github.com/sift-stack/sift/go](https://pkg.go.dev/github.com/sift-stack/sift/go)', '[Example](#go)', '[Go documentation](https://pkg.go.dev/github.com/sift-stack/sift/go)'],
]}
/>

### Using other languages to connect with Sift's gRPC API

If your preferred language doesn't yet have a dedicated client library, you can instead:

* Compile Sift's **Protocol Buffers** manually to generate gRPC client code in your preferred language.
* Use the Sift **REST** API, which provides a standard HTTP-based interface for integration.

### URL formatting for official gRPC clients

The required format for official gRPC API URLs depends on your client library. Some libraries require you to omit the URL scheme and port number, while others expect them to be included. Refer to the documentation of your chosen client library to confirm the expected URL format.

<MintTable
  columns={['Language', 'Requires `https://` prefix', 'Requires port number']}
  columnWidths={['25%', '40%', '35%']}
  rows={[
['**Python**', 'No', 'No'],
['**Rust**', 'Yes', 'No'],
['**Go**', 'No', 'Yes'],
]}
/>

<Callout type="info">
  The gRPC API uses port `443` by default in all environments.
</Callout>

## Quickstart: Connect to the gRPC API with an official Sift client

### Python

To quickly connect with Sift's Python client, consider the following steps:

1. Create a Python environment.

   ```bash theme={null}
     python3 -m venv venv 
   ```

2. In your Python environment (`venv`) install the Sift Python package:

   ```bash theme={null}
   pip install sift-stack-py
   ```

3. In your Python environment directory, create a file named `main.py` and paste the following code:

   ```python theme={null}
   import os

   from sift.ping.v1.ping_pb2 import PingRequest
   from sift.ping.v1.ping_pb2_grpc import PingServiceStub
   from sift_py.grpc.transport import SiftChannelConfig, use_sift_channel

   if __name__ == "__main__":
       apikey = os.getenv("SIFT_API_KEY")
       assert apikey

       uri = os.getenv("SIFT_GRPC_BASE_URL")
       assert uri

       channel_config: SiftChannelConfig = {
           "apikey": apikey,
           "uri": uri,
       }

       with use_sift_channel(channel_config) as channel:
           response = PingServiceStub(channel).Ping(PingRequest())
           print(response)
   ```

4. In your Python environment directory, run the following command after replacing the placeholders (`$SIFT_API_KEY` and `$SIFT_GRPC_BASE_URL`) with your actual values:

   ```bash theme={null}
   SIFT_GRPC_BASE_URL=$SIFT_GRPC_BASE_URL:$PORT_NUM SIFT_API_KEY=$SIFT_API_KEY python main.py
   ```

   * `$SIFT_API_KEY`: To learn how to create an API key, see [Create an API key]().
   * `$SIFT_GRPC_BASE_URL`:
     * The Python client allows you to omit the URL scheme and port number.
     * To learn how to obtain the base URL for gRPC requests, see [Obtain the base URL for REST/gRPC requests]().

### Rust

To quickly connect with Sift's Rust client, consider the following steps:

1. Create a Rust project.

   ```bash theme={null}
   cargo new my_sift_project
   ```

2. In your Rust project, add the `sift_rs` crate.

   ```bash theme={null}
   cd my_sift_project
   cargo add sift_rs
   ```

3. In your Rust project, add the `tokio` runtime.

   ```bash theme={null}
   cargo add tokio --features full
   ```

4. Copy and paste the following into your `my_sift_project/src/main.rs`:

   ```bash theme={null}
   use sift_rs::{
       Credentials, SiftChannelBuilder,
       ping::v1::{PingRequest, ping_service_client::PingServiceClient},
   };
   use std::env;

   #[tokio::main]
   async fn main() {
       let credentials = Credentials::Config {
           apikey: env::var("SIFT_API_KEY").unwrap(),
           uri: env::var("SIFT_GRPC_BASE_URL").unwrap(),
       };

       let conn = SiftChannelBuilder::new(credentials).build().unwrap();
       let mut ping_service = PingServiceClient::new(conn);
       let ping_response = ping_service.ping(PingRequest::default()).await.unwrap();

       println!("{}", ping_response.into_inner().response);
   }
   ```

5. In your Rust project directory, run the following command after replacing the placeholders (`$SIFT_API_KEY` and `$SIFT_GRPC_BASE_URL`) with your actual values:

   ```bash theme={null}
   SIFT_GRPC_BASE_URL=$SIFT_GRPC_BASE_URL:$PORT_NUM SIFT_API_KEY=$SIFT_API_KEY cargo run
   ```

   * `$SIFT_API_KEY`: To learn how to create an API key, see [Create an API key]().
   * `$SIFT_GRPC_BASE_URL`:
     * The Rust client requires you to add the URL scheme while adding the port number is optional.
     * To learn how to obtain the base URL for gRPC requests, see [Obtain the base URL for REST/gRPC requests]().

### Go

To quickly connect with Sift's Go client, consider the following steps:

1. Set up a dedicated directory and initialize it as a Go module using `go mod`:

   ```bash theme={null}
   mkdir go-client-connection && cd go-client-connection
   go mod init sift_go_project
   ```

2. Use `go get` to fetch the Sift Go SDK and include it in your project:

   ```bash theme={null}
   go get github.com/sift-stack/sift/go
   ```

3. In the `sift_go_project` directory, create a `main.go` file and copy and paste the following into that file:

   ```bash theme={null}
   package main

   import (
       "context"
       "fmt"
       "log"
       "os"

       "github.com/sift-stack/sift/go/gen/sift/ping/v1"
       "github.com/sift-stack/sift/go/grpc"
   )

   func main() {
       ctx := context.Background()
       channelConfig := grpc.SiftChannelConfig{
           Uri:    os.Getenv("SIFT_GRPC_BASE_URL"),
           Apikey: os.Getenv("SIFT_API_KEY"),
       }
       conn, err := grpc.UseSiftChannel(ctx, channelConfig)
       if err != nil {
           log.Fatalln(err)
       }
       pingClient := pingv1.NewPingServiceClient(conn)
       res, err := pingClient.Ping(ctx, &pingv1.PingRequest{})
       if err != nil {
           log.Fatalln(err)
       }
       fmt.Println(res.Response)
   }
   ```

4. Verify and tidy up your module dependencies:

   ```bash theme={null}
   go mod tidy 
   ```

5. In your Go module, run the following command after replacing the placeholders (`$SIFT_API_KEY`, `$SIFT_GRPC_BASE_URL`, and `$PORT_NUM`) with your actual values:

   ```bash theme={null}
   SIFT_GRPC_BASE_URL=$SIFT_GRPC_BASE_URL:$PORT_NUM SIFT_API_KEY=$SIFT_API_KEY go run .
   ```

   * `$SIFT_GRPC_BASE_URL`: The base URL for Sift gRPC requests.
     * The Go client expects the base URL without the URL scheme (for example, use `api.siftstack.com`, not `https://api.siftstack.com`).
     * To learn how to obtain the base URL for gRPC requests, see [Obtain the base URL for REST/gRPC requests]().
   * `$PORT_NUM`: The port number used for gRPC connections.
     * Defaults to `443` in all environments.
     * The Go client requires you to explicitly include the port number.
   * `$SIFT_API_KEY`: Your Sift API key for authentication.
     * To learn how to generate an API key, see [Create an API key]().
