AbuseGraph + Go
Go net/http client POSTs to /api/v1/check with sk_ and x-abusegraph-site on register and login.
Quick path
- Set
ABUSEGRAPH_SECRET_KEYandABUSEGRAPH_SITEin env. - POST JSON to
https://abusegraph.com/api/v1/checkbefore creating a session. - Map
verdictto 403 (block) or step-up (challenge).
Keys
| Key | Env | Use |
|---|---|---|
| Secret | ABUSEGRAPH_SECRET_KEY (sk_test_… / sk_live_…) | Server /api/v1/check |
| Publishable | NEXT_PUBLIC_ABUSEGRAPH_PUBLISHABLE_KEY (pk_test_…) | Browser SDK |
| Site | ABUSEGRAPH_SITE | DNS-verified domain |
Free includes 1,000 live API checks / month after DNS verify. Test keys never bill.
Env
ABUSEGRAPH_SITE=yourdomain.com
ABUSEGRAPH_CHECK_URL=https://abusegraph.com/api/v1/check
ABUSEGRAPH_SECRET_KEY=sk_test_…Use sk_live_… in production after DNS verify.
Server check
Go uses direct HTTP POST to https://abusegraph.com/api/v1/check. Events: signup | login | password_reset | email_change. Optional sessionId.
package abusegraph
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
)
type CheckRequest struct {
Email string `json:"email,omitempty"`
UserID string `json:"userId,omitempty"`
Event string `json:"event,omitempty"`
SessionID string `json:"sessionId,omitempty"`
Site string `json:"site"`
}
type CheckResponse struct {
Verdict string `json:"verdict"`
Score float64 `json:"score"`
Summary string `json:"summary,omitempty"`
}
func Check(email, event string, extra map[string]any) (*CheckResponse, error) {
site := os.Getenv("ABUSEGRAPH_SITE")
checkURL := os.Getenv("ABUSEGRAPH_CHECK_URL")
if checkURL == "" {
checkURL = "https://abusegraph.com/api/v1/check"
}
body := map[string]any{
"email": email,
"event": event,
"site": site,
}
for k, v := range extra {
body[k] = v
}
raw, _ := json.Marshal(body)
req, err := http.NewRequest("POST", checkURL, bytes.NewReader(raw))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("x-api-key", os.Getenv("ABUSEGRAPH_SECRET_KEY")) // sk_test_…
req.Header.Set("x-abusegraph-site", site)
res, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode == 402 {
return nil, fmt.Errorf("credits_exhausted")
}
if res.StatusCode >= 400 {
return nil, fmt.Errorf("check failed: %d", res.StatusCode)
}
var out CheckResponse
return &out, json.NewDecoder(res.Body).Decode(&out)
}Register handler:
result, err := abusegraph.Check(email, "signup", nil)
if err != nil { /* fail open or 503 */ }
if result.Verdict == "block" {
http.Error(w, "signup blocked", http.StatusForbidden)
return
}
// create user + sessionBrowser signals (recommended)
If you serve a web UI, forward toCheckBody fields from @abusegraph/sdk in the request body — NEVER use browser-only checks as the authoritative decision.
Lifecycle events
- login —
Check(email, "login", nil)before session issue. - password_reset —
event: "password_reset"on reset request. - email_change —
event: "email_change"after email update.
Platform
Lists, rules, and linked accounts apply on every check — configure in the console. Optional session: POST /api/v1/session. Native apps: iOS, Android, React Native.
Verify
Register a test user with sk_test_…, confirm Activity shows the check, and blocked emails get 403.