Reads OMNISOCIALS_API_KEY if no option is passed. A missing key returns
*omnisocials.AuthenticationError.
Create a post
Code
res, err := client.Posts.Create(ctx, &omnisocials.PostCreateParams{ Content: "New drop this Friday", Channels: []string{"instagram", "facebook", "linkedin"}, ScheduledAt: "2026-08-01T09:00:00Z", MediaURLs: []string{"https://example.com/teaser.jpg"},})fmt.Println(res.Data.ID, res.Data.Status)
MediaURLs / MediaIDs entries can also carry per-media alt text (max 1500
chars) via MediaURLEntry / MediaIDEntry, delivered to Mastodon, Bluesky,
X (photos/GIFs), and Pinterest:
Code
MediaURLs: []omnisocials.MediaURLEntry{ {URL: "https://example.com/teaser.jpg", Alt: "Red sneaker on a white background"},},
Publish immediately:
Code
res, err := client.Posts.CreateAndPublish(ctx, &omnisocials.PostCreateParams{ Content: "Going live right now", Channels: []string{"x", "bluesky"},})
// One post's latest per-platform metricsstats, err := client.Analytics.Post(ctx, "post_id")fmt.Println(stats.Data.Platforms["instagram"].Metrics)// Batch: up to 100 posts in one callbatch, err := client.Analytics.Posts(ctx, []string{"id1", "id2", "id3"})// Workspace-wide overviewoverview, err := client.Analytics.Overview(ctx, &omnisocials.AnalyticsOverviewParams{Period: "30d"})fmt.Println(overview.Data.TotalImpressions, overview.Data.TotalEngagement)// Account-level stats (followers etc)accountStats, err := client.Analytics.Accounts(ctx, &omnisocials.AccountAnalyticsParams{Platform: "instagram"})
Verify webhooks
Code
package mainimport ( "errors" "io" "log" "net/http" "os" "time" omnisocials "github.com/OmniSocials/omnisocials-go")func main() { secret := os.Getenv("OMNISOCIALS_WEBHOOK_SECRET") http.HandleFunc("/omnisocials/webhook", func(w http.ResponseWriter, r *http.Request) { payload, err := io.ReadAll(r.Body) // keep the raw body! if err != nil { http.Error(w, "failed to read body", http.StatusBadRequest) return } event, err := omnisocials.VerifyWebhookSignature( payload, r.Header.Get("X-OmniSocials-Signature"), secret, 5*time.Minute, // tolerance; pass 0 for the default (5 minutes) ) if err != nil { var verr *omnisocials.WebhookVerificationError if errors.As(err, &verr) { http.Error(w, "invalid signature", http.StatusBadRequest) return } http.Error(w, "server error", http.StatusInternalServerError) return } data, _ := event["data"].(map[string]any) switch event["type"] { case "post.published": log.Println("Published:", data["post_id"], data["targets"]) case "post.failed": log.Println("Failed:", data["post_id"]) } w.WriteHeader(http.StatusOK) }) log.Fatal(http.ListenAndServe(":8080", nil))}
Errors
Typed errors matched with errors.As. The *APIError wrapper has Status,
Code, Message, and Body. Types: *ValidationError (400/422),
*AuthenticationError (401), *PermissionDeniedError (403), *NotFoundError
(404), *RateLimitError (429, RetryAfter is a time.Duration), *ServerError
(5xx), *ConnectionError, and *WebhookVerificationError.
Code
_, err := client.Posts.Create(ctx, &omnisocials.PostCreateParams{ Content: "Hi", Channels: []string{"instagram"},})if err != nil { var rateLimited *omnisocials.RateLimitError var validation *omnisocials.ValidationError var connection *omnisocials.ConnectionError var apiErr *omnisocials.APIError switch { case errors.As(err, &rateLimited): log.Printf("rate limited, retry in %s", rateLimited.RetryAfter) case errors.As(err, &validation): log.Printf("bad request (%s): %s", validation.Code, validation.Message) case errors.As(err, &connection): log.Printf("network problem: %v", connection) case errors.As(err, &apiErr): log.Printf("API error %d (%s): %s", apiErr.Status, apiErr.Code, apiErr.Message) default: log.Fatal(err) }}