You already have a service that posts webhooks to your customers with net/http and a hand-built JSON body. This guide replaces one of those calls with a generated, typed sender: no rewrite, no big bang. Set aside about 15 minutes.
You start from something like this, scattered wherever an event happens:
// The ad-hoc send you have today.
body, _ := json.Marshal(map[string]any{
"type": "order.created",
"data": map[string]any{"id": order.ID, "currency": order.Currency},
})
http.Post(customer.WebhookURL, "application/json", bytes.NewReader(body))Go 1.25 or later is required.
Add the repost runtime module to your existing project. It carries no third-party dependencies.
go get github.com/repost-sh/repost-goThe module is imported under the alias repost in the examples that follow.
From the repository root:
repost schema init --language go --output ./internal/repostclientThis scaffolds a repost/ directory with a starter schema and a .env file for your key. The generated package is written into your repo and committed, like protoc or sqlc output.
Edit repost/schema.repost so the model and event match the payload your ad-hoc call sends today. For the order.created example above:
generator sdk {
language = "go"
output = "../internal/repostclient"
}
model Order {
id String
currency String
}
type Order {
created
}
event OrderCreated {
type @type(Order.created)
data Order
timestamp DateTime
}Add one field per key you send today. Schema covers enums, nested models, and more.
repost schema migrate dev --name initThis records your schema as a migration and writes the client package into internal/repostclient. Commit it. Code generation covers every file it emits and how regeneration works.
Create an environment in the dashboard, copy its publish API key into .env, then deploy your schema:
repost auth login
repost schema migrate deployReplace the ad-hoc call#
Swap the raw http.Post for the generated sender. Repost fans the event out to the customer's registered endpoints, so you no longer track WebhookURL yourself:
client, err := repostclient.NewClient(repost.ClientOptions{})
if err != nil {
log.Fatal(err)
}
result, err := client.Webhooks.Order.Created(context.Background(), repostclient.OrderCreatedInput{
CustomerID: "acme",
Data: repostclient.Order{ID: "order-1001", Currency: "EUR"},
IdempotencyKey: "order-1001:created",
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("sent %s as %s\n", result.ID, result.Type)NewClient only checks that the generated package and runtime are compatible; everything else is lazy. The API key resolves at send time from ClientOptions.APIKey, then REPOST_SEND_API_KEY, then REPOST_TOKEN. Leaving IdempotencyKey empty lets the runtime mint one per send.
Verify delivery#
Trigger the code path that fires the event, then open the dashboard. The send appears in the event stream with its msg_... id and per-endpoint delivery status. Once you trust it, delete the old http.Post call and repeat for the next event type.