---
title: "Semantic Search (Go SDK)"
canonical: "https://test.abhinandan.one/go-semantic-search"
markdown_url: "https://test.abhinandan.one/go-semantic-search.md"
publisher: "Primitive SDKs"
kind: "guide"
content_type: "reference"
category: "Go SDK"
description: "Client.SemanticSearch runs ranked semantic, hybrid, or keyword search across received and sent mail and requires the Pro plan's semantic_search_enabled entitlement."
keywords: ["Client.SemanticSearch", "SemanticSearchInput", "SemanticSearchResult", "semantic_search_enabled", "POST /v1/semantic-search", "semantic-search host-2"]
last_modified: "2026-08-11T18:55:01.211428+00:00"
published_at: "2026-08-11T18:55:01.056916+00:00"
source_files:
  - "sdk-go/client.go"
  - "sdk-node/src/api/index.ts"
  - "sdk-python/src/primitive/client.py"
sections:
  - {anchor: "when-to-use-it", title: "When to use it"}
  - {anchor: "run-a-search", title: "Run a search"}
  - {anchor: "step-build-the-client", title: "Build the client"}
  - {anchor: "step-call-semanticsearch-with-a-query", title: "Call SemanticSearch with a query"}
  - {anchor: "step-read-the-ranked-results", title: "Read the ranked results"}
  - {anchor: "expected-result", title: "Expected result"}
  - {anchor: "handling-errors", title: "Handling errors"}
  - {anchor: "next-steps", title: "Next steps"}
---

> Documentation index: https://test.abhinandan.one/llms.txt

# Semantic Search (Go SDK)

Run ranked semantic, hybrid, or keyword search across received and sent mail from the Go SDK with Client.SemanticSearch, and read the matched-field excerpts and score breakdown on each result row.

## When to use it

Use `Client.SemanticSearch`, which POSTs to `/v1/semantic-search`, when a meaning-based query across received and sent mail ("the invoice from last month about the API overage") is more useful than filtering by sender or date. It returns ranked rows rather than a raw list.

The call requires the Pro plan and the `semantic_search_enabled` entitlement. Callers without them get an [`APIError`](https://test.abhinandan.one/go-error-handling.md) with `StatusCode: 403`.

> **Note:** The endpoint lives on the same worker host as `/send-mail`. `Client.SemanticSearch` routes to that host-2 client internally, see [Client and Configuration](https://test.abhinandan.one/go-client-configuration.md) for the dual-host split, so you never configure this yourself.

## Run a search

### 1. Build the client

```go
package main

import (
	"context"
	"fmt"
	"log"

	primitive "github.com/primitivedotdev/sdks/sdk-go"
	primitiveapi "github.com/primitivedotdev/sdks/sdk-go/api"
)

func main() {
	client, err := primitive.NewClient("prim_test")
	if err != nil {
		log.Fatal(err)
	}
	_ = client
}
```

### 2. Call SemanticSearch with a query

`SemanticSearch` takes a `*primitiveapi.SemanticSearchInput` and a `context.Context` for [cancellation and timeouts](https://test.abhinandan.one/go-context-timeouts.md):

```go
ctx := context.Background()

res, err := client.SemanticSearch(ctx, &primitiveapi.SemanticSearchInput{
	Query: "invoice overage from last month",
})
if err != nil {
	log.Fatal(err)
}

for _, row := range res.Data {
	fmt.Printf("%+v\n", row)
}
fmt.Println("meta:", res.Meta)
```

### 3. Read the ranked results

`SemanticSearch` returns a `SemanticSearchResponse`:

```go
type SemanticSearchResponse struct {
	Data []primitiveapi.SemanticSearchResult
	Meta primitiveapi.SemanticSearchMeta
}
```

- `Data` is the ranked rows, newest-first as a tiebreak within equal scores. Each row carries the matched fields, a match-centered excerpt, and an additive score breakdown.
- `Meta.Cursor` is non-null when another page is available.

## Expected result

A successful call returns a `SemanticSearchResponse` with `Data` populated and a `nil` error. An empty `Data` slice with a `nil` error means the query matched nothing, not a failure, so check `len(res.Data) == 0` rather than treating it as an error path.

## Handling errors

Every non-2xx response maps to an `*primitive.APIError`, which you inspect with `errors.As`:

```go
import (
	"errors"
	"log"

	primitive "github.com/primitivedotdev/sdks/sdk-go"
	primitiveapi "github.com/primitivedotdev/sdks/sdk-go/api"
)

res, err := client.SemanticSearch(ctx, &primitiveapi.SemanticSearchInput{
	Query: "invoice overage",
})
if err != nil {
	var apiErr *primitive.APIError
	if errors.As(err, &apiErr) {
		if apiErr.StatusCode == 403 {
			log.Fatal("semantic search requires the Pro plan and semantic_search_enabled")
		}
	}
	log.Fatal(err)
}
```

See [Error Handling](https://test.abhinandan.one/go-error-handling.md) for the full `APIError` shape, including `RetryAfter` on a `429`.

> **Tip:** Passing a nil request fails before any network call with `request is required`, and calling the method on an unconfigured client fails with `client is not configured`. Always build the client with `NewClient` and pass a non-nil `*primitiveapi.SemanticSearchInput`.
