Getting Started in C
There are two ways to call the DocMgt REST API from .NET. The recommended way is the DocMgt.RESTHelper NuGet package, which wraps every endpoint in a typed C# method so you never build a URL or parse JSON yourself. The other way is plain HTTP with HttpClient, which works from any language and is shown alongside the helper in each article for readers who are not on .NET. Both talk to the same endpoints under https://yoursite.docmgt.com/rest/v2/.
Install the helper
dotnet add package DocMgt.RESTHelper
Version 5.x of the package targets .NET 8 or later. A project on .NET Framework 4.7.2 or .NET Standard 2.0 must stay on the 4.x line, which is synchronous and uses the older DocMgt namespace. Everything below is written for 5.x.
Connect
Create one dmRestHelper per unit of work and dispose it when you are done. The first argument is your site's base URL with no path after the host. Prefer an API token; a username and password also work unless the site has turned password authentication off.
using DocMgt.RESTHelper;
// Recommended: an API token issued from Admin > Security > API Tokens
using var client = dmRestHelper.CreateWithApiToken("https://yoursite.docmgt.com", "dmapi_your_token_here");
// Alternative: username and password
using var client2 = new dmRestHelper("https://yoursite.docmgt.com", "someuser", "somepassword");
You do not have to call LoginAsync before other calls. Every call carries the credential, and the helper detects your server version on the first call and picks the v2 endpoints automatically. A cheap connection test is GetInfoAsync, which returns the server's URL and version and fails fast with a clear message when the URL or credential is wrong.
The async part, explained
Every method on the 5.x helper ends in Async and returns a Task or a Task<T>. A Task<T> is not the result; it is a promise that a result will arrive once the HTTP call finishes. You get the actual value by putting await in front of the call, and await is only allowed inside a method marked async.
This is the mistake that costs people the most time. It compiles, and it never returns a record ID:
// WRONG: sRecordID is a Task<string>, not a string, and the call has not finished yet
Task<string> sRecordID = GetVendorRecordByVendorID(recordType, vendorID);
The correct form is one word longer. The await unwraps the task and hands you the string, and any exception thrown inside the call surfaces here where your try and catch can see it:
// RIGHT
string sRecordID = await GetVendorRecordByVendorID(recordType, vendorID);
Three rules keep this simple. First, a method that awaits must be declared async and should return Task or Task<T> rather than void or a plain value. Second, go "async all the way up": the caller of an async method awaits it too, right up to static async Task Main(string[] args), which C# has supported since 7.1. Third, if you truly cannot make a caller async, for example an old event handler or a library interface you do not own, bridge with .GetAwaiter().GetResult() on the task rather than .Result or .Wait(), and only do that in console programs or background services. In a Windows Forms or WPF application blocking on a task from the UI thread can deadlock, so make the event handler async void and await inside it instead.
A complete console program that connects and prints the server version looks like this:
using DocMgt.RESTHelper;
class Program
{
static async Task Main(string[] args)
{
using var client = dmRestHelper.CreateWithApiToken("https://yoursite.docmgt.com", "dmapi_your_token_here");
var info = await client.GetInfoAsync();
Console.WriteLine($"Connected to {info.URL}, server version {info.Version}");
}
}
Handle errors
When the server answers with anything other than success, the helper throws a DocMgtRestException. Its StatusCode property carries the HTTP status and its Message carries the server's explanation, so catch it separately from everything else and log both. A 401 means the credential was refused, a 403 means the user is valid but lacks rights to that operation, and a 404 means the record or document does not exist or the user cannot see it. Network failures and timeouts arrive as a plain Exception whose message begins with "Communicating".
try
{
var record = await client.GetRecordAsync(123);
}
catch (DocMgtRestException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
{
Console.WriteLine("Record 123 does not exist or is not visible to this user");
}
catch (DocMgtRestException ex)
{
Console.WriteLine($"DocMgt returned {(int)ex.StatusCode}: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"Could not reach the server: {ex.Message}");
}
Always write the exception message somewhere you will read it. An integration that swallows the exception and returns an empty string looks exactly like an integration that found nothing, and the two problems have completely different fixes.
Paging
Every search method takes a pageNum and numPerPage and returns one page. After any search the helper's NumResults property holds the total number of matches across all pages, so a loop that needs everything checks it after the first page. Keep pages modest; 25 to 100 is typical.
var page = 1;
var all = new List<Record>();
do
{
var batch = await client.SearchRecordsAsync("invoice", pageNum: page, numPerPage: 100);
all.AddRange(batch);
page++;
} while (all.Count < client.NumResults);
Calling the API without the helper
Every endpoint is ordinary JSON over HTTPS, so any language works. Send the credential in the Authorization header on every request, ask for JSON with Accept: application/json, and send request bodies as Content-Type: application/json. The site's Swagger page at https://yoursite.docmgt.com/swagger lists every endpoint with its request and response shapes and has an Authorize button that accepts both token and password credentials, which makes it the fastest place to try a call before writing code. The articles that follow show the raw request next to each helper call.
TIPS
- Await every helper call. If a variable's type shows as Task<...> in the editor, an await is missing.
- Prefer an API token over a username and password. Tokens keep working when the site turns password authentication off.
- Log ex.Message on every catch. The server's explanation is in it.
- Test the URL and credential with GetInfoAsync first, before you debug anything else.
- Use one dmRestHelper for a batch of calls, not one per call, so the version detection and any session reuse happen once.