π .NET SDK β Quick Start¶
Get your first end-to-end flow running in minutes:
- Authenticate with API key
- Discover a Project and Service (or use environment variables)
- Upload a document
- Trigger processing
- Poll until done
- Extract and print results
NuGet: AIForged.SDK
Prerequisites¶
- .NET 6+ SDK
- An AIForged account with access to at least one Project and Service
- An API key
Unified access
No cloud-provider keys or regional setup required. AIForged is a unified access layerβyour AIForged account + API key is all you need.
Preferred classifier for new projects
If your first automation flow needs document classification, create an LLM Classifier service in AIForged Studio and point AIFORGED_SERVICE_ID at it. The LLM Classifier is the preferred classification service type for new projects.
Set environment variables (recommended)¶
Use environment variables to keep secrets out of source control and switch environments easily.
- AIFORGED_BASE_URL β Production API base URL: https://portal.aiforged.com
- AIFORGED_API_KEY β your API key
- AIFORGED_PROJECT_ID β optional; default project id for samples
- AIFORGED_SERVICE_ID β optional; default service id for samples
- AIFORGED_GROUP_ID β optional; default group for HITL (work items)
PowerShell:
$env:AIFORGED_BASE_URL = "https://portal.aiforged.com"
$env:AIFORGED_API_KEY = "β’β’β’"
# Optional shortcuts for this quick start
$env:AIFORGED_PROJECT_ID = "123"
$env:AIFORGED_SERVICE_ID = "456"
$env:AIFORGED_GROUP_ID = "789"
Bash/zsh:
export AIFORGED_BASE_URL="https://portal.aiforged.com"
export AIFORGED_API_KEY="β’β’β’"
export AIFORGED_PROJECT_ID="123"
export AIFORGED_SERVICE_ID="456"
export AIFORGED_GROUP_ID="789"
Optional (local dev) β .NET user secrets:
dotnet user-secrets set "AIFORGED_BASE_URL" "https://portal.aiforged.com"
dotnet user-secrets set "AIFORGED_API_KEY" "β’β’β’"
Security
- Treat your API key like a password. Donβt commit it to source control.
- Prefer environment variables or a secrets manager (Key Vault, AWS Secrets Manager).
- Never log the API key; redact secrets in telemetry.
Create a console app¶
mkdir aiforged-quickstart
cd aiforged-quickstart
dotnet new console
dotnet add package AIForged.SDK
Replace Program.cs with the code below, then run:
dotnet run
Program.cs (copy/paste)¶
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using AIForged.API;
class Program
{
static async Task<int> Main()
{
// 1) Read environment variables
var baseUrl = Env("AIFORGED_BASE_URL") ?? "https://portal.aiforged.com"; // production
var apiKey = Env("AIFORGED_API_KEY") ?? throw new Exception("AIFORGED_API_KEY not set.");
int? projectId = TryInt("AIFORGED_PROJECT_ID");
int? serviceId = TryInt("AIFORGED_SERVICE_ID");
// Optional: change file to your local test document
var filePath = "invoice.pdf";
// 2) Configure the SDK
var cfg = new Config
{
BaseUrl = baseUrl,
Timeout = TimeSpan.FromMinutes(5)
};
await cfg.Init(); // wires HttpClient/handler
cfg.HttpClient.DefaultRequestHeaders.Add("X-Api-Key", apiKey);
var ctx = new Context(cfg);
try
{
// 3) Verify we can call the API
var me = await ctx.GetCurrentUserAsync();
Console.WriteLine($"Connected as: {me?.Email ?? me?.UserName} ({me?.Id})");
// 4) Pick a Project and Service (env vars or auto-discover first available)
if (projectId == null || serviceId == null)
{
(projectId, serviceId) = await AutoDiscoverProjectAndServiceAsync(ctx);
if (projectId == null || serviceId == null)
throw new Exception("No accessible Project/Service found. Please set AIFORGED_PROJECT_ID and AIFORGED_SERVICE_ID.");
}
Console.WriteLine($"Using ProjectId={projectId}, ServiceId={serviceId}");
// 5) Upload a document
if (!File.Exists(filePath))
{
Console.WriteLine($"Sample file '{filePath}' not found. Create a PDF with this name or update filePath.");
return 0;
}
byte[] bytes = await File.ReadAllBytesAsync(filePath);
using var ms = new MemoryStream(bytes);
var fp = new FileParameter(ms, Path.GetFileName(filePath), "application/pdf");
var upload = await ctx.DocumentClient.UploadFileAsync(
stpdId: serviceId,
userId: ctx.CurrentUser.Id,
projectId: projectId,
classId: null,
status: DocumentStatus.Received,
usage: UsageType.Inbox,
masterid: null,
comment: "Quick Start upload",
externalId: $"QS-{Guid.NewGuid():N}",
result: null, resultId: null, resultIndex: null,
guid: Guid.NewGuid(),
data: fp
);
var doc = upload?.Result?.FirstOrDefault();
if (doc?.Id == null) throw new Exception("Upload failed: no document returned.");
Console.WriteLine($"Uploaded doc id: {doc.Id}");
// 6) Trigger processing
await ctx.ServicesClient.ProcessAsync(
userId: ctx.CurrentUser.Id,
projectId: projectId,
stpdId: serviceId,
docIds: new() { doc.Id }
);
Console.WriteLine("Processing started...");
// 7) Poll until done (simple exponential backoff)
var processed = await WaitUntilProcessedAsync(ctx, doc.Id, TimeSpan.FromMinutes(3));
if (processed == null)
{
Console.WriteLine("Timed out waiting for processing. Check status in Studio.");
return 0;
}
Console.WriteLine($"Final status: {processed.Status}");
if (processed.Status == DocumentStatus.Error)
{
Console.WriteLine("Document ended in Error. Review logs in Studio or via System/Log clients.");
return 0;
}
// 8) Extract and print results
var extraction = await ctx.ParametersClient.ExtractAsync(processed.Id);
Console.WriteLine("Results:");
foreach (var row in extraction?.Result ?? Enumerable.Empty<DocumentExtraction>())
{
Console.WriteLine($"- {row.Name}: {row.Value} (conf {row.Confidence})");
}
Console.WriteLine("Quick Start completed successfully!");
return 0;
}
catch (SwaggerException ex)
{
Console.Error.WriteLine($"API error {(int)ex.StatusCode} {ex.StatusCode}: {ex.Message}");
Console.Error.WriteLine($"Response: {ex.Response}");
if (ex.StatusCode == HttpStatusCode.Unauthorized || ex.StatusCode == HttpStatusCode.Forbidden)
Console.Error.WriteLine("Check X-Api-Key and permissions for the target project/service.");
return 1;
}
catch (Exception ex)
{
Console.Error.WriteLine($"Unexpected error: {ex}");
return 1;
}
}
static async Task<(int? projectId, int? serviceId)> AutoDiscoverProjectAndServiceAsync(Context ctx)
{
// Get all projects for the current user
var projects = await ctx.ProjectClient.GetByUserAsync(ctx.CurrentUser.Id, includeBalance: true);
var project = projects?.Result?.FirstOrDefault();
if (project == null) return (null, null);
// Get services in the selected project
var services = await ctx.ProjectClient.GetServicesAsync(ctx.CurrentUser.Id, project.Id, null, null);
var service = services?.Result?.FirstOrDefault();
if (service == null) return (project.Id, null);
return (project.Id, service.Id);
}
static async Task<DocumentViewModel?> WaitUntilProcessedAsync(Context ctx, int docId, TimeSpan timeout)
{
var sw = System.Diagnostics.Stopwatch.StartNew();
var delay = TimeSpan.FromSeconds(2);
while (sw.Elapsed < timeout)
{
var resp = await ctx.DocumentClient.GetDocumentAsync(docId);
var d = resp?.Result;
if (d == null) return null;
if (d.Status is DocumentStatus.Processed
or DocumentStatus.InterimProcessed
or DocumentStatus.Verification
or DocumentStatus.Error)
return d;
await Task.Delay(delay);
var next = Math.Min(delay.TotalSeconds * 1.5, 30); // cap at ~30s
delay = TimeSpan.FromSeconds(next);
}
return null;
}
static string? Env(string name) => Environment.GetEnvironmentVariable(name);
static int? TryInt(string name) => int.TryParse(Env(name), out var v) ? v : null;
}
Optional
If your project uses implicit usings or a different SDK style, no changes are needed. The code above targets .NET SDK defaults.
What just happened?¶
- Initialized the SDK with BaseUrl https://portal.aiforged.com and your API key (X-Api-Key).
- Confirmed connectivity by fetching the current user.
- Selected a Project and Service (from env vars, or auto-discovered the first available).
- Uploaded a PDF into Inbox with status Received.
- Triggered processing for that document.
- Polled until terminal status (Processed, InterimProcessed, Verification, or Error).
- Extracted results and printed them.
Roles required
To create/configure services, you need the Owner, Administrator, or Developer role in the target tenant. Viewing/processing may vary by your organizationβs RBAC policies.
Troubleshooting¶
-
401/403 Unauthorized/Forbidden
- Verify AIFORGED_BASE_URL and that the API key is valid and active.
- Ensure the key has access to the Project and Service.
-
404 Not Found
- Double-check ProjectId/ServiceId; avoid mixing environments (e.g., Studio vs API base).
-
Timeouts or large files
- Increase
Config.Timeout(e.g., 5β10 minutes for large PDFs). - Use retries with backoff for 429/5xx.
- Increase
-
Status remains Received
- Confirm Auto Execution isnβt disabled.
- Ensure the Service supports processing path for your document type.
Next steps
- Replace filePath with your own sample documents.
- Add minimal logging (ILogger) and trace IDs to correlate across services.
- Switch from polling to webhooks for production-scale flows.