Phase 3: Organization Public Profile Page - Pinned repositories with groups - Public members display with roles - API endpoints for pinned repos and groups Phase 4: Gitea Pages Foundation - Landing page templates (simple, docs, product, portfolio) - Custom domain support with verification - YAML configuration parser (.gitea/landing.yaml) - Repository settings UI for pages Phase 5: Enhanced Wiki System with V2 API - Full CRUD operations via v2 API - Full-text search with WikiIndex table - Link graph visualization - Wiki health metrics (orphaned, dead links, outdated) - Designed for external AI plugin integration - Developer guide for .NET integration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
27 KiB
Gitea Wiki V2 API Developer Guide
For .NET Plugin Developers
This guide explains how to integrate with the Gitea Wiki V2 API from your .NET application. The V2 API provides structured, AI-friendly endpoints designed for external tool integration.
Table of Contents
Authentication
All write operations (create, update, delete) require authentication. Read operations on public repositories work without authentication.
Token Authentication
Use a personal access token in the Authorization header:
Authorization: token YOUR_ACCESS_TOKEN
Creating a Token
- Go to Gitea → Settings → Applications → Generate New Token
- Select scopes:
write:repository(for wiki access) - Copy the token and store securely
C# HttpClient Setup
var client = new HttpClient();
client.BaseAddress = new Uri("https://your-gitea-instance.com/api/v2/");
client.DefaultRequestHeaders.Add("Authorization", $"token {accessToken}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Base URL
https://{gitea-instance}/api/v2/repos/{owner}/{repo}/wiki
Replace:
{gitea-instance}- Your Gitea server domain{owner}- Repository owner (user or organization){repo}- Repository name
API Endpoints
List Wiki Pages
Returns all wiki pages with metadata.
GET /api/v2/repos/{owner}/{repo}/wiki/pages
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
page |
int | 1 | Page number (1-based) |
limit |
int | 30 | Items per page (max 100) |
Response: WikiPageListV2
{
"pages": [
{
"name": "Home",
"title": "Home",
"path": "Home.md",
"url": "https://gitea.example.com/api/v2/repos/owner/repo/wiki/pages/Home",
"html_url": "https://gitea.example.com/owner/repo/wiki/Home",
"word_count": 250,
"last_commit": {
"sha": "abc123...",
"message": "Update Home page",
"date": "2026-01-09T10:30:00Z",
"author": {
"name": "John Doe",
"email": "john@example.com"
}
}
}
],
"total_count": 15,
"has_more": false
}
Get Wiki Page
Returns a single page with full content, HTML rendering, and link information.
GET /api/v2/repos/{owner}/{repo}/wiki/pages/{pageName}
Response: WikiPageV2
{
"name": "Getting-Started",
"title": "Getting Started",
"path": "Getting-Started.md",
"url": "https://gitea.example.com/api/v2/repos/owner/repo/wiki/pages/Getting-Started",
"html_url": "https://gitea.example.com/owner/repo/wiki/Getting-Started",
"content": "# Getting Started\n\nWelcome to the project...",
"content_html": "<h1>Getting Started</h1>\n<p>Welcome to the project...</p>",
"word_count": 450,
"links_out": ["Installation", "Configuration", "FAQ"],
"links_in": ["Home", "README"],
"sidebar": "## Navigation\n- [[Home]]\n- [[Getting-Started]]",
"footer": "Copyright 2026",
"history_url": "https://gitea.example.com/api/v2/repos/owner/repo/wiki/pages/Getting-Started/revisions",
"last_commit": {
"sha": "def456...",
"message": "Add quick start section",
"date": "2026-01-08T14:22:00Z",
"author": {
"name": "Jane Smith",
"email": "jane@example.com"
},
"committer": {
"name": "Jane Smith",
"email": "jane@example.com"
}
}
}
Key Fields for AI Integration:
| Field | Description |
|---|---|
content |
Raw markdown content (use for AI processing) |
content_html |
Pre-rendered HTML (use for display) |
links_out |
Pages this page links to |
links_in |
Pages that link to this page |
word_count |
Word count for content analysis |
Create Wiki Page
Creates a new wiki page.
POST /api/v2/repos/{owner}/{repo}/wiki/pages
Request Body: CreateWikiPageV2Option
{
"name": "New-Feature",
"title": "New Feature Documentation",
"content": "# New Feature\n\nThis page documents the new feature...",
"message": "Add documentation for new feature"
}
| Field | Required | Description |
|---|---|---|
name |
Yes | Page name (used in URL, spaces become dashes) |
title |
No | Display title (defaults to name) |
content |
Yes | Markdown content |
message |
No | Commit message (auto-generated if empty) |
Response: Redirects to the created page (HTTP 302)
Update Wiki Page
Updates an existing wiki page. Can also rename the page.
PUT /api/v2/repos/{owner}/{repo}/wiki/pages/{pageName}
Request Body: UpdateWikiPageV2Option
{
"title": "Updated Title",
"content": "# Updated Content\n\nNew content here...",
"message": "Update page content",
"rename_to": "New-Page-Name"
}
| Field | Required | Description |
|---|---|---|
title |
No | New display title |
content |
No | New markdown content |
message |
No | Commit message |
rename_to |
No | New page name (renames the page) |
Response: Redirects to the updated page (HTTP 302)
Delete Wiki Page
Deletes a wiki page.
DELETE /api/v2/repos/{owner}/{repo}/wiki/pages/{pageName}
Response: WikiDeleteResponseV2
{
"success": true
}
Search Wiki
Full-text search across all wiki pages.
GET /api/v2/repos/{owner}/{repo}/wiki/search?q={query}
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
q |
string | required | Search query |
limit |
int | 20 | Max results (max 100) |
offset |
int | 0 | Skip N results |
Response: WikiSearchResponseV2
{
"query": "installation",
"results": [
{
"name": "Getting-Started",
"title": "Getting Started",
"snippet": "...Follow these steps for **installation**. First, download the package...",
"score": 8.5,
"word_count": 450,
"last_updated": "2026-01-08T14:22:00Z"
},
{
"name": "Installation",
"title": "Installation Guide",
"snippet": "# **Installation** Guide\n\nThis page covers all **installation** methods...",
"score": 12.3,
"word_count": 890,
"last_updated": "2026-01-05T09:15:00Z"
}
],
"total_count": 2
}
Score Calculation:
- Title match: +10 points
- Page name match: +8 points
- Content matches: +0.5 per occurrence
- Normalized by word count
Get Link Graph
Returns the wiki's link relationship graph (for visualization or analysis).
GET /api/v2/repos/{owner}/{repo}/wiki/graph
Response: WikiGraphV2
{
"nodes": [
{ "name": "Home", "title": "Home", "word_count": 250 },
{ "name": "Getting-Started", "title": "Getting Started", "word_count": 450 },
{ "name": "Installation", "title": "Installation Guide", "word_count": 890 },
{ "name": "Configuration", "title": "Configuration", "word_count": 320 }
],
"edges": [
{ "source": "Home", "target": "Getting-Started" },
{ "source": "Home", "target": "Installation" },
{ "source": "Getting-Started", "target": "Installation" },
{ "source": "Getting-Started", "target": "Configuration" },
{ "source": "Installation", "target": "Configuration" }
]
}
Use Cases:
- Build a visual wiki map
- Find navigation paths between pages
- Identify central/hub pages
- Detect isolated page clusters
Get Wiki Statistics
Returns comprehensive wiki statistics and health metrics.
GET /api/v2/repos/{owner}/{repo}/wiki/stats
Response: WikiStatsV2
{
"total_pages": 15,
"total_words": 12500,
"total_commits": 87,
"last_updated": "2026-01-09T10:30:00Z",
"contributors": 5,
"health": {
"orphaned_pages": [
{ "name": "Old-Feature", "word_count": 120 }
],
"dead_links": [
{ "page": "Getting-Started", "broken_link": "Deprecated-Page" }
],
"outdated_pages": [
{ "name": "Legacy-Setup", "last_edit": "2025-03-15T00:00:00Z", "days_old": 300 }
],
"short_pages": [
{ "name": "TODO", "word_count": 25 }
]
},
"top_linked": [
{ "name": "Home", "incoming_links": 12 },
{ "name": "Installation", "incoming_links": 8 },
{ "name": "Configuration", "incoming_links": 6 }
]
}
Health Metrics:
| Metric | Description |
|---|---|
orphaned_pages |
Pages with no incoming links (except Home) |
dead_links |
Links pointing to non-existent pages |
outdated_pages |
Pages not edited in 180+ days |
short_pages |
Pages with < 100 words |
Get Page Revisions
Returns the revision history for a specific page.
GET /api/v2/repos/{owner}/{repo}/wiki/pages/{pageName}/revisions
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
page |
int | 1 | Page number |
Response: WikiRevisionsV2
{
"page_name": "Getting-Started",
"revisions": [
{
"sha": "abc123...",
"message": "Add troubleshooting section",
"date": "2026-01-09T10:30:00Z",
"author": {
"name": "John Doe",
"email": "john@example.com"
}
},
{
"sha": "def456...",
"message": "Fix typo in installation steps",
"date": "2026-01-08T14:22:00Z",
"author": {
"name": "Jane Smith",
"email": "jane@example.com"
}
}
],
"total_count": 15
}
Data Models
C# Model Definitions
// Wiki Page (full details)
public class WikiPageV2
{
public string Name { get; set; }
public string Title { get; set; }
public string Path { get; set; }
public string Url { get; set; }
public string HtmlUrl { get; set; }
public string Content { get; set; }
public string ContentHtml { get; set; }
public int WordCount { get; set; }
public List<string> LinksOut { get; set; }
public List<string> LinksIn { get; set; }
public string Sidebar { get; set; }
public string Footer { get; set; }
public string HistoryUrl { get; set; }
public WikiCommitV2 LastCommit { get; set; }
}
// Wiki Commit
public class WikiCommitV2
{
public string Sha { get; set; }
public string Message { get; set; }
public DateTime Date { get; set; }
public WikiAuthorV2 Author { get; set; }
public WikiAuthorV2 Committer { get; set; }
}
// Wiki Author
public class WikiAuthorV2
{
public string Username { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string AvatarUrl { get; set; }
}
// Page List Response
public class WikiPageListV2
{
public List<WikiPageV2> Pages { get; set; }
public long TotalCount { get; set; }
public bool HasMore { get; set; }
}
// Search Result
public class WikiSearchResultV2
{
public string Name { get; set; }
public string Title { get; set; }
public string Snippet { get; set; }
public float Score { get; set; }
public int WordCount { get; set; }
public DateTime LastUpdated { get; set; }
}
// Search Response
public class WikiSearchResponseV2
{
public string Query { get; set; }
public List<WikiSearchResultV2> Results { get; set; }
public long TotalCount { get; set; }
}
// Graph Node
public class WikiGraphNodeV2
{
public string Name { get; set; }
public string Title { get; set; }
public int WordCount { get; set; }
}
// Graph Edge
public class WikiGraphEdgeV2
{
public string Source { get; set; }
public string Target { get; set; }
}
// Graph Response
public class WikiGraphV2
{
public List<WikiGraphNodeV2> Nodes { get; set; }
public List<WikiGraphEdgeV2> Edges { get; set; }
}
// Health Metrics
public class WikiHealthV2
{
public List<WikiOrphanedPageV2> OrphanedPages { get; set; }
public List<WikiDeadLinkV2> DeadLinks { get; set; }
public List<WikiOutdatedPageV2> OutdatedPages { get; set; }
public List<WikiShortPageV2> ShortPages { get; set; }
}
public class WikiOrphanedPageV2
{
public string Name { get; set; }
public int WordCount { get; set; }
}
public class WikiDeadLinkV2
{
public string Page { get; set; }
public string BrokenLink { get; set; }
}
public class WikiOutdatedPageV2
{
public string Name { get; set; }
public DateTime LastEdit { get; set; }
public int DaysOld { get; set; }
}
public class WikiShortPageV2
{
public string Name { get; set; }
public int WordCount { get; set; }
}
// Statistics Response
public class WikiStatsV2
{
public long TotalPages { get; set; }
public long TotalWords { get; set; }
public long TotalCommits { get; set; }
public DateTime LastUpdated { get; set; }
public long Contributors { get; set; }
public WikiHealthV2 Health { get; set; }
public List<WikiTopLinkedPageV2> TopLinked { get; set; }
}
public class WikiTopLinkedPageV2
{
public string Name { get; set; }
public int IncomingLinks { get; set; }
}
// Create/Update Options
public class CreateWikiPageV2Option
{
public string Name { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public string Message { get; set; }
}
public class UpdateWikiPageV2Option
{
public string Title { get; set; }
public string Content { get; set; }
public string Message { get; set; }
public string RenameTo { get; set; }
}
C# Example Code
Complete Wiki Client
using System.Net.Http.Json;
using System.Text.Json;
using System.Text.Json.Serialization;
public class GiteaWikiClient : IDisposable
{
private readonly HttpClient _client;
private readonly string _owner;
private readonly string _repo;
private readonly JsonSerializerOptions _jsonOptions;
public GiteaWikiClient(string baseUrl, string owner, string repo, string accessToken)
{
_owner = owner;
_repo = repo;
_client = new HttpClient
{
BaseAddress = new Uri(baseUrl.TrimEnd('/') + "/")
};
_client.DefaultRequestHeaders.Add("Authorization", $"token {accessToken}");
_jsonOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
}
private string WikiPath => $"api/v2/repos/{_owner}/{_repo}/wiki";
// List all pages
public async Task<WikiPageListV2> ListPagesAsync(int page = 1, int limit = 30)
{
var response = await _client.GetAsync($"{WikiPath}/pages?page={page}&limit={limit}");
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<WikiPageListV2>(_jsonOptions);
}
// Get a single page
public async Task<WikiPageV2> GetPageAsync(string pageName)
{
var response = await _client.GetAsync($"{WikiPath}/pages/{Uri.EscapeDataString(pageName)}");
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<WikiPageV2>(_jsonOptions);
}
// Create a new page
public async Task<WikiPageV2> CreatePageAsync(string name, string content, string title = null, string message = null)
{
var options = new CreateWikiPageV2Option
{
Name = name,
Title = title ?? name,
Content = content,
Message = message
};
var response = await _client.PostAsJsonAsync($"{WikiPath}/pages", options, _jsonOptions);
response.EnsureSuccessStatusCode();
// Follow redirect to get the created page
if (response.Headers.Location != null)
{
return await GetPageAsync(name);
}
return null;
}
// Update a page
public async Task<WikiPageV2> UpdatePageAsync(string pageName, string content = null, string title = null, string renameTo = null, string message = null)
{
var options = new UpdateWikiPageV2Option
{
Title = title,
Content = content,
Message = message,
RenameTo = renameTo
};
var response = await _client.PutAsJsonAsync($"{WikiPath}/pages/{Uri.EscapeDataString(pageName)}", options, _jsonOptions);
response.EnsureSuccessStatusCode();
var finalName = renameTo ?? pageName;
return await GetPageAsync(finalName);
}
// Delete a page
public async Task<bool> DeletePageAsync(string pageName)
{
var response = await _client.DeleteAsync($"{WikiPath}/pages/{Uri.EscapeDataString(pageName)}");
response.EnsureSuccessStatusCode();
return true;
}
// Search wiki
public async Task<WikiSearchResponseV2> SearchAsync(string query, int limit = 20, int offset = 0)
{
var url = $"{WikiPath}/search?q={Uri.EscapeDataString(query)}&limit={limit}&offset={offset}";
var response = await _client.GetAsync(url);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<WikiSearchResponseV2>(_jsonOptions);
}
// Get link graph
public async Task<WikiGraphV2> GetGraphAsync()
{
var response = await _client.GetAsync($"{WikiPath}/graph");
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<WikiGraphV2>(_jsonOptions);
}
// Get statistics
public async Task<WikiStatsV2> GetStatsAsync()
{
var response = await _client.GetAsync($"{WikiPath}/stats");
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<WikiStatsV2>(_jsonOptions);
}
// Get page revisions
public async Task<WikiRevisionsV2> GetRevisionsAsync(string pageName, int page = 1)
{
var url = $"{WikiPath}/pages/{Uri.EscapeDataString(pageName)}/revisions?page={page}";
var response = await _client.GetAsync(url);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<WikiRevisionsV2>(_jsonOptions);
}
public void Dispose()
{
_client?.Dispose();
}
}
Usage Examples
// Initialize client
using var wiki = new GiteaWikiClient(
baseUrl: "https://gitea.example.com",
owner: "myorg",
repo: "myproject",
accessToken: "your_token_here"
);
// List all pages
var pageList = await wiki.ListPagesAsync();
Console.WriteLine($"Found {pageList.TotalCount} wiki pages");
foreach (var page in pageList.Pages)
{
Console.WriteLine($"- {page.Title} ({page.WordCount} words)");
}
// Get a specific page
var page = await wiki.GetPageAsync("Getting-Started");
Console.WriteLine($"Content: {page.Content}");
Console.WriteLine($"Links to: {string.Join(", ", page.LinksOut)}");
Console.WriteLine($"Linked from: {string.Join(", ", page.LinksIn)}");
// Create a new page
var newPage = await wiki.CreatePageAsync(
name: "API-Reference",
content: "# API Reference\n\nThis page documents the API...",
title: "API Reference",
message: "Add API documentation"
);
// Update a page
var updated = await wiki.UpdatePageAsync(
pageName: "API-Reference",
content: "# API Reference\n\nUpdated content...",
message: "Update API docs"
);
// Rename a page
var renamed = await wiki.UpdatePageAsync(
pageName: "API-Reference",
renameTo: "API-Documentation",
message: "Rename API page"
);
// Search
var results = await wiki.SearchAsync("installation");
foreach (var result in results.Results)
{
Console.WriteLine($"Found: {result.Title} (score: {result.Score})");
Console.WriteLine($" {result.Snippet}");
}
// Get wiki health
var stats = await wiki.GetStatsAsync();
Console.WriteLine($"Wiki has {stats.TotalPages} pages with {stats.TotalWords} total words");
if (stats.Health.DeadLinks.Any())
{
Console.WriteLine("Broken links found:");
foreach (var deadLink in stats.Health.DeadLinks)
{
Console.WriteLine($" {deadLink.Page} -> {deadLink.BrokenLink}");
}
}
// Delete a page
await wiki.DeletePageAsync("Old-Page");
AI Function Calling Integration
If you're using the wiki with AI function calling (e.g., OpenAI, Azure OpenAI):
// Define functions for AI
var functions = new[]
{
new
{
name = "search_wiki",
description = "Search the project wiki for information",
parameters = new
{
type = "object",
properties = new
{
query = new { type = "string", description = "Search query" }
},
required = new[] { "query" }
}
},
new
{
name = "get_wiki_page",
description = "Get the full content of a wiki page",
parameters = new
{
type = "object",
properties = new
{
page_name = new { type = "string", description = "Name of the wiki page" }
},
required = new[] { "page_name" }
}
},
new
{
name = "create_wiki_page",
description = "Create a new wiki page",
parameters = new
{
type = "object",
properties = new
{
name = new { type = "string", description = "Page name" },
content = new { type = "string", description = "Markdown content" },
message = new { type = "string", description = "Commit message" }
},
required = new[] { "name", "content" }
}
},
new
{
name = "get_wiki_stats",
description = "Get wiki statistics including health metrics",
parameters = new { type = "object", properties = new { } }
}
};
// Handle function calls
async Task<string> HandleFunctionCall(string functionName, JsonElement arguments)
{
switch (functionName)
{
case "search_wiki":
var query = arguments.GetProperty("query").GetString();
var results = await wiki.SearchAsync(query);
return JsonSerializer.Serialize(results);
case "get_wiki_page":
var pageName = arguments.GetProperty("page_name").GetString();
var page = await wiki.GetPageAsync(pageName);
return JsonSerializer.Serialize(page);
case "create_wiki_page":
var name = arguments.GetProperty("name").GetString();
var content = arguments.GetProperty("content").GetString();
var message = arguments.TryGetProperty("message", out var msg) ? msg.GetString() : null;
var newPage = await wiki.CreatePageAsync(name, content, message: message);
return JsonSerializer.Serialize(newPage);
case "get_wiki_stats":
var stats = await wiki.GetStatsAsync();
return JsonSerializer.Serialize(stats);
default:
throw new ArgumentException($"Unknown function: {functionName}");
}
}
Error Handling
Error Response Format
All errors return a consistent JSON structure:
{
"error": {
"code": "WIKI_PAGE_NOT_FOUND",
"message": "Wiki page not found",
"details": {}
}
}
Error Codes
| Code | HTTP Status | Description |
|---|---|---|
WIKI_PAGE_NOT_FOUND |
404 | The requested page doesn't exist |
WIKI_PAGE_ALREADY_EXISTS |
409 | A page with that name already exists |
WIKI_RESERVED_NAME |
400 | The page name is reserved (e.g., _Sidebar) |
WIKI_DISABLED |
403 | Wiki is disabled for this repository |
AUTH_TOKEN_MISSING |
401 | No authentication token provided |
REPO_NOT_FOUND |
404 | Repository doesn't exist |
REPO_ARCHIVED |
403 | Repository is archived (read-only) |
ACCESS_DENIED |
403 | Insufficient permissions |
C# Error Handling
public class GiteaApiException : Exception
{
public string ErrorCode { get; }
public int StatusCode { get; }
public GiteaApiException(string code, string message, int statusCode)
: base(message)
{
ErrorCode = code;
StatusCode = statusCode;
}
}
// In your client methods:
public async Task<WikiPageV2> GetPageAsync(string pageName)
{
var response = await _client.GetAsync($"{WikiPath}/pages/{Uri.EscapeDataString(pageName)}");
if (!response.IsSuccessStatusCode)
{
var error = await response.Content.ReadFromJsonAsync<ErrorResponse>(_jsonOptions);
throw new GiteaApiException(
error?.Error?.Code ?? "UNKNOWN",
error?.Error?.Message ?? "Unknown error",
(int)response.StatusCode
);
}
return await response.Content.ReadFromJsonAsync<WikiPageV2>(_jsonOptions);
}
// Usage:
try
{
var page = await wiki.GetPageAsync("NonExistent");
}
catch (GiteaApiException ex) when (ex.ErrorCode == "WIKI_PAGE_NOT_FOUND")
{
Console.WriteLine("Page doesn't exist, creating it...");
await wiki.CreatePageAsync("NonExistent", "# New Page");
}
Best Practices
1. Page Naming
- Use URL-friendly names:
Getting-Started, notGetting Started - Avoid special characters:
/,\,?,#,% - Keep names concise but descriptive
- The API automatically converts spaces to dashes
2. Content Format
- Use standard Markdown
- Wiki links:
[[Page-Name]]or[[Page-Name|Display Text]] - Relative links:
[text](./Other-Page)or[text](Other-Page) - The API extracts both formats for the
links_outfield
3. Commit Messages
- Always provide meaningful commit messages
- If omitted, auto-generated: "Add {page}" or "Update {page}"
- Good for audit trail and history
4. Rate Limiting
- Be mindful of API rate limits
- Cache responses when appropriate
- Use pagination for large wikis
5. Indexing
- The wiki is automatically indexed for search
- First access may trigger background indexing
- Stats and graph endpoints trigger re-indexing if needed
6. Error Recovery
// Retry logic for transient failures
public async Task<T> WithRetryAsync<T>(Func<Task<T>> action, int maxRetries = 3)
{
for (int i = 0; i < maxRetries; i++)
{
try
{
return await action();
}
catch (HttpRequestException) when (i < maxRetries - 1)
{
await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, i)));
}
}
throw new Exception("Max retries exceeded");
}
// Usage:
var page = await WithRetryAsync(() => wiki.GetPageAsync("Home"));
Support
For issues with the Wiki V2 API:
- Check the Gitea documentation
- Report bugs at the Gitea repository
- For .NET client issues, check your authentication and base URL
Document Version: 1.0 | API Version: v2 | Last Updated: January 2026