C# SDK

C# / .NET Quick Start

WowSQL · WOWSQL.SDK · PostgreSQL REST API

Get your API keys: In your WowSQL project dashboard, go to Settings → API to find your anon key (wowsql_anon_...) and service role key (wowsql_service_...). The anon key is safe for client-side use (respects Row Level Security). The service role key bypasses RLS and should only be used server-side.

Installation

NuGet: WOWSQL.SDK on nuget.org →

.NET CLI:

dotnet add package WOWSQL.SDK

Package Manager:

Install-Package WOWSQL.SDK

PackageReference:

<PackageReference Include="WOWSQL.SDK" Version="2.0.0" />

Targets .NET Standard 2.0 (works with .NET Framework 4.6.1+ and .NET Core / 5+).

Namespace

All types are in using WOWSQL; — class names are WOWSQLClient, ProjectAuthClient, WOWSQLStorage, WOWSQLSchema.

Initialize database client

using WOWSQL;
using System.Collections.Generic;
using System.Threading.Tasks;

// URL resolves to: https://myproject.wowsqlconnect.com
// SDK talks to PostgREST at /rest/v1/
var client = new WOWSQLClient(
    projectUrl: "myproject",           // slug or full URL
    apiKey: "wowsql_anon_your_key_here",
    baseDomain: "wowsqlconnect.com",
    secure: true,
    timeout: 30,
    verifySsl: true
);

// Query: always Select() before GetAsync() on the builder
var users = await client.Table("users").Select("*").GetAsync();

Query data

Basic

var all = await client.Table("users").Select("*").GetAsync();

var adults = await client.Table("users").Select("*").Gte("age", 18).GetAsync();

var names = await client.Table("users").Select("id", "name").GetAsync();

Chained filters & paging

var active = await client.Table("users")
    .Select("*")
    .Eq("status", "active")
    .Gt("age", 18)
    .Order("created_at", "desc")
    .Limit(20)
    .Offset(0)
    .GetAsync();

System.Console.WriteLine($"Count: {active.Count}");
foreach (var row in active.Data)
    System.Console.WriteLine(row["name"]);

GROUP BY / HAVING (POST when needed)

var stats = await client.Table("products")
    .Select("category", "COUNT(*) as count", "AVG(price) as avg_price")
    .GroupBy("category")
    .Having("COUNT(*)", "gt", 10)
    .GetAsync();

CRUD

var created = await client.Table("users").CreateAsync(new Dictionary<string, object> {
    ["name"] = "Jane",
    ["email"] = "jane@example.com"
});
// created.Id, created.Message

await client.Table("users").UpdateAsync(created.Id, new Dictionary<string, object> {
    ["email"] = "new@example.com"
});

await client.Table("users").DeleteAsync(created.Id);

var one = await client.Table("users").GetByIdAsync(123);

var first = await client.Table("users").Eq("status", "active").FirstAsync();

Error handling

try
{
    var res = await client.Table("users").Select("*").GetAsync();
}
catch (WOWSQLException ex)
{
    if (ex.StatusCode == 401) { /* bad API key */ }
}
finally { client.Dispose(); }

// or
using (var c = new WOWSQLClient("myproject", "wowsql_anon_your_key_here"))
{
    var r = await c.Table("users").Select("*").GetAsync();
}

Authentication — ProjectAuthClient

Authentication endpoints are served at /auth/v1/. Use your anon key for client-side auth operations.

// Auth endpoints: POST /auth/v1/signup, POST /auth/v1/login
// Header: apikey: wowsql_anon_your_key_here
using (var auth = new ProjectAuthClient(
    projectUrl: "myproject",
    apiKey: "wowsql_anon_your_key_here",
    baseDomain: "wowsqlconnect.com"))
{
    var session = await auth.SignUpAsync(
        "user@example.com",
        "SecurePassword123!",
        "Full Name",
        new Dictionary<string, object> { ["k"] = "v" });

    auth.SetSession(session.Session.AccessToken, session.Session.RefreshToken);

    var login = await auth.SignInAsync("user@example.com", "SecurePassword123!");
    await auth.ForgotPasswordAsync("user@example.com");
}

OAuth Authentication

Setup checklist — do this once per provider, per project:
1. Dashboard → Project → Auth → Providers: enable the provider, paste Client ID and Client Secret (no leading/trailing spaces).
2. Copy the Redirect URI shown: https://<slug>.wowsqlconnect.com/auth/v1/oauth/<provider>/callback and register it in your provider's developer console.
3. The callback URL is handled entirely by WowSQL — your app does not send an API key on it. WowSQL exchanges the code and redirects to your frontend_redirect_uri with ?access_token=&refresh_token=.

