How to Call the OpenAI API from C#: A Complete Guide for .NET Developers
Almost every LLM tutorial on the internet starts with pip install. If you're a .NET developer, it's easy to conclude that AI development belongs to Python and your stack is a second-class citizen. It isn't. OpenAI ships an official .NET SDK, the APIs are plain HTTPS underneath, and C# is a genuinely great language for building production AI features — you already have the typing, the async story, and the DI ecosystem.
This is the guide I wish I'd had when I added my first LLM feature to an ASP.NET Core service: from zero to a streaming, error-handled chat completion, all in C#.
Setup
You'll need an API key from the OpenAI platform (Dashboard → API keys). Then install the official package:
Never hardcode the key. Locally, use user secrets; in production, environment variables or a secret store (Azure Key Vault):
Your first chat completion
Three things worth understanding immediately:
- The system message is your steering wheel. Tone, format, constraints, persona — set them here, not by hoping the user asks nicely.
- Models are named strings.
gpt-4o-miniis cheap and fast — right for most features; step up to a larger model only where quality measurably demands it. - The API is stateless. The model remembers nothing between calls. "Conversation memory" is you sending the history back every time:
That growing list is also your growing bill — long conversations eventually need summarizing or trimming, because you pay per token, every turn.
Wiring it into ASP.NET Core properly
ChatClient is thread-safe; register it once as a singleton behind your own interface so the rest of the codebase isn't coupled to a vendor SDK:
That interface seam matters more in AI code than most: providers leapfrog each other every few months, and you want swapping (or A/B testing) to be a one-class change. (If you want the abstraction handled for you, that's exactly what Microsoft.Extensions.AI provides — see the follow-up post linked below.)
Streaming: the difference between "broken" and "fast"
A full completion can take many seconds, and users perceive a silent spinner as failure. Streaming sends tokens as they're generated:
In ASP.NET Core, pair this with server-sent events or SignalR to get the ChatGPT-style typing effect. Same cost, same latency-to-last-token — dramatically better perceived speed. For any user-facing chat feature, streaming isn't optional polish; it's table stakes.
Errors and resilience: the part demos skip
LLM APIs fail in ways your other dependencies don't — rate limits are routine, latency is variable, and outages happen. Production checklist:
- Retry 429/5xx with exponential backoff (Polly's
AddResilienceHandlerif you're calling via HttpClient, or a simple retry loop). - Always pass the CancellationToken — users abandon slow requests; don't keep paying for them.
- Degrade gracefully. Your app should have an answer for "the AI is down" that isn't a 500.
- Log token usage (
completion.Usage) — it's your cost meter, and the first thing you'll want when the invoice surprises someone.
What it costs (and how not to get surprised)
You're billed per input and output token (a token ≈ ¾ of an English word). Small models cost fractions of a cent per typical request; the mistakes that produce scary invoices are always architectural: resending huge conversation histories, stuffing entire documents into every prompt, or retry loops without caps. Set a monthly budget limit in the OpenAI dashboard on day one, and log usage per feature so costs have an owner.
Where to go next
You now have the core loop every AI feature is built on: messages in, completion out, streamed to the user, with failure handling around it. From here:
- Getting Started with Microsoft.Extensions.AI — the provider-agnostic abstraction layer for .NET.
- Getting Reliable JSON Out of LLMs in C# — when you need data back, not prose.
- LLM Function Calling in C# — letting the model safely invoke your code.