C# / .NET SDK
⚠️
Preview — this feature is being built; the design below is the spec.
Syntic on NuGet is the planned official .NET client. It is generated from the OpenAPI description, uses async methods throughout, works with dependency injection, and adds helpers for streaming with IAsyncEnumerable, tool loops, pagination and batches. It is in the second release wave; see Other languages.
Today, use HttpClient as shown in Quickstart: C#. That code keeps working after the SDK ships.
Install
dotnet add package Syntic| Requirement | Value |
|---|---|
| .NET | 8.0 or newer |
| Package | Syntic on NuGet |
| Dependencies | System.Text.Json, Microsoft.Extensions.Http (optional, for DI) |
Create a client
using Syntic;
var client = new SynticClient(); // reads SYNTIC_API_KEY and SYNTIC_BASE_URL
var custom = new SynticClient(new SynticClientOptions
{
ApiKey = Environment.GetEnvironmentVariable("SYNTIC_API_KEY"),
BaseUrl = new Uri("https://app.syntic.ai/v1"),
MaxRetries = 3,
Timeout = TimeSpan.FromMinutes(5),
});With dependency injection:
builder.Services.AddSyntic(options => options.MaxRetries = 3); // registers SynticClient via IHttpClientFactory| Option | Default | Notes |
|---|---|---|
ApiKey | SYNTIC_API_KEY | Private key or workload identity token. |
BaseUrl | SYNTIC_BASE_URL, else https://app.syntic.ai/v1 | |
Version | The release’s API version | Sent as syntic-version. |
Betas | empty | Sent as syntic-beta; methods that need a flag add it. |
MaxRetries | 2 | rate_limit, overloaded, api_error and transient network errors. |
Timeout | 10 minutes |
A first request
var reply = await client.Chat.Completions.CreateAsync(new()
{
Model = "Amara S1.2",
MaxTokens = 200,
Messages = [Message.System("Answer in one sentence."), Message.User("Why is the sky blue?")],
});
Console.WriteLine(reply.Choices[0].Message.Content);
Console.WriteLine($"{reply.Usage.TotalTokens} tokens, request {reply.RequestId}");Streaming
await using var stream = client.Chat.Completions.Stream(new()
{
Model = "Amara Quick",
Messages = [Message.User("Write a haiku about rain.")],
});
await foreach (var text in stream.TextDeltasAsync(cancellationToken))
Console.Write(text);
var final = await stream.GetFinalCompletionAsync(); // assembled message, tool calls, usageCancelling the token or disposing the stream closes the connection.
Tool loop
var getOrder = Tool.Create("get_order", "Look up an order by its id.",
([Description("Order id such as 88123")] string orderId) =>
new { order_id = orderId, status = "shipped" });
var result = await client.Tools.RunAsync(new()
{
Model = "Amara S1.2",
Messages = [Message.User("Where is order 88123?")],
Tools = [getOrder],
MaxRounds = 8,
});
Console.WriteLine(result.FinalMessage.Content);Errors
| Exception | error.type |
|---|---|
SynticInvalidRequestException | invalid_request |
SynticAuthenticationException | authentication |
SynticPermissionException | permission |
SynticNotFoundException | not_found |
SynticQuotaExhaustedException | quota_exhausted |
SynticRateLimitException | rate_limit |
SynticOverloadedException | overloaded |
SynticServerException | api_error |
All derive from SynticApiException with StatusCode, Type, Code, Param, Details and RequestId. Network failures surface as HttpRequestException or TaskCanceledException.
try
{
await client.Chat.Completions.CreateAsync(request);
}
catch (SynticQuotaExhaustedException e)
{
Console.WriteLine($"Paused until {e.Details["resets_at"]}");
}Pagination
await foreach (var agent in client.Agents.ListAutoPagingAsync(new() { Limit = 50 }))
Console.WriteLine($"{agent.Id} {agent.Name}");Files, batches, agents and admin
var file = await client.Files.UploadAsync("contract.pdf", purpose: "document");
var batch = await client.Batches.CreateAsync(new() { InputFileId = file.Id });
batch = await client.Batches.WaitAsync(batch.Id, pollInterval: TimeSpan.FromSeconds(30));
var session = await client.Sessions.CreateAsync(new() { AgentId = "agt_01JC4R8W6Q2N9X3T5V7Y" });
await foreach (var ev in client.Sessions.StreamAsync(session.Id))
if (ev.Type == "message.completed") Console.WriteLine(ev.Content);
var admin = new SynticAdminClient(); // reads SYNTIC_ADMIN_KEY
await foreach (var user in admin.Users.ListAutoPagingAsync())
Console.WriteLine(user.Email);Raw responses
var raw = await client.Chat.Completions.WithRawResponse.CreateAsync(request);
Console.WriteLine(raw.Headers.GetValues("x-syntic-billing-source").First());
var reply = raw.Parse();Related
Was this page helpful?