.NET SDK

The official .NET client for the FoPost API, with no third-party dependencies.

FoPost.Sdk is the official .NET client. It needs .NET 8 or newer and has no third-party dependencies.

dotnet add package FoPost.Sdk

This is a 0.x release. The surface is still settling and a minor version may break something. Pin an exact version if that matters to you.

Published on NuGet. Source and issues: github.com/fopost/fopost-dotnet. MIT licensed.

Quick start

using FoPost;

using var client = new FoPostClient(Environment.GetEnvironmentVariable("FOPOST_API_KEY")!);

// List your accounts
var accounts = await client.Accounts.ListAsync("9b2f6c1e-…");

// Create a post, then publish it immediately
var post = await client.Posts.CreateAsync(
    workspaceId: "9b2f6c1e-…",
    text: "Hello from the SDK",
    accounts: accounts.Select(account => account.Id));

await client.Posts.PublishAsync(post.Id);

// Schedule for later
await client.Posts.CreateAsync(new CreatePostOptions
{
    WorkspaceId = "9b2f6c1e-…",
    Status = PostStatuses.Scheduled,
    ScheduleAt = new DateTimeOffset(2026, 9, 1, 10, 0, 0, TimeSpan.Zero),
    Content = new List<PostContent> { new("Scheduled with the SDK") },
    Accounts = new List<string> { accounts[0].Id },
});

PublishAsync returns once delivery is queued, not once it is live. Read Posts.DeliveriesAsync or subscribe to webhooks for the result. A key is limited to the scopes granted at creation; the calls above need posts and accounts.

Configuration

using var client = new FoPostClient(new FoPostClientOptions
{
    ApiKey = "fp_…",                        // defaults to $FOPOST_API_KEY
    BaseUrl = "https://api.fopost.com",     // override for another deployment
    Timeout = TimeSpan.FromSeconds(30),
    MaxRetries = 3,                         // total attempts on a 429, including the first
    HttpClient = httpClientFromFactory,     // optional; the SDK will not dispose it
});

FoPostClient is thread-safe and meant to be long-lived, so register it as a singleton rather than constructing one per request. With IHttpClientFactory:

services.AddHttpClient("fopost");
services.AddSingleton(provider => new FoPostClient(new FoPostClientOptions
{
    HttpClient = provider.GetRequiredService<IHttpClientFactory>().CreateClient("fopost"),
}));

Paging

ListAsync returns one page plus its Meta. ListAllAsync walks every page for you:

await foreach (var post in client.Posts.ListAllAsync(new ListPostsOptions
{
    WorkspaceId = "9b2f6c1e-…",
    Status = PostStatuses.Scheduled,
}))
{
    Console.WriteLine($"{post.ScheduleAt:u}  {post.Content.FirstOrDefault()?.Text}");
}

Partial updates

Every field on UpdatePostOptions is an Optional<T>, so "leave this alone" and "clear this" stay different things:

await client.Posts.UpdateAsync(post.Id, new UpdatePostOptions
{
    Title = "New title",                    // sent
    Summary = Optional<string?>.Of(null),   // sent as null, clearing it
    // ScheduleAt is untouched, not sent at all
});

AI features

var caption = await client.Ai.GenerateCaptionAsync(new GenerateCaptionOptions
{
    CurrentCaption = "shipping a new feature",
    Platforms = new List<string> { Platforms.Twitter, Platforms.LinkedIn },
});

var balance = await client.Ai.CreditsAsync();
Console.WriteLine($"{balance.CreditsRemaining} of {balance.CreditsTotal} credits left");

RewriteAsync and RepurposeUrlAsync reach dashboard-session endpoints: they need a BearerToken rather than an API key, and answer 401 to a key. Use the composer for those until a later release.

What is on the client

NamespaceMethods
PostsListAsync, ListAllAsync, GetAsync, CreateAsync, UpdateAsync, DeleteAsync, PublishAsync, CancelAsync, RetryAsync, PreflightAsync, DuplicateAsync, DeliveriesAsync
AccountsListAsync, GetAsync, HealthAsync
WorkspacesListAsync, GetAsync
LabelsListAsync
AiCreditsAsync, GenerateCaptionAsync, RewriteAsync, RepurposeUrlAsync

The API has more endpoints than this client wraps: analytics, webhooks, automations, media, and communities among them. RequestAsync reaches any of them with the same auth, retries, and error handling:

var overview = await client.RequestAsync(
    HttpMethod.Get,
    "/v1/analytics/overview",
    query: new Dictionary<string, object?> { ["workspace_id"] = "9b2f6c1e-…" });

Errors

Every non-2xx response raises a FoPostException carrying the API's status, error code, and body.

StatusException
400, 422FoPostValidationException
401FoPostAuthenticationException
402FoPostPaymentRequiredException
403FoPostPermissionDeniedException
404FoPostNotFoundException
429FoPostRateLimitException
anything elseFoPostException
try
{
    await client.Posts.PublishAsync(post.Id);
}
catch (FoPostRateLimitException error)
{
    Console.WriteLine($"Slow down for {error.RetryAfter}");
}
catch (FoPostPaymentRequiredException error)
{
    Console.WriteLine($"Upgrade at {error.UpgradeUrl}");
}
catch (FoPostException error)
{
    Console.WriteLine($"API {error.Status} ({error.Code}): {error.Message}");
}

A 429 is retried automatically, up to MaxRetries attempts, waiting for the interval the API asks for in Retry-After. The exception is raised only once the retries are spent.

Next

Related documentation
  • SDKs & Integrations

    Official FoPost clients for TypeScript, Python, PHP, Ruby, Go, Rust, Java, .NET, Swift, Kotlin, Dart, and Elixir, framework integrations from Laravel to Next.js, and tooling for the CLI, CI, Terraform, and the automation platforms.

  • SDKs Overview

    Every official FoPost client, what it covers, and how to pick one.

  • TypeScript SDK

    The official TypeScript and Node.js client for the FoPost API.

  • Python SDK

    The official Python client for the FoPost API.

  • PHP SDK

    The official PHP client for the FoPost API, with no framework and no HTTP library.

  • Ruby SDK

    The official Ruby client for the FoPost API, with no runtime dependencies.

  • Go SDK

    The official Go client for the FoPost API.

  • Rust SDK

    The official Rust client for the FoPost API, async and built on reqwest.

Was this helpful?

On this page