// Jeton client_credentials puis lecture paginée des factures — .NET 6+ (HttpClient, System.Text.Json). // client_credentials token, then paginated invoice reads — .NET 6+ (HttpClient, System.Text.Json). using System; using System.Collections.Generic; using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Text.Json; using System.Threading.Tasks; public static class ClientCredentials { private const string ApiBase = "https://api.tauraco.io/public/v1"; private const string TokenUrl = "https://api.tauraco.io/oauth/token"; public static async Task GetTokenAsync(HttpClient http, string clientId, string clientSecret, string scope) { using var request = new HttpRequestMessage(HttpMethod.Post, TokenUrl) { Content = new FormUrlEncodedContent(new Dictionary { ["grant_type"] = "client_credentials", ["scope"] = scope, ["resource"] = ApiBase, }), }; request.Headers.Authorization = new AuthenticationHeaderValue( "Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes($"{clientId}:{clientSecret}"))); using var response = await http.SendAsync(request); using var payload = JsonDocument.Parse(await response.Content.ReadAsStringAsync()); if (!response.IsSuccessStatusCode) { throw new InvalidOperationException($"jeton refusé : {(int)response.StatusCode} {payload.RootElement.GetProperty("error")}"); } return payload.RootElement.GetProperty("access_token").GetString()!; } public static async Task Main() { using var http = new HttpClient(); var token = await GetTokenAsync(http, Environment.GetEnvironmentVariable("TAURACO_CLIENT_ID")!, Environment.GetEnvironmentVariable("TAURACO_CLIENT_SECRET")!, "invoices:read"); http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); string? cursor = null; do { var url = $"{ApiBase}/invoices?status=PAID&limit=100" + (cursor is null ? "" : $"&cursor={Uri.EscapeDataString(cursor)}"); using var page = JsonDocument.Parse(await http.GetStringAsync(url)); foreach (var invoice in page.RootElement.GetProperty("data").EnumerateArray()) { // Montants : chaînes décimales en unités majeures, à lire en decimal, jamais en double. Console.WriteLine($"{invoice.GetProperty("number")} {invoice.GetProperty("customer_name")} {invoice.GetProperty("total")} {invoice.GetProperty("currency")}"); } cursor = page.RootElement.GetProperty("has_more").GetBoolean() ? page.RootElement.GetProperty("next_cursor").GetString() : null; } while (cursor is not null); } }