using (var auth = new ProjectAuthClient(projectUrl: "myproject", apiKey: "wowsql_anon_your_key_here"))
{
    // ── Step 1: Get the authorization URL ────────────────────────────────────
    var oauth = await auth.GetOAuthAuthorizationUrlAsync(
        "google",
        "https://yourapp.com/auth/callback"
    );
    // Redirect the browser to oauth.AuthorizationUrl
    // Google calls: https://<slug>.wowsqlconnect.com/auth/v1/oauth/google/callback
    // WowSQL exchanges the code and redirects to your frontend_redirect_uri.

    // ── Step 2: Read tokens from the redirect ────────────────────────────────
    // WowSQL redirects to: https://yourapp.com/auth/callback?access_token=...&refresh_token=...

    // ── (Advanced) Manual code exchange — only if you handle the callback yourself
    var result = await auth.ExchangeOAuthCallbackAsync(
        "google",
        "authorization_code_from_callback",
        "https://yourapp.com/auth/callback"  // must match step 1
    );
    Console.WriteLine($"OAuth login successful: {result.User.Id}");
}

Storage — WOWSQLStorage (buckets)

Storage endpoints are served at /storage/v1/.

using (var storage = new WOWSQLStorage(
    projectUrl: "myproject",
    apiKey: "wowsql_service_your_key_here",
    baseDomain: "wowsqlconnect.com",
    timeout: 60))
{
    // Upload — POST /storage/v1/object/{bucket}/{path}
    var bucket = await storage.CreateBucketAsync("uploads", isPublic: false);
    var file = await storage.UploadFromPathAsync(@".\doc.pdf", "uploads", path: "docs/doc.pdf");

    // List — POST /storage/v1/object/list/{bucket}
    var files = await storage.ListFilesAsync("uploads", prefix: "docs/", limit: 100, offset: 0);

    // Public URL — GET /storage/v1/object/public/{bucket}/{path}
    var url = storage.GetPublicUrl("uploads", "docs/doc.pdf");

    // Download — GET /storage/v1/object/{bucket}/{path}
    var quota = await storage.GetQuotaAsync();
}

Schema — WOWSQLSchema (service key only)

Requires service role key. The API requires the primaryKey column to be type UUID (not SERIAL). Use ["type"] = "UUID" with ["auto_increment"] = true for DEFAULT gen_random_uuid(). Raw CREATE TABLE via ExecuteSQL must not use integer/SERIAL primary keys.

using (var schema = new WOWSQLSchema(
    projectUrl: "myproject",
    serviceKey: "wowsql_service_your_key_here",
    baseDomain: "wowsqlconnect.com"))
{
    await schema.CreateTableAsync("items", new List<Dictionary<string, object>> {
        new Dictionary<string, object> { ["name"] = "id", ["type"] = "UUID", ["auto_increment"] = true },
        new Dictionary<string, object> { ["name"] = "title", ["type"] = "TEXT" }
    }, primaryKey: "id");

    var tables = await schema.ListTablesAsync();
}

Catch SchemaPermissionException if a non-service key is used.

Example API Call (REST)

The SDK wraps PostgREST. Here's what the underlying HTTP calls look like:

Query (GET)

GET https://myproject.wowsqlconnect.com/rest/v1/users?select=id,email,name&status=eq.active&order=created_at.desc&limit=10
Headers:
  apikey: wowsql_anon_your_key_here
  Content-Type: application/json

Insert (POST)

POST https://myproject.wowsqlconnect.com/rest/v1/users
Headers:
  apikey: wowsql_anon_your_key_here
  Content-Type: application/json
  Prefer: return=representation

Body:
{
  "name": "John Doe",
  "email": "john@example.com",
  "age": 30
}

Update (PATCH)

PATCH https://myproject.wowsqlconnect.com/rest/v1/users?id=eq.123
Headers:
  apikey: wowsql_anon_your_key_here
  Content-Type: application/json
  Prefer: return=representation

Body:
{
  "email": "newemail@example.com"
}

Delete (DELETE)

DELETE https://myproject.wowsqlconnect.com/rest/v1/users?id=eq.123
Headers:
  apikey: wowsql_anon_your_key_here

NuGet package readme

Recent packages embed README.md so the gallery shows documentation. Unsigned packages show NU3004 under dotnet nuget verify — that is normal; publishing still works.

← All SDK docs