C# / .NET SDK
For .NET projects, two packages are recommended:
- OpenAI compatible:
OpenAI(official, maintained jointly with Microsoft) - Anthropic native:
Anthropic.SDK(community, maintained bytghamm)
Anthropic also has an official C# SDK (
anthropics/anthropic-sdk-csharp) currently in beta. If you want to try it, refer to its README. For production, the communityAnthropic.SDKis the safer choice today. Examples are based on the official and community READMEs pulled via Context7; defer to the package docs for the latest API.
Setup
export SAKRYLLE_API_KEY="sk-xxxxxxxxxxxxxxxx".NET 6+ is required.
OpenAI compatible
Install
dotnet add package OpenAIMinimal usage
Use OpenAIClientOptions.Endpoint to redirect requests to Sakrylle:
using System;
using System.ClientModel;
using OpenAI;
using OpenAI.Chat;
var apiKey = Environment.GetEnvironmentVariable("SAKRYLLE_API_KEY")
?? throw new InvalidOperationException("missing SAKRYLLE_API_KEY");
var options = new OpenAIClientOptions
{
Endpoint = new Uri("https://api.sakrylle.com/v1"),
};
ChatClient client = new(
model: "gpt-5.6-sol",
credential: new ApiKeyCredential(apiKey),
options: options);
ChatCompletion completion = client.CompleteChat(
new SystemChatMessage("You are a concise assistant."),
new UserChatMessage("Explain vector databases in one sentence."));
Console.WriteLine(completion.Content[0].Text);Streaming
using System;
using System.ClientModel;
using OpenAI;
using OpenAI.Chat;
var apiKey = Environment.GetEnvironmentVariable("SAKRYLLE_API_KEY")!;
var options = new OpenAIClientOptions
{
Endpoint = new Uri("https://api.sakrylle.com/v1"),
};
ChatClient client = new("gpt-5.6-sol", new ApiKeyCredential(apiKey), options);
foreach (var update in client.CompleteChatStreaming("Count to 5."))
{
foreach (var part in update.ContentUpdate)
{
Console.Write(part.Text);
}
}
Console.WriteLine();Tool calling
using System.Text.Json;
using OpenAI.Chat;
ChatTool getWeather = ChatTool.CreateFunctionTool(
functionName: "get_weather",
functionDescription: "Look up the current weather for a city",
functionParameters: BinaryData.FromString(
"""
{
"type": "object",
"properties": {
"city": { "type": "string" }
},
"required": ["city"]
}
"""));
ChatCompletionOptions chatOptions = new()
{
Tools = { getWeather },
};
ChatCompletion result = client.CompleteChat(
new[] { new UserChatMessage("What's the weather in Beijing today?") },
chatOptions);
if (result.FinishReason == ChatFinishReason.ToolCalls)
{
foreach (var call in result.ToolCalls)
{
Console.WriteLine($"call: {call.FunctionName} args: {call.FunctionArguments}");
}
}Anthropic native
Install
dotnet add package Anthropic.SDKThis is the community-maintained package by tghamm, not an official Anthropic release.
Minimal usage
using Anthropic.SDK;
using Anthropic.SDK.Constants;
using Anthropic.SDK.Messaging;
var apiKey = Environment.GetEnvironmentVariable("SAKRYLLE_API_KEY")!;
// Use a custom HttpClient to point BaseAddress at Sakrylle
var http = new HttpClient
{
BaseAddress = new Uri("https://api.sakrylle.com/"),
};
var client = new AnthropicClient(
apiKeys: new APIAuthentication(apiKey),
client: http);
var parameters = new MessageParameters
{
Model = "claude-haiku-4-5-20251001",
MaxTokens = 1024,
Messages = new List<Message>
{
new(RoleType.User, "Introduce Claude in one sentence."),
},
};
var response = await client.Messages.GetClaudeMessageAsync(parameters);
Console.WriteLine(response.Message);The SDK uses
HttpClient.BaseAddressto control the gateway URL. Keep the trailing slash, or the SDK will drop the prefix when joining paths. Refer to the Anthropic.SDK README for the current API and constructor signatures.
Streaming
var streamParams = new MessageParameters
{
Model = "claude-haiku-4-5-20251001",
MaxTokens = 1024,
Stream = true,
Messages = new List<Message>
{
new(RoleType.User, "Write a four-line poem."),
},
};
await foreach (var chunk in client.Messages.StreamClaudeMessageAsync(streamParams))
{
if (chunk.Delta != null)
{
Console.Write(chunk.Delta.Text);
}
}Error handling
using System.ClientModel;
try
{
var completion = client.CompleteChat("hi");
}
catch (ClientResultException ex)
{
// 401 / 429 / 500, etc., all land here
Console.Error.WriteLine($"status={ex.Status} message={ex.Message}");
}For a full error table, see Errors.
