go get github.com/MichaelOgunjimi/notification-system/sdks/goGo SDK
The official Go SDK publishes and queries Beaco events using only the standard library. It supports Go 1.22 and newer.
The SDK uses a secret project API key. Use it only from trusted server code and keep
BEACO_API_KEYout of source control.
Installation
go get github.com/MichaelOgunjimi/notification-system/sdks/goPublish an Event
package main
import (
"context"
"os"
beaco "github.com/MichaelOgunjimi/notification-system/sdks/go"
)
func main() {
client, err := beaco.New(os.Getenv("BEACO_API_KEY"), nil)
if err != nil {
panic(err)
}
_, err = client.Events.Publish(context.Background(), beaco.PublishEventInput{
EventType: "user.welcome",
Recipients: []beaco.Recipient{{
Channels: []string{"email"},
Email: "[email protected]",
}},
Payload: map[string]any{"name": "Alice"},
})
if err != nil {
panic(err)
}
}Query Events
page, err := client.Events.List(ctx, beaco.EventListOptions{Status: "completed", Page: 1})
event, err := client.Events.Retrieve(ctx, "evt_123")Publish a batch atomically with client.Events.PublishBatch(ctx, events).
Available Resources
Events
client.Events.Publish(ctx, input)
client.Events.PublishBatch(ctx, events)
client.Events.Retrieve(ctx, eventID)
client.Events.List(ctx, beaco.EventListOptions{Status: "completed", Page: 1})Scopes: events:write for publishing and events:read for retrieving and listing.
Templates
template, err := client.Templates.Create(ctx, beaco.CreateTemplateInput{
Name: "order-shipped",
Channel: "email",
Subject: "Your order has shipped",
Body: "Hi {{ name }}, order {{ order_id }} is on its way.",
Variables: []string{"name", "order_id"},
})
template, err = client.Templates.UpsertByName(ctx, "order-shipped", "email", beaco.UpsertTemplateInput{
Body: "<p>Hi {{ name }}</p>",
TextBody: "Hi {{ name }}",
})
imported, err := client.Templates.ImportHTML(ctx, beaco.ImportTemplateInput{
Name: "welcome", HTML: "<h1>Hi Alice</h1>", Variables: map[string]string{"name": "Alice"},
})
client.Templates.Retrieve(ctx, template.ID)
client.Templates.List(ctx, beaco.TemplateListOptions{Channel: "email"})
client.Templates.Update(ctx, template.ID, beaco.UpdateTemplateInput{Body: "Updated"})
client.Templates.Preview(ctx, template.ID, map[string]any{"name": "Alice"})
client.Templates.Delete(ctx, template.ID)Immediate events require exactly one of TemplateID, TemplateName, or Inline.
Choose the sender with FromLocal (the part before the @), FromName, and ReplyTo on
InlineEmail and on the template inputs. The domain always stays the server's verified domain;
ReplyTo can be any valid address. In UpdateTemplateInput these are *string: a pointer to an
empty string clears the field.
_, err := client.Events.Publish(ctx, beaco.PublishEventInput{
EventType: "order.confirmed",
Recipients: []beaco.Recipient{{Channels: []string{"email"}, Email: "[email protected]"}},
Inline: &beaco.InlineEmail{
Subject: "Order BEA-1042 confirmed",
HTML: "<h1>Thanks for your order</h1>",
FromLocal: "orders",
FromName: "Winwell Orders",
ReplyTo: "[email protected]",
},
})Attach files with Attachments []beaco.Attachment (Filename, URL, SizeBytes) on
PublishEventInput: up to 10, 30 MB declared in total. Beaco never stores them: the email provider
downloads each URL when sending, so it must stay reachable until delivery succeeds, including
retries. Invalid attachments return an error before any request is made.
_, err := client.Events.Publish(ctx, beaco.PublishEventInput{
EventType: "order.confirmed",
Recipients: []beaco.Recipient{{Channels: []string{"email"}, Email: "[email protected]"}},
Inline: &beaco.InlineEmail{Subject: "Your invoice", HTML: "<p>Attached.</p>"},
Attachments: []beaco.Attachment{
{Filename: "invoice.pdf", URL: "https://files.example.com/a.pdf", SizeBytes: 48213},
},
})Scopes: templates:write for mutations and templates:read for retrieval, listing, and previews.
Notifications
notification, err := client.Notifications.Retrieve(ctx, "ntf_123")
page, err := client.Notifications.List(ctx, beaco.NotificationListOptions{
Status: "failed",
Channel: "email",
})Scope: notifications:read.
Scheduled Events
scheduled, err := client.ScheduledEvents.Create(ctx, beaco.CreateScheduledEventInput{
EventType: "renewal.reminder",
ScheduledFor: time.Date(2026, 10, 2, 9, 0, 0, 0, time.UTC),
Recipients: []beaco.Recipient{{
Channels: []string{"email"},
Email: "[email protected]",
}},
TemplateName: "renewal-reminder", // or TemplateID / Inline, same as Publish
Payload: map[string]any{"renewal_date": "2026-10-03"},
})
client.ScheduledEvents.List(ctx, beaco.ScheduledEventListOptions{Status: "pending"})
client.ScheduledEvents.Cancel(ctx, scheduled.ID)Scheduled events accept the same content fields as Publish (exactly one of TemplateID,
TemplateName or Inline, plus optional Attachments; no IdempotencyKey). Once the time arrives
the event is dispatched and its EventID is set; an event more than an hour overdue is expired
instead of sent. Cancelling is only possible while Status is pending.
Scopes: scheduled_events:write for creation and cancellation, and scheduled_events:read for listing.
Suppressions
suppression, err := client.Suppressions.Create(ctx, beaco.CreateSuppressionInput{
Channel: "email",
Recipient: "[email protected]",
Reason: "manual",
})
client.Suppressions.List(ctx, beaco.SuppressionListOptions{Channel: "email"})
client.Suppressions.Delete(ctx, suppression.ID)Scopes: suppressions:write for creation and deletion, and suppressions:read for listing.
Local Development
client, err := beaco.New(os.Getenv("BEACO_API_KEY"), &beaco.Options{
BaseURL: "http://localhost:8000/api/v1",
})Remote base URLs must use HTTPS unless AllowInsecureHTTP is explicitly enabled.
Errors
Failed requests return *beaco.Error, including stable Code, Status, Details, and Retryable fields.
List methods return Page[T] with Items, Total, Page, PerPage, and TotalPages fields.

