Go SDK
Biometry Go SDK
The official Go SDK for the Biometry platform. It provides a simple, idiomatic Go interface for biometric verification, document authentication, and transaction management — all authenticated via API keys.
Repository: github.com/Namadgi/biometry-go
Features
- Session Management: Start and end biometric verification sessions
- Video Processing: Submit videos for multi-service biometric verification
- Face & Voice Enrollment: Enroll users for face and voice recognition
- Face Matching: Compare faces from images and videos, with session video reuse
- Document Authentication: Verify document authenticity with MRZ validation
- Transaction Queries: List, count, filter, and tag transactions
- Anti-Video Forgery: Detect video manipulation attempts
- API Key Management: Mint, revoke, and inspect API keys
- Zero Dependencies: Uses only Go standard library (
net/http)
Installation
go get github.com/Namadgi/biometry-goRequires Go 1.26.1 or later.
Quick Start
Initialize the client
package main
import ( "context" "fmt" "log" "os"
"github.com/Namadgi/biometry-go")
func main() { client := biometry.NewClient(os.Getenv("BIOMETRY_API_KEY"))
ctx := context.Background()
sessionID, err := client.Sessions.Start(ctx) if err != nil { log.Fatal(err) } fmt.Println("Session:", sessionID)}Client options
| Option | Description |
|---|---|
WithBaseURL(url) | Override the default API base URL |
WithHTTPClient(hc) | Use a custom *http.Client for timeouts or transport |
WithUserAgent(ua) | Override the default User-Agent |
Per-request options (request-metadata headers)
| Option | Description |
|---|---|
WithDeviceInfo(json) | Set X-Device-Info — JSON-encoded device metadata |
WithGeoLocation(json) | Set X-Geo-Location — JSON-encoded geo data (overrides IP lookup) |
WithRequestTags(tags) | Set X-Request-Tags — comma-separated labels |
WithClientApp(app) | Set X-Client-App — calling application name |
WithClientVersion(ver) | Set X-Client-Version — client version string |
Full Verification Flow
A typical biometric onboarding session involves: starting a session, verifying a document, enrolling the face, processing a live video, matching the document photo against the video, and ending the session.
ctx := context.Background()
// 1. Start sessionsessionID, err := client.Sessions.Start(ctx)if err != nil { log.Fatal(err)}
userID := "user-123"
// 2. Approve consenterr = client.Consents.Approve(ctx, "consent-id", userID)
// 3. Document authenticationdocFile, _ := os.Open("passport.jpg")defer docFile.Close()
docResp, err := client.DocAuth.Check(ctx, biometry.DocAuthInput{ Document: docFile, FileName: "passport.jpg", SessionID: sessionID, Provider: "inhouse",})if err != nil { log.Fatal(err)}
var docInfo biometry.DocAuthInfoif err := docResp.Decode(&docInfo); err != nil { log.Fatal(err)}fmt.Printf("Name: %s %s, Country: %s\n", docInfo.FirstName, docInfo.LastName, docInfo.CountryCode)
// 4. Enroll face from documentdocPhoto, _ := os.Open("passport.jpg")defer docPhoto.Close()
_, err = client.Enrollment.Face(ctx, biometry.EnrollFaceInput{ UserID: userID, Face: docPhoto, FileName: "passport.jpg", IsDocument: true,})
// 5. Liveness on the live videovideoFile, _ := os.Open("selfie.mp4")defer videoFile.Close()
livenessResp, err := client.Verification.Liveness(ctx, biometry.LivenessInput{ UserID: userID, Video: videoFile, FileName: "selfie.mp4", Phrase: "one two three four five", SessionID: sessionID,})if err != nil { log.Fatal(err)}if livenessResp.Decision != nil { fmt.Printf("Decision: %s\n", livenessResp.Decision.Status)}
// 6. Face match — document vs video (reuses the session video from step 5)matchPhoto, _ := os.Open("passport.jpg")defer matchPhoto.Close()
matchResp, err := client.FaceMatch.Match(ctx, biometry.FaceMatchInput{ UserID: userID, ReferenceImage: matchPhoto, ReferenceName: "passport.jpg", UseSessionVideo: true, SessionID: sessionID,})if matchResp.Decision != nil { fmt.Printf("Match decision: %s\n", matchResp.Decision.Status)}
// 7. End sessionif err := client.Sessions.End(ctx, sessionID, nil); err != nil { log.Printf("Failed to end session: %v", err)}Services Reference
Sessions
// Start a new sessionsessionID, err := client.Sessions.Start(ctx)
// End a session (optional phone number for telco fraud check)err := client.Sessions.End(ctx, sessionID, &biometry.EndSessionRequest{ PhoneNumber: "+61400000000",})Verification (Liveness / Face / Voice)
The v1 Video.Process call is split into Verification.Liveness, Verification.FaceVerify, and Verification.VoiceVerify.
// Liveness (face liveness, active speaker, visual speech)resp, err := client.Verification.Liveness(ctx, biometry.LivenessInput{ UserID: "user-123", Video: videoReader, // io.Reader FileName: "video.mp4", Phrase: "one two three four five", Vocabulary: "", // optional Trigger: "", // optional SessionID: sessionID, // optional})// resp.Decision (Status/Score/Reasons) available when a scoring system applies// resp.Decode(&yourStruct) to parse the data field
// Verify against an enrolled templateresp, err = client.Verification.FaceVerify(ctx, biometry.VerifyInput{ UserID: "user-123", Media: videoReader, FileName: "video.mp4", Phrase: "one two three four five", SessionID: sessionID,})// client.Verification.VoiceVerify(ctx, biometry.VerifyInput{...}) likewiseEnrollment
// Face enrollmentresp, err := client.Enrollment.Face(ctx, biometry.EnrollFaceInput{ UserID: "user-123", Face: faceReader, FileName: "photo.jpg", IsDocument: false,})
// Voice enrollment (single file + phrase)resp, err := client.Enrollment.Voice(ctx, biometry.EnrollVoiceInput{ UserID: "user-123", Voice: voiceReader, FileName: "voice.wav", Phrase: "one two three four five",})Face Match
// Standard — upload reference image and live videoresp, err := client.FaceMatch.Match(ctx, biometry.FaceMatchInput{ UserID: "user-123", ReferenceImage: imageReader, ReferenceName: "photo.jpg", Video: videoReader, VideoName: "video.mp4",})
// Reuse the video captured earlier in the sessionresp, err = client.FaceMatch.Match(ctx, biometry.FaceMatchInput{ UserID: "user-123", ReferenceImage: imageReader, ReferenceName: "photo.jpg", UseSessionVideo: true, SessionID: sessionID,})Document Authentication
resp, err := client.DocAuth.Check(ctx, biometry.DocAuthInput{ Document: docReader, FileName: "passport.jpg", SessionID: sessionID, Provider: "inhouse", // or "idscan"})
var info biometry.DocAuthInforesp.Decode(&info)// info.FirstName, info.LastName, info.DocumentCategory, info.CountryCode, etc.Transactions
// List with filterstxns, err := client.Transactions.List(ctx, biometry.TransactionListRequest{ Page: 1, PageSize: 20, Decision: "approved",})
// Countcount, err := client.Transactions.Count(ctx, biometry.TransactionListRequest{ FromDate: "2025-01-01", ToDate: "2025-12-31",})
// Get by sessiontxns, err := client.Transactions.GetBySession(ctx, sessionID)
// Update tagserr := client.Transactions.UpdateTags(ctx, txnID, []string{"vip", "verified"})
// Flag as fraudulenterr := client.Transactions.Flag(ctx, txnID, "fraudulent")API Keys
// Get current key infoinfo, err := client.APIKeys.Info(ctx)
// Mint a new keynewKey, err := client.APIKeys.Mint(ctx)
// Revoke a keyerr := client.APIKeys.Revoke(ctx, "key-id-to-revoke")Consents
// Approve a consent for a usererr := client.Consents.Approve(ctx, "consent-id", "user-123")
// List a user's consent approvalsapprovals, err := client.Consents.MyApprovals(ctx, "user-123")Deepfake / Anti-Video Forgery
// Submit a video for deepfake analysischeck, err := client.Deepfake.Submit(ctx, biometry.DeepfakeInput{ UserID: "user-123", Video: videoReader, FileName: "video.mp4",})
// Poll the check statusstatus, err := client.Deepfake.Status(ctx, check.ID)// status.Status: pending | processing | completed | failedError Handling
All methods return *biometry.APIError for HTTP 4xx/5xx responses:
resp, err := client.Video.Process(ctx, input)if err != nil { var apiErr *biometry.APIError if errors.As(err, &apiErr) { fmt.Printf("HTTP %d: %s\n", apiErr.StatusCode, apiErr.Message) }}
// Convenience predicatesif biometry.IsNotFound(err) { ... }if biometry.IsForbidden(err) { ... }if biometry.IsUnauthorized(err) { ... }Response Envelope
Verification, face-match, doc-auth, and enrollment endpoints return a *biometry.Response — the API v2 success envelope:
type Response struct { Data json.RawMessage // the main result Decision *Decision // scoring decision (nil when no scoring system applies) Meta Meta // { RequestID, Message } Header http.Header // raw HTTP response headers}
type Decision struct { Status string // "pass" | "fail" | "refer" Score *float64 Reasons []string}
// Decode the Data field into a typed struct:var result MyStructresp.Decode(&result)Response Headers
The *Response exposes the request ID (from the envelope meta, falling back to the header) and the raw Header field:
resp, err := client.Verification.Liveness(ctx, input)
fmt.Println("Request ID:", resp.RequestID()) // meta.request_id / X-Request-Id
// Raw header access for any other headerfmt.Println(resp.Header.Get("X-Custom-Header"))| Accessor | Source | Description |
|---|---|---|
resp.RequestID() | meta.request_id / X-Request-Id | Unique request ID for tracking and support |
resp.Meta.Message | meta.message | Human-readable status message |
resp.Decision | decision | Scoring decision (Status/Score/Reasons), when a scoring system applies |
DocAuth with MRZ validation
Select the MRZ extraction provider via MRZProvider on the input:
resp, err := client.DocAuth.Check(ctx, biometry.DocAuthInput{ Document: docFile, FileName: "passport.jpg", SessionID: sessionID, Provider: "inhouse", MRZProvider: "inhouse",})
var info biometry.DocAuthInforesp.Decode(&info)fmt.Println("Request ID:", resp.RequestID())