The Corti.Sdk NuGet package is the official C# .NET SDK for the Corti API. It provides full coverage of every REST endpoint and WebSocket connection, with built-in authentication, automatic token refresh, async/await support, and typed exceptions.
The simplest way to get started is with client credentials (server-side):
C# .NET
using Corti;var client = new CortiClient( tenantName: "YOUR_TENANT_NAME", environment: "YOUR_ENVIRONMENT_ID", auth: CortiClientAuth.ClientCredentials( clientId: "YOUR_CLIENT_ID", clientSecret: "YOUR_CLIENT_SECRET"));
Client credentials authentication is intended for backend / server-side applications only. Never expose your client secret in client-side code. For frontend scenarios, use bearer tokens or pass tokens from your backend.
Create a single CortiClient instance and reuse it throughout your application. The SDK handles token refresh automatically — there is no need to re-initialize for each request.
The SDK supports six authentication methods to cover different deployment scenarios:
Method
Environment
Use case
Client Credentials (recommended)
Backend only
Server-to-server integrations
Authorization Code
Backend
Interactive user login (confidential clients)
PKCE
Frontend & Backend
Interactive user login (public clients)
ROPC
Backend only
Username/password for trusted apps
Bearer Token
Frontend & Backend
When you already have a token from another source
Custom Refresh
Frontend & Backend
You manage token refresh yourself
Client Credentials is the recommended authentication method. Your backend should handle all data access checks and never expose the service-account token or client secret to the browser. The other flows (Authorization Code, PKCE, ROPC) are primarily intended for Embedded Assistant use cases where end-user login is required.
var now = DateTime.UtcNow;var interaction = await client.Interactions.CreateAsync(new InteractionsCreateRequest{ AssignedUserId = "GUID OF YOUR CHOOSING", Encounter = new InteractionsEncounterCreateRequest { Identifier = "GUID OF YOUR CHOOSING", Status = InteractionsEncounterStatusEnum.Planned, Type = InteractionsEncounterTypeEnum.FirstConsultation, Period = new InteractionsEncounterPeriod { StartedAt = now, EndedAt = now, }, Title = "Consultation", }, Patient = new InteractionsPatient { Identifier = "<string>", Name = "<string>", Gender = InteractionsGenderEnum.Male, BirthDate = now, Pronouns = "<string>", },});
See the full request specification in the API Reference.
var document = await client.Documents.CreateAsync( interactionId, new DocumentsCreateRequestWithTemplateKey { Context = [ DocumentsContext.FromDocumentsContextWithTranscript( new DocumentsContextWithTranscript { Type = DocumentsContextWithTranscriptType.Transcript, Data = new CommonTranscriptRequest { Text = "tell me a bit about what's been going on? When did you first start feeling unwell?\n\n- Erm, I think it was probably about a week ago.\n\n- Right, okay. And when you say achy, was it more like muscle aches, or joint pain?", }, } ), ], TemplateKey = "corti-brief-clinical-note", Name = "test brief note from transcript", OutputLanguage = "en", });
The SDK retries failed requests with exponential backoff when the response is retryable and the attempt count is below the limit (default: 2). A response is retryable when the status code is 408, 429, or any 5xx.Override per request:
await client.Interactions.CreateAsync( new InteractionsCreateRequest { /* ... */ }, new RequestOptions { MaxRetries = 0 });
Set defaults for all requests via CortiRequestOptions on the client:
var client = new CortiClient( tenantName: "YOUR_TENANT", environment: "YOUR_ENVIRONMENT_ID", auth: CortiClientAuth.ClientCredentials( clientId: "YOUR_CLIENT_ID", clientSecret: "YOUR_CLIENT_SECRET" ), requestOptions: new CortiRequestOptions { MaxRetries = 3, Timeout = TimeSpan.FromMinutes(2), });
Methods that return WithRawResponseTask<T> let you await either the parsed model or parsed data plus HTTP metadata. Call .WithRawResponse() on the task to get status code, URL, and headers alongside Data:
var result = await client.Interactions.GetAsync("YOUR_INTERACTION_ID").WithRawResponse();var interaction = result.Data;Console.WriteLine(result.RawResponse.StatusCode);Console.WriteLine(result.RawResponse.Url);if (result.RawResponse.Headers.TryGetValue("X-Request-Id", out var requestId)){ Console.WriteLine($"Request ID: {requestId}");}
Paginated ListAsync helpers return a Pager and do not expose .WithRawResponse(). Use a non-paginated endpoint method that returns WithRawResponseTask<T> when you need raw HTTP metadata.
Enum-like types in the SDK accept unknown API values without failing deserialization. You can use built-in values, custom string values from the API, and inspect .Value in a switch:
var sort = InteractionsListRequestSort.Id;var custom = InteractionsListRequestSort.FromCustom("future-sort-key");switch (sort.Value){ case InteractionsListRequestSort.Values.Id: Console.WriteLine("Id"); break; default: Console.WriteLine($"Unknown or forward-compatible: {sort.Value}"); break;}string asString = (string)InteractionsListRequestSort.Id;InteractionsListRequestSort fromString = (InteractionsListRequestSort)"id";
For scenarios where your server proxies requests to Corti and handles auth externally, you can create a client with only an environment (no credentials):
var env = CortiEnvironments.FromBaseUrl("https://your-proxy.com/api");var client = new CortiClient(environment: env);
No Authorization header is sent by default. Add your own headers per request using RequestOptions.AdditionalHeaders.See the Authentication Guide for details.