Go SDK
The Propper Click Go SDK wraps the public Click REST API with typed structs, idiomatic error handling, and a Stripe-compatible webhook signature verifier.
Install
go get github.com/mypropper/click-sdk-go
Requires Go 1.21+. Uses only the standard library — no external dependencies.
Quick start
package main
import (
"context"
"log"
"os"
click "github.com/mypropper/click-sdk-go"
)
func main() {
c, err := click.NewClient(click.Config{
APIKey: os.Getenv("PROPPER_API_KEY"),
})
if err != nil {
log.Fatal(err)
}
receipt, err := c.Acceptances.Create(context.Background(), click.AcceptConsentInput{
TemplateVersionID: "tv_...",
DeploymentID: "dep_...",
Checksum: "sha256-hex...",
ConsentMethod: click.ConsentBUTTON,
Email: "user@example.com",
}, click.CreateOptions{})
if err != nil {
log.Fatal(err)
}
log.Printf("Receipt: %s", receipt.ReceiptID)
}
Authentication
// API key (default when APIKey is set)
click.NewClient(click.Config{APIKey: "sk_live_..."})
// OAuth bearer
click.NewClient(click.Config{
AuthType: click.AuthBearer,
BearerToken: "eyJ...",
})
Resources
| Service | Methods |
|---|---|
Acceptances | Create(ctx, input, opts) |
Templates | List, Get, Create, Update, Delete |
Deployments | List, Get, Create |
Render | ByDeployment(ctx, id, opts), ByRoute(ctx, input) |
Verification | VerifyReceipt(ctx, input) |
Idempotency
c.Acceptances.Create(ctx, input, click.CreateOptions{IdempotencyKey: requestID})
The SDK auto-generates a UUID v4 when IdempotencyKey is empty.
Webhook verification
package main
import (
"errors"
"io"
"net/http"
click "github.com/mypropper/click-sdk-go"
)
func webhookHandler(secret string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
body, _ := io.ReadAll(r.Body)
defer r.Body.Close()
if err := click.VerifyWebhookSignature(click.VerifyWebhookOptions{
Body: body,
SignatureHeader: r.Header.Get("X-Propper-Signature"),
Secrets: []string{secret},
}); err != nil {
var verr *click.WebhookVerificationError
if errors.As(err, &verr) {
http.Error(w, "invalid signature", http.StatusBadRequest)
return
}
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// ... parse body and handle event
w.WriteHeader(http.StatusOK)
}
}
Read body bytes before parsing JSON — the signature is computed over the exact bytes the sender wrote.
Error handling
import "errors"
receipt, err := c.Acceptances.Create(ctx, input, click.CreateOptions{})
var authErr *click.AuthError
var rateLimitErr *click.RateLimitError
switch {
case errors.As(err, &authErr):
// rotate your API key
case errors.As(err, &rateLimitErr):
// back off rateLimitErr.RetryAfterSeconds
default:
log.Print(err)
}
Configuration reference
click.Config{
APIKey: "sk_live_...", // or BearerToken with AuthType: click.AuthBearer
Environment: click.EnvProduction,
BaseURL: "https://api.propper.ai/v1/click",
MaxRetries: 3,
Timeout: 30 * time.Second,
HTTPClient: &http.Client{}, // bring your own transport if needed
}