Welcome to the Sayari Graph SDK for Go. The goal of this project is to get you up and running as quickly as possible so you can start benefiting from the power of Sayari Graph. In the new few sections you will learn how to setup and use the Sayari Graph SDK. We also document some example use cases to show how easy it is to build the power of Sayari Graph into your application.

This SDK is in beta, and there may be breaking changes between versions without a major version update.

Setup

Prerequisites

The only thing you need to start using this SDK are your CLIENT_ID and CLIENT_SECRET provided to you by Sayari.

Interested and need credentials? Fill out this form and our team will get in touch.

Installation

To install this SDK, simply run go get "github.com/sayari-analytics/sayari-go/..." Then simply import “github.com/sayari-analytics/sayari-go/sdk” into your go code to use the SDK.

Quickstart

This section will walk you through a basic example of connecting to Sayari Graph, resolving and entity, and getting that entity’s detailed information.

Connecting

To connect to Sayari Graph, simply create a client object by calling the SDK’s ‘Connect’ method and passing in your client ID and secret. Note: For security purposes, it is highly recommended that you don’t hardcode your client ID and secret in your code. Instead, simply export them as environment variables and use those.

1client, err := sdk.Connect(os.Getenv("CLIENT_ID"), os.Getenv("CLIENT_SECRET"))
2if err != nil {
3 log.Fatalf("Error: %v", err)
4}

Resolving an entity

Now that we have a client, we can use the Resolution method to find an entity. To do this we create a resolution request with the entity information we are using to search. Full documentation of this endpoint can be seen in the API docs.

A request to resolve an entity with the name “Victoria Beckham” is shown below:

1// Create the request body
2resolutionRequest := sayari.Resolution{Name: []*string{sdk.String("Victoria Beckham")}}
3
4// Make the request and handle the error
5resolution, err := client.Resolution.Resolution(context.Background(), &resolutionRequest)
6if err != nil {
7 log.Fatalf("Error: %v", err)
8}

Getting entity information

The resolution results themselves do contain some information about the entities found, but to get all the details for that entity we need to call the “get entity” endpoint.

A request to view the first resolved entity (best match) from the previous request would look like this:

1// Get the entity details for the best match
2entityDetails, err := client.Entity.GetEntity(context.Background(), resolution.Data[0].EntityId, &sayari.GetEntity{})
3if err != nil {
4 log.Fatalf("Error: %v", err)
5}

Complete example

After the steps above you should be left with code looks like this. We can add one final line to print all the fields of the resolved entity to see what it looks like.

1package main
2
3import (
4 "context"
5 "log"
6 "os"
7
8 sayari "github.com/sayari-analytics/sayari-go/generated/go"
9 "github.com/sayari-analytics/sayari-go/sdk"
10)
11
12func main() {
13 // NOTE: To connect you most provide your client ID and client secret. To avoid accidentally checking these into git,
14 // it is recommended to use ENV variables
15
16 // Create a client to auth against the API
17 client, err := sdk.Connect(os.Getenv("CLIENT_ID"), os.Getenv("CLIENT_SECRET"))
18 if err != nil {
19 log.Fatalf("Error: %v", err)
20 }
21
22 // Create the request body
23 resolutionRequest := sayari.Resolution{
24 Name: []*string{sdk.String("Victoria Beckham")},
25 }
26
27 // Make the request and handle the error
28 resolution, err := client.Resolution.Resolution(context.Background(), &resolutionRequest)
29 if err != nil {
30 log.Fatalf("Error: %v", err)
31 }
32
33 // Get the entity details for the best match
34 entityDetails, err := client.Entity.GetEntity(context.Background(), resolution.Data[0].EntityId, &sayari.GetEntity{})
35 if err != nil {
36 log.Fatalf("Error: %v", err)
37 }
38
39 log.Printf("%+v", entityDetails)
40}

Advanced

