Go uses the Raw HTTP path in Go. Complete every step with an isolated non-production workspace before deploying.
Prerequisites
Go 1.22+
A scoped non-production API key
Environment setup
MONETIZEKIT_BASE_URL=https://app.monetizekit.app/api/v1
MONETIZEKIT_API_KEY=${MONETIZEKIT_API_KEY}
MONETIZEKIT_PLAN_ID=${MONETIZEKIT_PLAN_ID}
MONETIZEKIT_FEATURE_KEY=${MONETIZEKIT_FEATURE_KEY}
MONETIZEKIT_DENIED_FEATURE_KEY=${MONETIZEKIT_DENIED_FEATURE_KEY}
MONETIZEKIT_METER_ID=${MONETIZEKIT_METER_ID}
MONETIZEKIT_RUN_ID=replace-with-a-unique-run-idInstall commands
cd examples/docs-quickstarts/go && go mod downloadHappy path
1. Create a customer
Create a unique test customer. Raw HTTP variants send a deterministic idempotency key; the current Node SDK does not expose one for customer creation.
func createCustomer(cfg config, idempotencyKey string) (customer, error) {
var result customer
err := requestJSON(
cfg,
http.MethodPost,
"/customers",
map[string]any{
"name": "Docs quickstart " + cfg.RunID,
"email": "docs-quickstart+" + cfg.RunID + "@example.com",
},
idempotencyKey,
http.StatusCreated,
&result,
)
return result, err
}Expected HTTP status: 201.
2. Select the isolated published plan
List published plans and select the exact MONETIZEKIT_PLAN_ID provisioned for this run.
func selectPlan(cfg config) (plan, error) {
var plans planList
if err := requestJSON(cfg, http.MethodGet, "/plans", nil, "", http.StatusOK, &plans); err != nil {
return plan{}, err
}
for _, candidate := range plans.Data {
if candidate.ID == cfg.PlanID {
return candidate, nil
}
}
return plan{}, fmt.Errorf("isolated plan %s is not published in this workspace", cfg.PlanID)
}Expected HTTP status: 200.
3. Attach the plan
Create the customer's subscription. Raw HTTP variants reuse a deterministic idempotency key.
func attachPlan(
cfg config,
customerID string,
planID string,
idempotencyKey string,
) (subscription, error) {
var result subscription
err := requestJSON(
cfg,
http.MethodPost,
"/subscriptions",
map[string]any{"customerId": customerID, "planId": planID, "status": "active"},
idempotencyKey,
http.StatusCreated,
&result,
)
return result, err
}Expected HTTP status: 201.
4. Check and enforce an entitlement
Request the feature decision and stop protected work unless `allowed` is true.
func requireEntitlement(cfg config, customerID string) (entitlementDecision, error) {
var decision entitlementDecision
path := fmt.Sprintf(
"/entitlements/%s/%s",
url.PathEscape(customerID),
url.PathEscape(cfg.FeatureKey),
)
if err := requestJSON(cfg, http.MethodGet, path, nil, "", http.StatusOK, &decision); err != nil {
return entitlementDecision{}, err
}
if !decision.Allowed {
return entitlementDecision{}, fmt.Errorf(
"entitlement denied (%s): %s",
decision.ReasonCode,
decision.Reason,
)
}
return decision, nil
}Expected HTTP status: 200.
5. Submit usage
Record one metered event with a deterministic idempotency key that remains stable across retries.
func submitUsage(cfg config, customerID string, idempotencyKey string) (map[string]any, error) {
result := map[string]any{}
err := requestJSON(
cfg,
http.MethodPost,
"/usage/events",
map[string]any{"customerId": customerID, "meterId": cfg.MeterID, "value": 1},
idempotencyKey,
http.StatusCreated,
&result,
)
return result, err
}Expected HTTP status: 201.
6. Verify the observed usage
Read the meter after submission and include the observed result in the smoke output.
func validateUsage(cfg config, customerID string) (map[string]any, error) {
result := map[string]any{}
path := fmt.Sprintf("/usage/%s/%s", url.PathEscape(customerID), url.PathEscape(cfg.MeterID))
err := requestJSON(cfg, http.MethodGet, path, nil, "", http.StatusOK, &result)
return result, err
}Expected HTTP status: 200.
Troubleshooting
401 missing_api_key / invalid_api_key
Confirm the API key is present, active, and uses the non-production prefix for the environment you intend to test.
403 missing scope
Issue a key with customers:create, plans:read, subscriptions:write, entitlements:read, usage:write, usage:read, and cleanup permissions.
Entitlement denied
Confirm MONETIZEKIT_PLAN_ID is the isolated plan that grants MONETIZEKIT_FEATURE_KEY and does not grant MONETIZEKIT_DENIED_FEATURE_KEY.
A retry records duplicate usage
Keep MONETIZEKIT_RUN_ID stable for retries of the same logical smoke run so the generated Idempotency-Key is reused.
Deploy + smoke test
Platform: Docker Compose.
Build the Go binary and inject the seven quickstart environment variables.
Run the service image before invoking the binary's smoke entry point.
(cd examples/docs-quickstarts/go && go run . --smoke)Expected: One JSON object with outcome "passed", allowed and denied entitlement decisions, and observed usage data, followed by successful subscription/customer cleanup.
CLI links
Use the CLI to authenticate and inspect the same workspace after the smoke test.
monetizekit customers listmonetizekit workspace list