// List + fetch AI transcripts from a CodeB tenant (.NET 6+). // European Digital Identity Wallet-enabled tenants use the same key surface. // [compliance-archive-cookbook 2026-07-23] // // Endpoints live-verified in signal.ashx: // GET signal.ashx?list-transcripts=1 // GET signal.ashx?get-transcript=.json using System; using System.IO; using System.Net.Http; using System.Net.Http.Headers; using System.Text.Json; using System.Threading.Tasks; class FetchTranscripts { static async Task Main() { var tenant = Environment.GetEnvironmentVariable("CODEB_TENANT") ?? "https://"; var apiKey = Environment.GetEnvironmentVariable("CODEB_API_KEY"); var outDir = Environment.GetEnvironmentVariable("OUT_DIR") ?? "./codeb-transcripts"; if (string.IsNullOrEmpty(apiKey)) { Console.Error.WriteLine("CODEB_API_KEY not set"); Environment.Exit(2); } Directory.CreateDirectory(outDir); using var http = new HttpClient { BaseAddress = new Uri(tenant) }; http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey); var idxJson = await http.GetStringAsync("/signal.ashx?list-transcripts=1"); using var doc = JsonDocument.Parse(idxJson); if (!doc.RootElement.TryGetProperty("items", out var items)) return; Console.WriteLine($"[list] {items.GetArrayLength()} transcripts"); foreach (var it in items.EnumerateArray()) { if (!it.TryGetProperty("file", out var f)) continue; var name = f.GetString(); if (string.IsNullOrEmpty(name)) continue; var body = await http.GetStringAsync("/signal.ashx?get-transcript=" + Uri.EscapeDataString(name)); await File.WriteAllTextAsync(Path.Combine(outDir, name), body); using var d = JsonDocument.Parse(body); int turns = d.RootElement.TryGetProperty("_transcriptTurns", out var t) ? t.GetArrayLength() : 0; Console.WriteLine($"[fetch] {name} turns={turns}"); } } }