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.
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.
Run a search#
- 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
Call SemanticSearch with a query#
SemanticSearchtakes a*primitiveapi.SemanticSearchInputand acontext.Contextfor 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
Read the ranked results#
SemanticSearchreturns aSemanticSearchResponse:type SemanticSearchResponse struct { Data []primitiveapi.SemanticSearchResult Meta primitiveapi.SemanticSearchMeta }Datais 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.Cursoris 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.
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#
Normalize inbound mail into a ReceivedEmail before you search or act on it.
Error HandlingLook up every error type SemanticSearch and other calls can return.
Client and ConfigurationUnderstand the dual-host client that SemanticSearch routes through.
Context, Timeouts, and CancellationApply a deadline or cancellation signal to a SemanticSearch call.
Was this page helpful?