Go
Basic Example
Section titled “Basic Example”No external dependencies required for the standard library example.
package main
import ( "bytes" "encoding/json" "fmt" "log" "net/http" "os" "time")
type VerifyRequest struct { APIKey string `json:"apiKey"` FormID string `json:"formId"` Payload map[string]interface{} `json:"payload"`}
type VerifyResponse struct { Status string `json:"status"` Confidence float64 `json:"confidence"` Reasoning string `json:"reasoning"` SubmissionID string `json:"submissionId"` ProcessingTime int `json:"processingTime"` FormID string `json:"formId"`}
func verifySubmission(payload map[string]interface{}) (*VerifyResponse, error) { reqBody := VerifyRequest{ APIKey: os.Getenv("FORMSENTRY_API_KEY"), FormID: os.Getenv("FORMSENTRY_FORM_ID"), Payload: payload, }
jsonData, err := json.Marshal(reqBody) if err != nil { return nil, err }
client := &http.Client{Timeout: 5 * time.Second} resp, err := client.Post( "https://api.formsentry.ai/v1/verify", "application/json", bytes.NewBuffer(jsonData), ) if err != nil { return nil, err } defer resp.Body.Close()
var result VerifyResponse if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, err }
return &result, nil}
func main() { result, err := verifySubmission(map[string]interface{}{ "name": "John Doe", "email": "john@example.com", "message": "I would like to learn more about your services.", }) if err != nil { log.Fatal("Error:", err) }
if result.Status == "spam" { fmt.Println("Spam detected:", result.Reasoning) } else { fmt.Println("Legitimate submission") }}net/http Handler
Section titled “net/http Handler”This extends the basic example. Add contactHandler and replace main with the server version:
func contactHandler(w http.ResponseWriter, r *http.Request) { var formData map[string]interface{} if err := json.NewDecoder(r.Body).Decode(&formData); err != nil { http.Error(w, "Invalid request", http.StatusBadRequest) return }
w.Header().Set("Content-Type", "application/json")
result, err := verifySubmission(formData) if err != nil { // Fail open — if FormSentry is unreachable, allow the submission log.Printf("FormSentry error: %v", err) result = &VerifyResponse{Status: "legitimate", Confidence: 0.0} }
if result.Status == "spam" { // Silently accept to avoid tipping off spammers json.NewEncoder(w).Encode(map[string]bool{"success": true}) return }
// TODO: Process the legitimate submission json.NewEncoder(w).Encode(map[string]bool{"success": true})}
func main() { http.HandleFunc("/contact", contactHandler) log.Println("Listening on :3000") log.Fatal(http.ListenAndServe(":3000", nil))}Gin Integration
Section titled “Gin Integration”Install Gin first:
go get github.com/gin-gonic/ginThis is a complete, standalone file:
package main
import ( "bytes" "encoding/json" "log" "net/http" "os" "time"
"github.com/gin-gonic/gin")
type VerifyRequest struct { APIKey string `json:"apiKey"` FormID string `json:"formId"` Payload map[string]interface{} `json:"payload"`}
type VerifyResponse struct { Status string `json:"status"` Confidence float64 `json:"confidence"` Reasoning string `json:"reasoning"` SubmissionID string `json:"submissionId"` ProcessingTime int `json:"processingTime"` FormID string `json:"formId"`}
func verifySubmission(payload map[string]interface{}) (*VerifyResponse, error) { reqBody := VerifyRequest{ APIKey: os.Getenv("FORMSENTRY_API_KEY"), FormID: os.Getenv("FORMSENTRY_FORM_ID"), Payload: payload, }
jsonData, err := json.Marshal(reqBody) if err != nil { return nil, err }
client := &http.Client{Timeout: 5 * time.Second} resp, err := client.Post( "https://api.formsentry.ai/v1/verify", "application/json", bytes.NewBuffer(jsonData), ) if err != nil { return nil, err } defer resp.Body.Close()
var result VerifyResponse if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, err }
return &result, nil}
func main() { r := gin.Default()
r.POST("/contact", func(c *gin.Context) { var formData map[string]interface{} if err := c.ShouldBindJSON(&formData); err != nil { c.JSON(400, gin.H{"error": "Invalid request"}) return }
result, err := verifySubmission(formData) if err != nil { // Fail open — if FormSentry is unreachable, allow the submission log.Printf("FormSentry error: %v", err) result = &VerifyResponse{Status: "legitimate", Confidence: 0.0} }
if result.Status == "spam" { c.JSON(200, gin.H{"success": true}) return }
// TODO: Process the legitimate submission c.JSON(200, gin.H{"success": true}) })
r.Run(":3000")}Error Handling
Section titled “Error Handling”Add this to your main package alongside verifySubmission from the basic example:
import ( "fmt" "time")
func verifyWithRetry(payload map[string]interface{}, maxRetries int) (*VerifyResponse, error) { var lastErr error for attempt := 1; attempt <= maxRetries; attempt++ { result, err := verifySubmission(payload) if err == nil { return result, nil } lastErr = err
if attempt < maxRetries { delay := time.Duration(1<<uint(attempt-1)) * time.Second if delay > 5*time.Second { delay = 5 * time.Second } time.Sleep(delay) } } return nil, fmt.Errorf("max retries exceeded: %w", lastErr)}See Errors for all error codes and retry strategies.