Secret Key–Based Usage Rights Validation
Use the secret key validation endpoint when your application does not have a user login flow. Instead, the end user provides a Client Secret (a license key string) that they obtain from their Distancer.ai account. Your application sends this key to the API to verify usage rights.
This integration works from any external application stack that can send HTTPS requests, including desktop apps, CLIs, plugins, automation tools, and cross-platform clients.
Endpoint
POST api/v1/keyAuthentication: None required — this endpoint is anonymous.
Request
Headers
| Header | Value |
|---|---|
Content-Type |
application/json |
Body — ProductRightsKeyRequest
| Property | Type | Required | Constraints | Description |
|---|---|---|---|---|
ProductKeys |
string[] |
Yes | Each up to 150 characters | Array of product keys identifying the products to validate. |
ClientSecret |
string |
Yes | Up to 150 characters | The user’s secret key obtained from their Distancer.ai license management page. |
{
"ProductKeys": ["your-product-key-here"],
"ClientSecret": "user-secret-key-here"
}Product Key is the unique identifier for your product, hardcoded at build time.
Client Secret is a per-user key that the customer retrieves from their Distancer.ai license management page after purchasing your product. They paste it into your application’s settings.
Response — ProductRightsResponse
| Property | Type | Description |
|---|---|---|
UsageRights |
UsageRightsRecord[] |
List of usage rights matching the client secret and requested product keys. Empty array if no rights found. |
UsageRightsRecord
| Property | Type | Description |
|---|---|---|
ProductKey |
string? |
The product key this record applies to. |
LicensePayload |
string? |
Optional payload data your application can interpret, such as tier metadata or other app-specific context. |
TestLicense |
bool |
true if this is a sandbox/test license, false for production licenses. |
Example Response
{
"UsageRights": [
{
"ProductKey": "your-product-key",
"LicensePayload": "enterprise-tier",
"TestLicense": false
}
]
}If the client secret is invalid or has no active license:
{
"UsageRights": []
}Interpreting Entitlements in Your App
The API returns matching usage-rights data, but your application must decide what to enable.
- Use
ProductKeyto identify which product or variation the customer owns. - Use
LicensePayloadas optional metadata, not as a substitute for clear product modeling. - For different editions or feature combinations, create separate products in your Business Project.
- The recommended setup is a root product with child variation products for each app configuration.
This keeps entitlement logic explicit and lets your application map purchased products to the correct in-app behavior.
.NET Integration Example
Define the Models
public class ProductRightsKeyRequest
{
public string[] ProductKeys { get; set; } = [];
public string ClientSecret { get; set; } = string.Empty;
}
public class ProductRightsResponse
{
public List<UsageRightsRecord> UsageRights { get; set; } = [];
}
public class UsageRightsRecord
{
public string? ProductKey { get; set; }
public string? LicensePayload { get; set; }
public bool TestLicense { get; set; }
}Call the Endpoint
using System.Net.Http.Json;
public class DistancerLicenseClient
{
private readonly HttpClient _httpClient;
private const string BaseUrl = "https://appstore.distancer.ai/";
public DistancerLicenseClient(HttpClient httpClient)
{
_httpClient = httpClient;
_httpClient.BaseAddress = new Uri(BaseUrl);
}
public async Task<ProductRightsResponse?> ValidateByKeyAsync(
string[] productKeys, string clientSecret, CancellationToken ct = default)
{
var request = new ProductRightsKeyRequest
{
ProductKeys = productKeys,
ClientSecret = clientSecret
};
var response = await _httpClient.PostAsJsonAsync("api/v1/key", request, ct);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<ProductRightsResponse>(ct);
}
}Use in Your Application
var client = new DistancerLicenseClient(new HttpClient());
// clientSecret is provided by the user in your app's settings
var rights = await client.ValidateByKeyAsync(
productKeys: ["your-product-key"],
clientSecret: "user-provided-secret-key"
);
if (rights?.UsageRights.Count > 0)
{
var license = rights.UsageRights[0];
Console.WriteLine($"License active — Payload: {license.LicensePayload}");
}
else
{
Console.WriteLine("Invalid key or no active license.");
}Typical User Flow
- The customer purchases your product on Distancer.ai.
- They navigate to their license management page and copy the Client Secret.
- They paste the secret into your application’s settings or activation dialog.
- Your application calls
api/v1/keywith the secret to verify the license. - On success, your application inspects the returned rights and unlocks the correct features or edition.
When to Use Secret Key Validation
- Your application does not have its own login or authentication flow.
- You are building a desktop application, CLI tool, or plugin.
- You want a simple “paste your license key” activation model.
- You need to validate licenses without requiring the user to be online with a browser session.
If your app signs users in with Distancer.ai, use Login Validation instead. If you want to check for updates, use Product Version Check separately.
Related
- Login Validation — Use when the customer signs in with a Distancer.ai account.
- Product Version Check — Use separately to check the latest published version.
Security Considerations
- Treat the Client Secret as sensitive data. Store it securely in your application (e.g., encrypted configuration, OS credential store).
- Do not log the Client Secret. The API marks this field as sensitive.
- Cache validation results to avoid excessive API calls, but re-validate periodically (e.g., on application startup or every 24 hours).
Error Handling
| Scenario | Behavior |
|---|---|
| Invalid client secret | 200 OK with empty UsageRights array |
| Valid secret, no matching product keys | 200 OK with empty UsageRights array |
| Missing required fields | 400 Bad Request |
| Server error | null response — retry with exponential backoff |