When interacting with the API directly, there are a few concepts that you need to handle manually. The SDK takes care of these things for you, but it is important to understand them if you want to use the SDK properly.

Authentication and token management

As you can see from the API documentation, there is an endpoint provided for authenticating to Sayari Graph which will return a bearer token. This token is then passed on all subsequent API calls to authenticate them. The SDK handles this process for you by first requesting the token and then adding it to all subsequent requests.

In addition to simplifying the connection process, the SDK is also designed to work in long-running application and keep the token up to date by rotating it before it expires. This is all handled behind the scenes by the client object itself and should require no additional action by the user.

Rate limiting

Some Sayari Graph endpoints are more compute intensive than others. To adequately allocate resources across customers and prevent service degradation, individual users are rate limited. It is very unlikely that you would ever encounter these limits when making requests manually or even in a single-threaded application. Typically, rate limiting will only come into play when making multiple API requests at the same time.

When a request is rate limited, the API will respond back with a 429 status code as well as a ‘Retry-After’ response header that tells you how long to wait before making a subsequent request (i.e. 5s).

To make things simpler, the SDK handles this for you and will automatically wait and retry requests if a 429 is received.

Guides

You should now have all the tools you need to start using the Sayari Graph Go SDK yourself. If you would like additional inspiration, please consider the following use-case-specific guides.


Examples

Please see the API documentation for detailed explanations of all the request and response bodies. Our documentation site (along with valid client ID and secret) can be used to make requests against our API to get a sense for how the API behaves.

In addition to the API documentation, the SDK code itself is a great resource for understanding the structure of Sayari Graph API requests and responses. Objects in the code should have helpful names and comments detailing their significance.

What follows is a list of invocation examples for each of the SDK functions. Again, this is not an exhaustive demonstration if its capabilities, but rather a minimal example to help you get started.

Top Level SDK functions

As mentioned above, this SDK provides some convenience functions beyond those available purely via the Sayari Graph API.

Connect

The connect function can be used to create an authenticated API client which supplies the methods for the rest of the SDK’s functionality. In addition to handling the authentication, this client object will also handle re-authentication in cases where the client is longer-lived then the duration of the initial authentication request.

To call the ‘Connect’ function, simply provide the client ID and secret

1client, err := sdk.Connect(os.Getenv("CLIENT_ID"), os.Getenv("CLIENT_SECRET"))
2if err != nil {
3 log.Fatalf("Error: %v", err)
4}

ScreenCSVEntities

One of the most common use cases for the Sayari Graph API is screening entities for potential risks. Because of this, the SDK includes tooling to simplify this process.

The ‘ScreenCSVEntities’ function takes in the path for a CSV containing entities to screen, and returns those entities and their associated risks. For this to work properly, the CSV must only contain columns that map to entity attributes. Valid names for those columns are as follows: (column names are case and spacing insensitive)

  • Name
  • Identifier
  • Country
  • Address
  • Date Of Birth
  • Contact
  • Entity Type

Once your CSV is property formatted, using the screen function is as simple as providing the path to the CSV.

1riskyEntities, nonRiskyEntities, unresolved, err := client.ScreenCSVEntities(context.Background(), "entities_to_screen.csv")
2 if err != nil {
3 log.Fatalf("Failed to screen entities. Err: %v", err)
4 }

As you can see from this example, the first object returned is a slice of entities that do have risks, the next is a slice of entities without risks, and the third is a slice of rows from the CSV that were unable to be resolved.

Pointers

To differentiate between not providing values and providing empty values, we follow the common go patter of using pointers. For, to allow us to differentiate between an integer value of 0 and no value at all we can pass a pointer either to a integer with a value of 0 or no pointer at all.

Because of this, we often need to specify pointers in our param structs. To make this easier/faster there are convenience functions. The snippet below shows and example of this. As you can see, we are limiting our entity search to just the first result by providing a pointer to an integer with a value of 1.

