Documentation Index: Fetch llms.txt first to discover every published page. This page is also available as Markdown at /go-semantic-search.md.
Verified · 8/11/2026

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 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 for the dual-host split, so you never configure this yourself.

  1. 1

    Build the client#

    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. 2

    Call SemanticSearch with a query#

    SemanticSearch takes a *primitiveapi.SemanticSearchInput and a context.Context for cancellation and timeouts:

    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. 3

    Read the ranked results#

    SemanticSearch returns a SemanticSearchResponse:

    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:

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

Next steps#

Was this page helpful?

© Primitive SDKs

Powered by Browzer