The official .NET SDK. Targets .NET 8, depends only on System.Net.Http and
System.Text.Json, fully async with CancellationToken support on every method.
Install
Code
dotnet add package OmniSocials
Authentication
Code
var client = new OmniSocialsClient(new OmniSocialsOptions { ApiKey = "omsk_live_..." });
Reads OMNISOCIALS_API_KEY if omitted. A missing key throws
AuthenticationException. The client owns an internal HttpClient and implements
IDisposable: create one and reuse it.
Create a post
Code
var response = await client.Posts.CreateAsync(new PostCreateParams{ Content = "New drop this Friday", Channels = new[] { "instagram", "facebook", "linkedin" }, ScheduledAt = "2026-08-01T09:00:00Z", MediaUrls = new[] { "https://example.com/teaser.jpg" },});var post = response!.Value.GetProperty("data");Console.WriteLine($"{post.GetProperty("id")} {post.GetProperty("status")}");
MediaUrls / MediaIds entries can also be objects carrying per-media alt text
(new { url, alt } / new { id, alt }, max 1500 chars), delivered to Mastodon,
Bluesky, X (photos/GIFs), and Pinterest:
Code
MediaUrls = new object[] { new { url = "https://example.com/teaser.jpg", alt = "Red sneaker on a white background" } },
Publish immediately:
Code
await client.Posts.CreateAndPublishAsync(new PostCreateParams{ Content = "Going live right now", Channels = new[] { "x", "bluesky" },});
Upload media
Code
var upload = await client.Media.UploadFromUrlAsync(new MediaUploadFromUrlParams{ Url = "https://example.com/launch-video.mp4", Name = "launch-video-v2", Folder = "Campaigns",});Console.WriteLine(upload!.Value.GetProperty("data").GetProperty("id"));
Local files via factory methods:
Code
// From a pathawait client.Media.UploadAsync(MediaUploadParams.FromFile("./photos/product.jpg", name: "product-hero"));// Or from bytes / a streamvar bytes = await File.ReadAllBytesAsync("./photos/product.jpg");await client.Media.UploadAsync(MediaUploadParams.FromBytes(bytes, "product.jpg"));await using var stream = File.OpenRead("./photos/product.jpg");await client.Media.UploadAsync(MediaUploadParams.FromStream(stream, "product.jpg"));
Analytics
Code
// One post's latest per-platform metricsvar stats = await client.Analytics.PostAsync("post_id");Console.WriteLine(stats!.Value.GetProperty("data").GetProperty("platforms"));// Batch: up to 100 posts in one callvar batch = await client.Analytics.PostsAsync(new[] { "id1", "id2", "id3" });// Workspace-wide overviewvar overview = await client.Analytics.OverviewAsync(new AnalyticsOverviewParams { Period = "30d" });var totals = overview!.Value.GetProperty("data");Console.WriteLine($"{totals.GetProperty("total_impressions")} impressions");// Account-level stats (followers etc)var accountStats = await client.Analytics.AccountsAsync(new AccountAnalyticsParams { Platform = "instagram" });
Social Inbox
The .NET SDK also covers the Social Inbox with cursor pagination and optional
typed models:
Code
var page = await client.Inbox.ListConversationsAsync(new InboxListParams { Platform = "instagram", Unread = true });var messages = await client.Inbox.GetMessagesAsync(conversationId);await client.Inbox.ReplyAsync(conversationId, new InboxReplyParams { Text = "Thanks for reaching out!" });await client.Inbox.MarkReadAsync(conversationId);
Requires the opt-in inbox:read / inbox:write scopes. See the
Social Inbox guide.
Verify webhooks
ASP.NET Core minimal API:
Code
using System.Text.Json;using OmniSocials;var builder = WebApplication.CreateBuilder(args);var app = builder.Build();app.MapPost("/omnisocials/webhook", async (HttpRequest request) =>{ using var reader = new StreamReader(request.Body); var payload = await reader.ReadToEndAsync(); // raw body, do not re-serialize var signature = request.Headers["X-OmniSocials-Signature"].ToString(); var secret = Environment.GetEnvironmentVariable("OMNISOCIALS_WEBHOOK_SECRET")!; JsonElement webhookEvent; try { webhookEvent = WebhookSignature.Verify(payload, signature, secret, toleranceSeconds: 300); } catch (WebhookVerificationException) { return Results.BadRequest(); } switch (webhookEvent.GetProperty("type").GetString()) { case "post.published": var data = webhookEvent.GetProperty("data"); Console.WriteLine($"Published: {data.GetProperty("post_id")} {data.GetProperty("targets")}"); break; case "post.failed": Console.Error.WriteLine($"Failed: {webhookEvent.GetProperty("data").GetProperty("post_id")}"); break; } return Results.Ok();});app.Run();