1package main
2
3import (
4 "context"
5 "log"
6 "os"
7
8 sayari "github.com/sayari-analytics/sayari-go/generated/go"
9 "github.com/sayari-analytics/sayari-go/sdk"
10)
11
12func main() {
13 // Create a client to auth against the API
14 client, err := sdk.Connect(os.Getenv("CLIENT_ID"), os.Getenv("CLIENT_SECRET"))
15 if err != nil {
16 log.Fatalf("Error: %v", err)
17 }
18
19 // Traversal
20 entity, err := client.Search.SearchEntity(context.Background(), &sayari.SearchEntity{Q: "Joe Smith", Limit: sayari.Int(1)})
21 if err != nil {
22 log.Fatalf("Error: %v", err)
23 }

Entity

Get Entity

1entityDetails, err := client.Entity.GetEntity(context.Background(), myEntityID, &sayari.GetEntity{})
2if err != nil {
3 log.Fatalf("Error: %v", err)
4}

Entity Summary

1entitySummary, err := client.Entity.EntitySummary(context.Background(), myEntityID)
2if err != nil {
3 log.Fatalf("Error: %v", err)
4}

Record

Get Record

Note: record ID’s must be URL escaped

1record, err := client.Record.GetRecord(context.Background(), url.QueryEscape(myRecordID), &sayari.GetRecord{})
2if err != nil {
3 log.Fatalf("Error: %v", err)
4}

Resolution

Resolution

1resolution, err := client.Resolution.Resolution(context.Background(), &sayari.Resolution{Name: []*string{sayari.String("search term")}})
2if err != nil {
3 log.Fatalf("Error: %v", err)
4}

Search Entity

1entitySearchResults, err := client.Search.SearchEntity(context.Background(), &sayari.SearchEntity{Q: "search term"})
2if err != nil {
3 log.Fatalf("Error: %v", err)
4}

Search Record

1recordSearch, err := client.Search.SearchRecord(context.Background(), &sayari.SearchRecord{Q: "search term"})
2if err != nil {
3 log.Fatalf("Error: %v", err)
4}

Source

List Sources

1sources, err := client.Source.ListSources(context.Background(), &sayari.ListSources{})
2if err != nil {
3 log.Fatalf("Error: %v", err)
4}

Get Source

1source, err := client.Source.GetSource(context.Background(), mySourceID)
2if err != nil {
3 log.Fatalf("Error: %v", err)
4}

Traversal

Traversal

1traversal, err := client.Traversal.Traversal(context.Background(), myEntityID, &sayari.Traversal{})
2if err != nil {
3 log.Fatalf("Error: %v", err)
4}

UBO

1ubo, err := client.Traversal.Ubo(context.Background(), myEntityID)
2if err != nil {
3 log.Fatalf("Error: %v", err)
4}

Ownership

1ownership, err := client.Traversal.Ownership(context.Background(), myEntityID)
2if err != nil {
3 log.Fatalf("Error: %v", err)
4}

Watchlist

1watchlist, err := client.Traversal.Watchlist(context.Background(), myEntityID)
2if err != nil {
3 log.Fatalf("Error: %v", err)
4}

Shortest Path

1shortestPath, err := client.Traversal.ShortestPath(context.Background(), &sayari.ShortestPath{Entities: []string{myFirstEntityID, mySecondEntityID}})
2if err != nil {
3 log.Fatalf("Error: %v", err)
4}

Trade

1shipments, err := client.Trade.SearchShipments(context.Background(), &sayari.SearchShipments{Q: "search term"})
2if err != nil {
3 log.Fatalf("Error: %v", err)
4}
1suppliers, err := client.Trade.SearchSuppliers(context.Background(), &sayari.SearchSuppliers{Q: "search term"})
2if err != nil {
3 log.Fatalf("Error: %v", err)
4}
1buyers, err := client.Trade.SearchBuyers(context.Background(), &sayari.SearchBuyers{Q: "search term"})
2if err != nil {
3 log.Fatalf("Error: %v", err)
4}