The official Go SDK (github.com/playcamp/playcamp-go-sdk) provides a type-safe way to integrate with the PlayCamp API. It handles authentication, pagination, retries, and error handling with zero external dependencies.
Installation
go get github.com/playcamp/playcamp-go-sdk
Requirements: Go >= 1.21
Quick Start
import playcamp "github.com/playcamp/playcamp-go-sdk"
server, err := playcamp.NewServer("your_server_key:your_secret",
playcamp.WithEnvironment(playcamp.EnvironmentSandbox),
)
if err != nil {
log.Fatal(err)
}
// Create a sponsor
sponsor, err := server.Sponsors.Create(ctx, playcamp.CreateSponsorParams{
UserID: "user_12345",
CreatorKey: "ABC12",
})
// Register a payment
payment, err := server.Payments.Create(ctx, playcamp.CreatePaymentParams{
UserID: "user_12345",
TransactionID: "txn_abc123",
ProductID: "gem_pack_100",
Amount: 9900,
Currency: "KRW",
Platform: playcamp.PaymentPlatformAndroid,
DistributionType: playcamp.String("MOBILE_STORE"),
PurchasedAt: time.Now(),
})
Client vs Server
The SDK provides two constructors depending on your API key type:
| Constructor | API Key | Access | Use Case |
|---|
NewClient | Client Key | Read-only | Game client, public queries |
NewServer | Server Key | Read/Write | Game server, all operations |
import playcamp "github.com/playcamp/playcamp-go-sdk"
// Read-only access (Client Key)
client, err := playcamp.NewClient("your_client_key:your_secret")
// Full access (Server Key)
server, err := playcamp.NewServer("your_server_key:your_secret")
Never use NewServer or expose your Server Key on the client side.
Client Resources
| Resource | Methods |
|---|
Campaigns | List(), ListAll(), Get(), GetCreators(), GetPackages() |
Creators | Get(), Search() |
Coupons | Validate() |
Sponsors | Get() |
Server Resources
| Resource | Methods |
|---|
Campaigns | List(), ListAll(), Get(), GetCreators() |
Creators | Get(), Search(), GetCoupons() |
Coupons | Validate(), Redeem(), GetUserHistory(), ListAllUserHistory() |
Sponsors | Create(), GetByUser(), Update(), Delete(), GetHistory(), ListAllHistory() |
Payments | Create(), Get(), ListByUser(), ListAllByUser(), Refund() |
Webhooks | List(), Create(), Update(), Delete(), GetLogs(), Test() |
Configuration
server, err := playcamp.NewServer("key:secret",
playcamp.WithEnvironment(playcamp.EnvironmentSandbox), // default: EnvironmentLive
playcamp.WithTimeout(30 * time.Second), // default: 30s
playcamp.WithTestMode(true), // default: false
playcamp.WithMaxRetries(3), // default: 3
playcamp.WithDebug(playcamp.DebugOptions{ // default: disabled
Enabled: true,
LogRequestBody: true,
LogResponseBody: true,
}),
)
Environments
| Environment | URL | Purpose |
|---|
EnvironmentSandbox | https://sandbox-sdk-api.playcamp.io | Development/Testing |
EnvironmentLive | https://sdk-api.playcamp.io | Production (default) |
You can also specify a custom URL directly:
server, err := playcamp.NewServer("key:secret",
playcamp.WithBaseURL("http://localhost:3003"), // Overrides environment setting
)
Pointer Helpers
Use built-in helpers for optional fields:
playcamp.String("value") // *string
playcamp.Int(10) // *int
playcamp.Bool(true) // *bool
playcamp.Float64(99.99) // *float64
List endpoints return paginated results:
// Get a single page
result, err := server.Campaigns.List(ctx, &playcamp.PaginationOptions{
Page: playcamp.Int(1),
Limit: playcamp.Int(20),
})
// result.Data, result.Pagination, result.HasNextPage
Use the iterator to automatically page through all results:
iterator := server.Campaigns.ListAll(&playcamp.PaginationOptions{
Limit: playcamp.Int(50),
})
for iterator.Next(ctx) {
campaign := iterator.Item()
fmt.Println(campaign.CampaignID)
iterator.Advance()
}
if err := iterator.Err(); err != nil {
log.Fatal(err)
}
Error Handling
The SDK returns typed errors for different scenarios:
import "errors"
campaign, err := server.Campaigns.Get(ctx, "invalid_id")
if err != nil {
var notFoundErr *playcamp.NotFoundError
var authErr *playcamp.AuthError
var rateLimitErr *playcamp.RateLimitError
var networkErr *playcamp.NetworkError
var apiErr *playcamp.APIError
switch {
case errors.As(err, ¬FoundErr):
fmt.Println("Campaign not found")
case errors.As(err, &authErr):
fmt.Println("Invalid API key")
case errors.As(err, &rateLimitErr):
fmt.Println("Rate limited:", rateLimitErr.Message)
case errors.As(err, &networkErr):
fmt.Println("Network error:", networkErr.Message)
case errors.As(err, &apiErr):
fmt.Printf("API error [%d]: %s\n", apiErr.StatusCode, apiErr.Message)
default:
fmt.Println("Unexpected error:", err)
}
}
| Error Type | HTTP Status | Description |
|---|
BadRequestError | 400 | Malformed request |
AuthError | 401 | Authentication failed |
ForbiddenError | 403 | Insufficient permissions |
NotFoundError | 404 | Resource not found |
ConflictError | 409 | Resource conflict (duplicate) |
ValidationError | 422 | Server-side validation failed |
RateLimitError | 429 | Rate limit exceeded |
NetworkError | — | Network/timeout error |
InputValidationError | — | Client-side parameter validation |
Webhook Verification
The SDK provides the webhookutil package for verifying incoming webhook signatures:
import "github.com/playcamp/playcamp-go-sdk/webhookutil"
func handleWebhook(w http.ResponseWriter, r *http.Request) {
body, _ := io.ReadAll(r.Body)
result := webhookutil.Verify(webhookutil.VerifyOptions{
Payload: body,
Signature: r.Header.Get("X-Webhook-Signature"),
Secret: "your_webhook_secret",
Tolerance: 300, // Max age in seconds (default: 300)
})
if !result.Valid {
http.Error(w, result.Error, http.StatusUnauthorized)
return
}
for _, event := range result.Payload.Events {
switch event.Event {
case playcamp.WebhookEventCouponRedeemed:
var data playcamp.CouponRedeemedData
json.Unmarshal(event.Data, &data)
fmt.Printf("Coupon redeemed: %s\n", data.CouponCode)
case playcamp.WebhookEventPaymentCreated:
var data playcamp.PaymentCreatedData
json.Unmarshal(event.Data, &data)
fmt.Printf("Payment created: %s\n", data.TransactionID)
case playcamp.WebhookEventSponsorCreated:
var data playcamp.SponsorCreatedData
json.Unmarshal(event.Data, &data)
fmt.Printf("Sponsor created: %s\n", data.UserID)
}
}
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]bool{"received": true})
}
For testing, you can generate signatures locally:
import "github.com/playcamp/playcamp-go-sdk/webhookutil"
payload := []byte(`{"events":[{"event":"coupon.redeemed","timestamp":"2024-01-15T10:30:00Z","data":{"couponCode":"TEST","userId":"user_123","usageId":1,"reward":[]}}]}`)
signature := webhookutil.ConstructSignature(payload, "your_webhook_secret", nil)
See the Webhook Events page for more details on webhook event types and payloads.
Example Project
For a complete working example with all API endpoints, see the playcamp-go-sdk-example repository.