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
- Go 1.21 or newer.
- A secret key, and a webhook signing secret if you receive webhooks.
Install
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.
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.
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.
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
| Member | Returns | Notes |
|---|---|---|
fingerly.New(secretKey string, opts ...Option) | *Client | Options: 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) | bool | Five minutes of tolerance. VerifyWebhookWithTolerance changes it. |