> ## 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

> Use Sift's gRPC API with official client libraries or grpcurl.

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 handles high-frequency telemetry ingestion and real-time analysis. It uses Protocol Buffers to define services and messages for efficient, high-throughput communication. You can interact with it 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.

Client libraries use [gRPC interceptors](https://grpc.io/docs/guides/interceptors/) to automate authentication and request handling. To authenticate a request directly, see [Authenticate with the API](/api/authenticate/authenticate-with-the-api).

## 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">
    ```bash theme={null}
    grpcurl $SIFT_GRPC_BASE_URL:$PORT_NUM list sift.assets.v1.AssetService
    ```
  </Tab>
</Tabs>

<Info>
  **gRPC base URL and port:** Do not include `https://` in the base URL, use only the hostname. `$PORT_NUM` is always `443`.
</Info>

## Official client libraries

Sift provides pre-built client libraries for Python, Rust, and Go, maintained as open source in the [Sift GitHub repository](https://github.com/sift-stack/sift). These libraries use the gRPC API internally. Supported languages:

* [Python](#python)
* [Rust](#rust)
* [Go](#go)

### Other languages

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

* [Generate a client with Buf](/api/clients/generate-a-client-with-buf) to compile Sift's Protocol Buffers into gRPC client code for your preferred language.
* Use the [Sift REST API](/api/overview#choosing-between-rest-and-grpc), 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'],
]}
/>

<Info>
  **Port:** The gRPC API uses port `443` by default in all environments.
</Info>

## Connect with an official client

### Python

1. Create a Python environment.

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

2. In your Python environment (`venv`) install the [Sift Python package](https://pypi.org/project/sift-stack-py/):

   ```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
   ```

See the [Python client documentation](https://sift-stack.github.io/sift/python/latest/) for the full API reference.

### Rust

1. Create a Rust project.

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

2. In your Rust project, add the [`sift_rs`](https://crates.io/crates/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
   ```

### Go

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](https://pkg.go.dev/github.com/sift-stack/sift/go) 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 .
   ```
