using System.Net.Http.Headers; using System.Net.Http.Json; using System.Text.Json.Nodes; using System.Text.RegularExpressions; using var client = new DidbanClient(Environment.GetEnvironmentVariable("DIDBAN_API_URL") ?? "http://127.0.0.1:4321", Environment.GetEnvironmentVariable("DIDBAN_API_KEY") ?? ""); var invoice = await client.CreateInvoice("CS-ORDER-1001", "550680"); // Save id beside the permanent order identifier; redirect the customer to payment_url. Console.WriteLine("Payment URL: " + invoice["payment_url"]); var state = await client.GetInvoice(invoice["id"]!.GetValue()); Console.WriteLine($"Status: {state["status"]} | Requires review: {state["requires_review"]}"); // Only live invoices with a verified bank approval can report paid=true. Never fulfill an order from test_payment. sealed class DidbanClient : IDisposable { private readonly HttpClient http; public DidbanClient(string baseUrl, string apiKey) { var uri = new Uri(baseUrl, UriKind.Absolute); if (uri.UserInfo.Length > 0 || uri.Query.Length > 0 || uri.Fragment.Length > 0 || uri.AbsolutePath != "/" || !(uri.Scheme == "https" || uri.Scheme == "http" && (uri.Host == "localhost" || uri.Host == "127.0.0.1"))) throw new ArgumentException("Use an HTTPS origin or localhost."); if (!Regex.IsMatch(apiKey, @"\Adb_(test|live)_[A-Za-z0-9_-]{43}\z")) throw new ArgumentException("Invalid API key."); http = new HttpClient(new HttpClientHandler { AllowAutoRedirect = false }) { BaseAddress = uri, Timeout = TimeSpan.FromSeconds(20) }; http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey); http.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); } public Task CreateInvoice(string requestId, string amountRial, string presentation = "hosted", int? ttlMinutes = null) => Send(HttpMethod.Post, "/api/v1/invoices", new { request_id = requestId, amount_rial = amountRial, ttl_minutes = ttlMinutes, presentation }); public Task GetInvoice(string id) { if (!Regex.IsMatch(id, @"\A[0-9a-f-]{36}\z")) throw new ArgumentException("Invalid invoice ID."); return Send(HttpMethod.Get, "/api/v1/invoices/" + id, null); } public Task GetPaymentData(string id) { if (!Regex.IsMatch(id, @"\A[0-9a-f-]{36}\z")) throw new ArgumentException("Invalid invoice ID."); return Send(HttpMethod.Get, "/api/v1/invoices/" + id + "/payment-data", null); } public Task GetWallet() => Send(HttpMethod.Get, "/api/v1/wallet", null); private async Task Send(HttpMethod method, string path, object? body) { using var request = new HttpRequestMessage(method, path); if (body is not null) request.Content = JsonContent.Create(body); using var response = await http.SendAsync(request); if (!response.IsSuccessStatusCode) throw new HttpRequestException($"Didban HTTP {(int)response.StatusCode}"); return await response.Content.ReadFromJsonAsync() ?? throw new HttpRequestException("Invalid response."); } public void Dispose() => http.Dispose(); }