SDKs

Go

Read identification events with a secret key and verify signed webhooks from Go, with context-aware calls and typed events.

The Go module reads stored events by request ID and verifies webhook signatures. Every call takes a context.Context, and the client is safe for concurrent use.

Requirements

Install

Terminal
go get github.com/fingerly-io/fingerly-go

Read an event

Create one client with your secret key and reuse it. The key decides the regional API and the environment the client reads.

Go
import fingerly "github.com/fingerly-io/fingerly-go"

client := fingerly.New(os.Getenv("FINGERLY_SECRET_KEY"))
event, err := client.Events.Get(ctx, "01a0a84b-e6a2-7c09-9f51-0b3d7a26c8e4")

An event has the fields listed in Get an event. suspect_score is null when the request was not scored.

Verify a checkout

Read the event your client identified, check it belongs to this action and is recent, then decide on its level. See server-side verification.

Go
func decide(ctx context.Context, orderID, requestID string) (string, error) {
    event, err := client.Events.Get(ctx, requestID)
    var apiErr *fingerly.APIError
    if errors.As(err, &apiErr) && apiErr.Status == http.StatusNotFound {
        return "refuse", nil
    } else if err != nil {
        return "", err
    }

    if event.Tag != "checkout:"+orderID || time.Since(event.OccurredAt) > 2*time.Minute {
        return "refuse", nil
    }

    switch event.SuspectLevel {
    case "high":
        return "review", nil
    case "medium":
        return "challenge", nil
    }
    return "allow", nil
}

Verify a webhook

Check the signature over the raw request body before parsing it. The helper rejects timestamps more than five minutes from now.

Go
func fingerlyWebhook(w http.ResponseWriter, r *http.Request) {
    body, err := io.ReadAll(r.Body)
    if err != nil {
        http.Error(w, "unreadable body", http.StatusBadRequest)
        return
    }
    if !fingerly.VerifyWebhook(
        os.Getenv("FINGERLY_WEBHOOK_SECRET"),
        body,
        r.Header.Get("X-Fingerly-Timestamp"),
        r.Header.Get("X-Fingerly-Signature"),
    ) {
        http.Error(w, "invalid signature", http.StatusBadRequest)
        return
    }

    var event fingerly.WebhookEvent
    _ = json.Unmarshal(body, &event)
    enqueue(event.ID, body)   // deduplicate on the event ID
    w.WriteHeader(http.StatusNoContent)
}

API

MemberReturnsNotes
fingerly.New(secretKey string, opts ...Option)*ClientOptions: WithEndpoint, WithHTTPClient.
client.Events.Get(ctx, requestID)(*Event, error)A non-2xx response returns *fingerly.APIError with Status.
client.Events.List(ctx, *EventListParams)(*EventPage, error)Params: From, To (time.Time), Page, Limit, Visitor, Level.
fingerly.VerifyWebhook(secret, body, timestamp, signature)boolFive minutes of tolerance. VerifyWebhookWithTolerance changes it.