CivitaiSharp.Core
0.11.0
dotnet add package CivitaiSharp.Core --version 0.11.0
NuGet\Install-Package CivitaiSharp.Core -Version 0.11.0
<PackageReference Include="CivitaiSharp.Core" Version="0.11.0" />
<PackageVersion Include="CivitaiSharp.Core" Version="0.11.0" />
<PackageReference Include="CivitaiSharp.Core" />
paket add CivitaiSharp.Core --version 0.11.0
#r "nuget: CivitaiSharp.Core, 0.11.0"
#:package CivitaiSharp.Core@0.11.0
#addin nuget:?package=CivitaiSharp.Core&version=0.11.0
#tool nuget:?package=CivitaiSharp.Core&version=0.11.0
CivitaiSharp

A modern, lightweight, and AOT-ready .NET 10 client library for all things Civitai.com.
Note: CivitaiSharp is currently in Alpha. APIs, features, and stability are subject to change.
Table of Contents
- Packages and Release Schedule
- Installation
- Quick Start
- Configuration
- API Examples
- Features
- Documentation
- Known API Quirks
- Versioning
- License
- Contributing
1. Packages and Release Schedule
| Package | Status | Description |
|---|---|---|
| CivitaiSharp.Core | Alpha | Public API client for models, images, tags, and creators |
| CivitaiSharp.Sdk | Alpha | Generator/Orchestration API client for image generation jobs |
| CivitaiSharp.Tools | Alpha | Utilities for downloads, file hashing, and HTML parsing |
Note: All packages are currently in Alpha. APIs may change between minor versions.
Warning: CivitaiSharp.Sdk is not fully tested and should not be used in production environments. Use at your own risk.
2. Installation
Install via NuGet:
# Core library - API client for models, images, tags, and creators
dotnet add package CivitaiSharp.Core --prerelease
# SDK - Image generation and job management (requires API token)
dotnet add package CivitaiSharp.Sdk --prerelease
# Tools - File hashing, downloads, and HTML parsing
dotnet add package CivitaiSharp.Tools --prerelease
3. Quick Start
Minimal Example
The simplest way to get started with CivitaiSharp.Core:
using CivitaiSharp.Core;
using CivitaiSharp.Core.Extensions;
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
services.AddCivitaiApi();
await using var provider = services.BuildServiceProvider();
var client = provider.GetRequiredService<IApiClient>();
var result = await client.Models.ExecuteAsync();
if (result.IsSuccess)
{
foreach (var model in result.Value.Items)
Console.WriteLine(model.Name);
}
Full Example with Configuration
using CivitaiSharp.Core;
using CivitaiSharp.Core.Extensions;
using CivitaiSharp.Core.Models;
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
services.AddCivitaiApi(options =>
{
options.TimeoutSeconds = 120;
options.StrictJsonParsing = true;
});
await using var provider = services.BuildServiceProvider();
var client = provider.GetRequiredService<IApiClient>();
var result = await client.Models
.WhereType(ModelType.Checkpoint)
.WhereNsfw(false)
.OrderBy(ModelSort.MostDownloaded)
.ExecuteAsync(resultsLimit: 10);
if (result.IsSuccess)
{
foreach (var model in result.Value.Items)
Console.WriteLine($"{model.Name} by {model.Creator?.Username}");
}
else
{
Console.WriteLine($"Error: {result.ErrorInfo.Message}");
}
4. Configuration
Using appsettings.json
CivitaiSharp.Core reads configuration from the CivitaiApi section by default.
Minimal Configuration (appsettings.json)
{
"CivitaiApi": {
}
}
All settings have sensible defaults, so an empty section is valid.
Full Configuration (appsettings.json)
{
"CivitaiApi": {
"BaseUrl": "https://civitai.com",
"ApiVersion": "v1",
"ApiKey": null,
"TimeoutSeconds": 30,
"StrictJsonParsing": false
}
}
| Property | Type | Default | Description |
|---|---|---|---|
BaseUrl |
string |
https://civitai.com |
Base URL for the Civitai API |
ApiVersion |
string |
v1 |
API version path segment |
ApiKey |
string? |
null |
Optional API key for authenticated requests |
TimeoutSeconds |
int |
30 |
HTTP request timeout (1-300 seconds) |
StrictJsonParsing |
bool |
false |
Throw on unmapped JSON properties |
Authentication Note: The Core library can query public endpoints (models, images, tags, creators) without an API key. An API key is only required for authenticated features like favorites, hidden models, and higher rate limits. NSFW Content: Setting
WhereNsfw(true)on models or using certainImageNsfwLevelvalues (Mature, X) requires authentication. This is different from CivitaiSharp.Sdk which always requires an API token for all operations.
Configuration with IConfiguration
using CivitaiSharp.Core.Extensions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
var services = new ServiceCollection();
services.AddCivitaiApi(configuration);
// Or with a custom section name:
// services.AddCivitaiApi(configuration, "MyCustomSection");
await using var provider = services.BuildServiceProvider();
5. API Examples
CivitaiSharp.Core provides fluent builders for each endpoint. Each builder is immutable and thread-safe.
Models Endpoint
// Get all models (default query)
var result = await client.Models.ExecuteAsync();
// Get a specific model by ID
var result = await client.Models.GetByIdAsync(12345);
if (result.IsSuccess)
Console.WriteLine($"Model: {result.Value.Name}");
// Get the first matching model (efficient single-item retrieval)
var result = await client.Models
.WhereName("SDXL")
.FirstOrDefaultAsync();
if (result is { IsSuccess: true, Value: not null })
Console.WriteLine($"Found: {result.Value.Name}");
// Search by name
var result = await client.Models
.WhereName("SDXL")
.ExecuteAsync();
// Filter by type and sort
var result = await client.Models
.WhereType(ModelType.Checkpoint)
.OrderBy(ModelSort.MostDownloaded)
.ExecuteAsync(resultsLimit: 25);
// Filter by tag
var result = await client.Models
.WhereTag("anime")
.WhereNsfw(false)
.ExecuteAsync();
// Filter by creator
var result = await client.Models
.WhereUsername("Mewyk")
.OrderBy(ModelSort.Newest)
.ExecuteAsync();
// Filter by base model (string value, e.g., "SDXL 1.0", "SD 1.5", "Flux.1 D")
var result = await client.Models
.WhereBaseModel("SDXL 1.0")
.WhereType(ModelType.Lora)
.ExecuteAsync();
// Filter by multiple base models
var result = await client.Models
.WhereBaseModels("SDXL 1.0", "Pony")
.ExecuteAsync();
// Filter by specific model IDs (ignored if query is also provided)
var result = await client.Models
.WhereIds(12345, 67890, 11111)
.ExecuteAsync();
// Get a specific model version by version ID
var versionResult = await client.Models.GetByVersionIdAsync(130072);
if (versionResult.IsSuccess)
{
Console.WriteLine($"Version: {versionResult.Value.Name}");
Console.WriteLine($"AIR: {versionResult.Value.AirIdentifier}");
}
// Get a model version by file hash (SHA256, AutoV2, CRC32, etc.)
var hashResult = await client.Models.GetByVersionHashAsync("ABC123DEF456");
if (hashResult.IsSuccess)
{
Console.WriteLine($"Found: {hashResult.Value.Model?.Name}");
Console.WriteLine($"AIR: {hashResult.Value.AirIdentifier}");
}
Images Endpoint
// Get all images (default query)
var result = await client.Images.ExecuteAsync();
// Get the first matching image
var result = await client.Images
.WhereModelId(12345)
.FirstOrDefaultAsync();
if (result is { IsSuccess: true, Value: not null })
Console.WriteLine($"Image URL: {result.Value.Url}");
// Filter by model ID
var result = await client.Images
.WhereModelId(12345)
.ExecuteAsync();
// Filter by model version ID
var result = await client.Images
.WhereModelVersionId(67890)
.OrderBy(ImageSort.Newest)
.ExecuteAsync();
// Filter by username
var result = await client.Images
.WhereUsername("Mewyk")
.WhereNsfwLevel(ImageNsfwLevel.None)
.ExecuteAsync(resultsLimit: 50);
// Filter by post ID
var result = await client.Images
.WherePostId(11111)
.ExecuteAsync();
Tags Endpoint
// Get all tags (default query)
var result = await client.Tags.ExecuteAsync();
// Search tags by name
var result = await client.Tags
.WhereName("portrait")
.ExecuteAsync(resultsLimit: 100);
Creators Endpoint
// Get all creators (default query)
var result = await client.Creators.ExecuteAsync();
// Search creators by name
var result = await client.Creators
.WhereName("Mewyk")
.ExecuteAsync(resultsLimit: 20);
// Page-based pagination (Models, Tags, and Creators use pages, not cursors)
var result = await client.Creators
.WithPageIndex(2)
.ExecuteAsync(resultsLimit: 50);
Pagination
// Cursor-based pagination (Images only)
string? cursor = null;
var allImages = new List<Image>();
do
{
result = await client.Images
.WhereModelId(12345)
.ExecuteAsync(resultsLimit: 100, cursor: cursor);
if (!result.IsSuccess)
break;
allImages.AddRange(result.Value.Items);
cursor = result.Value.Metadata?.NextCursor;
} while (cursor is not null);
// Page-based pagination (Models, Tags, Creators)
var page1 = await client.Models.WithPageIndex(1).ExecuteAsync();
var page2 = await client.Tags.WithPageIndex(2).ExecuteAsync();
var page3 = await client.Creators.WithPageIndex(3).ExecuteAsync();
Tools - File Hashing
using CivitaiSharp.Tools.Hashing;
using CivitaiSharp.Tools.Extensions;
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
services.AddCivitaiDownloads();
await using var provider = services.BuildServiceProvider();
var hashingService = provider.GetRequiredService<IFileHashingService>();
// Compute SHA256 hash
var result = await hashingService.ComputeHashAsync(
@"C:\Models\model.safetensors",
HashAlgorithm.Sha256);
if (result.IsSuccess)
{
Console.WriteLine($"Hash: {result.Value.Hash}");
Console.WriteLine($"Size: {result.Value.FileSize:N0} bytes");
}
// Supported algorithms: Sha256, Sha512, Blake3, Crc32
var blake3Result = await hashingService.ComputeHashAsync(filePath, HashAlgorithm.Blake3);
Tools - Downloading Files
using CivitaiSharp.Core;
using CivitaiSharp.Core.Extensions;
using CivitaiSharp.Tools.Downloads;
using CivitaiSharp.Tools.Extensions;
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
services.AddCivitaiApi();
services.AddCivitaiDownloads(options =>
{
options.Images.BaseDirectory = @"C:\Downloads\Images";
options.Images.PathPattern = "{Username}/{Id}.{Extension}";
options.Models.BaseDirectory = @"C:\Models";
options.Models.PathPattern = "{ModelType}/{ModelName}/{FileName}";
options.Models.VerifyHash = true;
});
await using var provider = services.BuildServiceProvider();
var apiClient = provider.GetRequiredService<IApiClient>();
var downloadService = provider.GetRequiredService<IDownloadService>();
// Download a model file with hash verification
var modelResult = await apiClient.Models.GetByIdAsync(4201);
if (modelResult.IsSuccess)
{
var version = modelResult.Value.ModelVersions?.FirstOrDefault();
var file = version?.Files?.FirstOrDefault(f => f.Primary == true);
if (file is not null && version is not null)
{
var downloadResult = await downloadService.DownloadAsync(file, version);
if (downloadResult.IsSuccess)
{
Console.WriteLine($"Downloaded: {downloadResult.Value.FilePath}");
Console.WriteLine($"Verified: {downloadResult.Value.IsVerified}");
}
}
}
Tools - HTML Parsing
using CivitaiSharp.Tools.Parsing;
// Convert HTML description to Markdown
var markdown = HtmlParser.ToMarkdown(model.Description);
// Convert to plain text
var plainText = HtmlParser.ToPlainText(model.Description);
// Or use extension methods on Model/ModelVersion
var markdown = model.GetDescriptionAsMarkdown();
var plainText = modelVersion.GetDescriptionAsPlainText();
SDK - Image Generation (Jobs)
using CivitaiSharp.Sdk;
using CivitaiSharp.Sdk.Extensions;
using CivitaiSharp.Sdk.Air;
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
services.AddCivitaiSdk(options =>
{
options.ApiToken = "your-api-token"; // Required for SDK
});
await using var provider = services.BuildServiceProvider();
var sdkClient = provider.GetRequiredService<ISdkClient>();
// Create a text-to-image job
var model = AirIdentifier.Parse("urn:air:sdxl:checkpoint:civitai:4201@130072");
var result = await sdkClient.Jobs
.CreateTextToImage()
.WithModel(model)
.WithPrompt("a beautiful sunset over mountains, highly detailed")
.WithNegativePrompt("blurry, low quality")
.WithSize(1024, 1024)
.WithSteps(30)
.WithCfgScale(7.5m)
.WithSeed(12345)
.ExecuteAsync();
if (result is Result<JobStatusCollection>.Success success)
{
var token = success.Data.Token;
Console.WriteLine($"Job submitted: {token}");
// Query job status
var statusResult = await sdkClient.Jobs.Query
.WithDetailed()
.GetByTokenAsync(token);
if (statusResult is Result<JobStatusCollection>.Success statusSuccess)
{
foreach (var job in statusSuccess.Data.Jobs)
{
Console.WriteLine($"Job {job.JobId}: {job.Status}");
}
}
}
// Wait for job completion (blocks up to ~10 minutes)
var completedResult = await sdkClient.Jobs.Query
.WithWait()
.WithDetailed()
.GetByTokenAsync(token);
// Query jobs by custom properties
var queryResult = await sdkClient.Jobs.Query
.WhereProperty("userId", JsonSerializer.SerializeToElement("12345"))
.WhereProperty("environment", JsonSerializer.SerializeToElement("production"))
.ExecuteAsync();
SDK - Coverage Service
using CivitaiSharp.Sdk;
using CivitaiSharp.Sdk.Air;
// Check if a model is available before submitting a job
var model = AirIdentifier.Parse("urn:air:sdxl:checkpoint:civitai:4201@130072");
var lora = AirIdentifier.Parse("urn:air:sdxl:lora:civitai:328553@368189");
// Check single model
var coverageResult = await sdkClient.Coverage.GetAsync(model);
if (coverageResult is Result<ProviderAssetAvailability>.Success coverage)
{
if (coverage.Data.Available)
{
Console.WriteLine("Model is available!");
foreach (var (provider, status) in coverage.Data.Providers)
{
Console.WriteLine($" {provider}: Queue position {status.QueuePosition}");
}
}
else
{
Console.WriteLine("Model not available on any provider");
}
}
// Check multiple resources at once
var resources = new[] { model, lora };
var batchResult = await sdkClient.Coverage.GetAsync(resources);
if (batchResult is Result<IReadOnlyDictionary<AirIdentifier, ProviderAssetAvailability>>.Success batch)
{
foreach (var (resource, availability) in batch.Data)
{
Console.WriteLine($"{resource}: {availability.Available}");
}
}
SDK - Usage Service
using CivitaiSharp.Sdk;
// Get current account usage
var usageResult = await sdkClient.Usage.GetConsumptionAsync();
if (usageResult is Result<ConsumptionDetails>.Success usage)
{
Console.WriteLine($"Total Jobs: {usage.Data.TotalJobs}");
Console.WriteLine($"Total Credits: {usage.Data.TotalCredits:F2}");
Console.WriteLine($"Period: {usage.Data.StartDate} to {usage.Data.EndDate}");
}
// Get usage for specific date range
var startDate = new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var endDate = new DateTime(2025, 1, 31, 23, 59, 59, DateTimeKind.Utc);
var monthlyResult = await sdkClient.Usage.GetConsumptionAsync(startDate, endDate);
if (monthlyResult is Result<ConsumptionDetails>.Success monthly)
{
Console.WriteLine($"January 2025:");
Console.WriteLine($" Jobs: {monthly.Data.TotalJobs}");
Console.WriteLine($" Credits: {monthly.Data.TotalCredits:F2}");
if (monthly.Data.JobsByType is not null)
{
Console.WriteLine(" Breakdown by type:");
foreach (var (jobType, count) in monthly.Data.JobsByType)
{
var credits = monthly.Data.CreditsByType?.GetValueOrDefault(jobType, 0) ?? 0;
Console.WriteLine($" {jobType}: {count} jobs, {credits:F2} credits");
}
}
}
Error Handling
var result = await client.Models.ExecuteAsync();
// Pattern matching
var message = result switch
{
{ IsSuccess: true, Value: var page } => $"Found {page.Items.Count} models",
{ IsSuccess: false, ErrorInfo: var error } => error.Code switch
{
ErrorCode.RateLimited => "Too many requests, please slow down",
ErrorCode.Unauthorized => "Invalid or missing API key",
ErrorCode.NotFound => "Resource not found",
_ => $"Error: {error.Code} - {error.Message}"
}
};
// Traditional approach
if (result.IsSuccess)
{
foreach (var model in result.Value.Items)
Console.WriteLine(model.Name);
}
else
{
Console.WriteLine($"Failed: {result.ErrorInfo.Message}");
}
6. Features
- Modern .NET 10 - Built with nullable reference types, records, and primary constructors
- AOT-Ready - Full Native AOT and trimming support with source-generated JSON serialization
- Fluent Query Builders - Type-safe, immutable, thread-safe builders for constructing API requests
- Result Pattern - Explicit success/failure handling without exceptions for expected errors
- Built-in Resilience - Standard resilience handler with retry policies, circuit breakers, rate limiting, and timeouts
- Dependency Injection - First-class support for
IHttpClientFactoryand Microsoft DI
AOT and Trimming Support
All CivitaiSharp packages are fully compatible with Native AOT compilation and IL trimming:
- Source-Generated JSON - Uses
System.Text.Jsonsource generators (JsonSerializerContext) for reflection-free serialization - Trim-Safe - All packages have
<IsAotCompatible>true</IsAotCompatible>and<EnableTrimAnalyzer>true</EnableTrimAnalyzer> - No Runtime Reflection - All type metadata is generated at compile-time
To publish with AOT:
dotnet publish -c Release -r win-x64 /p:PublishAot=true
To publish with trimming:
dotnet publish -c Release -r win-x64 /p:PublishTrimmed=true
7. Documentation
8. Known API Quirks
CivitaiSharp interacts with the Civitai.com API, which has several known quirks. Some are mitigated automatically; others are documented and under investigation.
| Issue | Description |
|---|---|
| Tags endpoint model count | Documented feature, but responses never include this field |
limit=0 parameter |
Documented to return all results for various endpoints, but returns an error |
| Semantic errors with HTTP 200 | Errors, Not Found, and others, all return HTTP 200 |
| Endpoint inconsistencies | Intermittent throttling, unreported outages, undocumented rate limits |
| Variable metadata structures | Metadata format varies widely between responses |
| User existence issues | During partial outages, existing users may appear nonexistent |
| Creator endpoint unreliability | See details below |
Creator Endpoint Reliability Issues
The /api/v1/creators endpoint is known to experience intermittent reliability issues:
- HTTP 500 errors: The endpoint frequently returns server errors, especially under load
- Slow response times: Requests may take significantly longer than other endpoints (10-30+ seconds)
- Timeout failures: Long response times can exceed client timeout thresholds
Recommendations:
- Implement generous timeouts: Set timeouts of 60-120 seconds for Creator endpoint requests
- Use retry logic: The built-in resilience handler will retry on 500 errors, but success is not guaranteed
- Handle failures gracefully: Your application should degrade gracefully when Creator data is unavailable
- Cache results aggressively: When requests succeed, cache the results to reduce API load
// Example: Handling Creator endpoint unreliability
var result = await client.Creators.ExecuteAsync(resultsLimit: 10);
if (!result.IsSuccess)
{
// Log the error but continue with degraded functionality
logger.LogWarning("Creator data unavailable: {Error}", result.ErrorInfo.Message);
return GetCachedCreators(); // Fallback to cached data
}
Additional quirks are being tracked and will be addressed in future releases.
9. Versioning
CivitaiSharp follows MAJOR.MINOR.PATCH semantic versioning:
| Component | Description |
|---|---|
| MAJOR | Significant, breaking API changes |
| MINOR | New features; may include limited breaking changes unlikely to affect most users |
| PATCH | Backwards-compatible bug fixes and improvements |
Pre-release versions use the format: MAJOR.MINOR.PATCH-alpha.N
Note: While in Alpha (0.x.x), APIs may change between minor versions. Stability is guaranteed from v1.0.0 onwards.
10. License
This repository is released under the MIT License.
11. Contributing
Contributions are welcome. Please read CONTRIBUTING.md for guidelines.
Legal Notice
CivitaiSharp is an independent open-source project and is not affiliated with, sponsored by, endorsed by, or officially associated with Civitai.com or Civitai, Inc. The Civitai name and any related trademarks are the property of their respective owners. Use of these names is for identification purposes only and does not imply any endorsement or partnership.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.Configuration (>= 10.0.0)
- Microsoft.Extensions.DependencyInjection (>= 10.0.0)
- Microsoft.Extensions.Http (>= 10.0.0)
- Microsoft.Extensions.Http.Resilience (>= 10.0.0)
- Microsoft.Extensions.Logging (>= 10.0.0)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on CivitaiSharp.Core:
| Package | Downloads |
|---|---|
|
CivitaiSharp.Sdk
PRE-ALPHA: This package is under active development and APIs may change significantly. Extended SDK for CivitaiSharp providing additional features for the Civitai.com API including AIR (Artificial Intelligence Resource) identifier parsing, image generation job management, and advanced model operations. Builds on CivitaiSharp.Core. CivitaiSharp is an independent open-source project and is not affiliated with, endorsed by, or associated with Civitai.com or Civitai, Inc. |
|
|
CivitaiSharp.Tools
PRE-ALPHA: This package is under active development and APIs may change significantly. Utility tools for CivitaiSharp including file hashing (BLAKE3, SHA256, SHA512, CRC32), download management with pattern-based file organization, HTML-to-Markdown/PlainText parsing for model descriptions, and file format detection. Builds on CivitaiSharp.Core. CivitaiSharp is an independent open-source project and is not affiliated with, endorsed by, or associated with Civitai.com or Civitai, Inc. |
GitHub repositories
This package is not used by any popular GitHub repositories.