WildwoodAPI Reference
Complete REST API documentation for WildwoodAPI — a .NET 9 backend providing authentication, AI services, user management, and security for multi-tenant applications.
https://localhost:7046. Check your launchSettings.json or
appsettings.json for the configured port.
"Swagger:Enabled": true in your appsettings.Development.json,
then navigate to /swagger. Swagger is disabled by default in production for security.
Authentication
WildwoodAPI uses JWT Bearer tokens for authentication. After logging in via
POST /api/auth/login, include the returned token in every subsequent request:
curl -X GET https://localhost:7046/api/ai/configurations \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json"
Authorization: Bearer {token} header unless explicitly
marked as Anonymous. Requests without a valid token receive a 401 Unauthorized response.
Multi-Tenant Scoping
WildwoodAPI is a multi-tenant platform. Every user belongs to one or more applications
identified by an AppId. When you log in, you pass the appId in the request body.
The JWT token returned contains embedded claims:
| Claim | Description |
|---|---|
sub |
User ID (unique identifier) |
email |
User's email address |
app_id |
Application ID the user authenticated against |
company_id |
Company the user belongs to |
role |
User roles (e.g., Admin, CompanyAdmin, User) |
All data queries are automatically scoped by these claims. A user can only access data belonging to their application and company.
Content Type
All request and response bodies use JSON. Set the Content-Type header to
application/json on every request that includes a body.
Common Response Format
Success Responses
Successful responses return the requested data directly in the body with an appropriate HTTP status code:
// 200 OK - Data returned
{
"id": "abc-123",
"firstName": "Jane",
"lastName": "Doe",
"email": "jane@example.com"
}
// 201 Created - Resource created (includes Location header)
// 204 No Content - Action succeeded with no body
Error Responses
Error responses follow a consistent JSON structure:
{
"error": "InvalidCredentials",
"message": "The email or password you entered is incorrect.",
"details": "Please check your password and try again."
}
| Field | Type | Description |
|---|---|---|
error |
string | Machine-readable error code (e.g., InvalidCredentials, UserNotFound) |
message |
string | Human-readable error message |
details |
string? | Optional additional context or guidance |
HTTP Status Codes
| Code | Meaning | When Used |
|---|---|---|
200 |
OK | Successful GET, PUT, POST, or DELETE |
201 |
Created | Resource successfully created (e.g., new session) |
400 |
Bad Request | Invalid input, validation failure, or malformed request |
401 |
Unauthorized | Missing or invalid JWT token |
403 |
Forbidden | Valid token but insufficient permissions (wrong role or app) |
404 |
Not Found | Requested resource does not exist |
409 |
Conflict | Resource already exists (e.g., duplicate email on registration) |
429 |
Too Many Requests | Rate limit exceeded (includes Retry-After header) |
500 |
Internal Server Error | Unexpected server error |
Rate Limiting
Certain endpoints enforce per-user rate limits. The AI chat endpoint (POST /api/ai/chat)
uses a PerUserAI rate limiting policy. When a limit is exceeded the API returns
429 Too Many Requests with a Retry-After header indicating how many
seconds to wait.
Token Refresh
JWT tokens expire after a configured duration. Use the POST /api/auth/refresh-token
endpoint with your refresh token to obtain a new JWT without re-authenticating. The refresh token
is also set as an httpOnly cookie named refreshToken.
Example: Full Login Flow
# 1. Login and obtain tokens
curl -X POST https://localhost:7046/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "YourPassword123!",
"appId": "d6e61c7a-eec5-4164-a004-9b99eb5eb6de",
"platform": "web",
"deviceInfo": "Chrome 120"
}'
# 2. Use the JWT token for authenticated requests
curl -X GET https://localhost:7046/api/ai/configurations \
-H "Authorization: Bearer eyJhbGciOi..."
# 3. Refresh the token when it expires
curl -X POST https://localhost:7046/api/auth/refresh-token \
-H "Content-Type: application/json" \
-d '{ "refreshToken": "abc123..." }'
// 1. Login and obtain tokens
var client = new HttpClient { BaseAddress = new Uri("https://localhost:7046") };
var loginRequest = new
{
email = "user@example.com",
password = "YourPassword123!",
appId = "d6e61c7a-eec5-4164-a004-9b99eb5eb6de",
platform = "web",
deviceInfo = "Console App"
};
var response = await client.PostAsJsonAsync("/api/auth/login", loginRequest);
var result = await response.Content.ReadFromJsonAsync<LoginResponse>();
// 2. Use the JWT token for authenticated requests
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", result.JwtToken);
var configs = await client.GetFromJsonAsync<List<AIConfiguration>>(
"/api/ai/configurations");
// 3. Refresh the token when it expires
var refreshResponse = await client.PostAsJsonAsync(
"/api/auth/refresh-token",
new { refreshToken = result.RefreshToken });
API Sections
Login, registration, token refresh, password reset, OAuth, and passkey endpoints.
AI chat, session management, configurations, and text-to-speech endpoints.
User profiles, password management, roles, and app associations.
Sessions, two-factor authentication, trusted devices, and passkey management.