Skip to content

Go

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")
}
}

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))
}

Install Gin first:

Terminal window
go get github.com/gin-gonic/gin

This 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")
}

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.