Bulk Queries API
Validate, lookup, and search multiple licenses in a single API call. Query by activation key, customer email, or hardware ID.
How do I query multiple licenses at once?
The ExisOne Bulk Queries API lets you validate, lookup, or search up to 100 licenses in a single HTTP request. Instead of making 100 separate API calls, you can:
- Bulk Validate - Check if multiple licenses are valid for specific hardware IDs
- Bulk Info - Get detailed information for multiple activation keys
- Bulk by Email - Find all licenses for multiple customer email addresses
- Bulk by Hardware - Find all licenses for multiple devices
This is ideal for enterprise dashboards, CRM integrations, device fleet management, and customer support tools.
Overview
The Bulk Queries API allows you to perform batch operations on licenses, reducing API calls and improving performance for enterprise applications.
Bulk Validate
Validate multiple licenses with hardware binding
POST /api/license/validate-bulk
Bulk Info
Get details for multiple activation keys
POST /api/license/bulk-info
Bulk by Email
Get all licenses for multiple customers
POST /api/license/bulk-by-email
Bulk by Hardware
Get licenses for multiple devices
POST /api/license/bulk-by-hardware
Use Cases
- Enterprise dashboards displaying license status for multiple customers
- CRM integrations syncing license data for customer accounts
- Device management checking licenses across a fleet of machines
- Batch validation at application startup for multi-license systems
- Customer support tools looking up all licenses for a customer
Authentication
Include your API token in the Authorization header:
Authorization: ExisOneApi your-api-token
Required Permissions
| Endpoint | Required Permission |
|---|---|
/api/license/validate-bulk |
verify |
/api/license/bulk-info |
Any valid token |
/api/license/bulk-by-email |
Any valid token |
/api/license/bulk-by-hardware |
Any valid token |
Endpoints
Bulk Validate Licenses
POST /api/license/validate-bulk
Validates multiple licenses against hardware IDs. Use this when you need to check if licenses are currently valid and active.
Request Body
{
"licenses": [
{
"activationKey": "XXXX-XXXX-XXXX-XXXX",
"hardwareId": "ABC123DEF456..."
},
{
"activationKey": "YYYY-YYYY-YYYY-YYYY",
"hardwareId": "DEF789GHI012..."
},
{
"hardwareId": "GHI345JKL678...",
"productName": "MyProduct"
}
]
}
Response
{
"results": [
{
"activationKey": "XXXX-XXXX-XXXX-XXXX",
"hardwareId": "ABC123DEF456...",
"isValid": true,
"status": "licensed",
"error": null,
"expirationDate": "2026-01-01T23:59:59Z",
"features": ["Feature1", "Feature2"]
}
],
"totalProcessed": 3,
"successCount": 2,
"failureCount": 1
}
Bulk Info by Activation Keys
POST /api/license/bulk-info
Gets detailed information for multiple licenses by their activation keys. Use this when you know the keys and need full license details.
Request Body
{
"activationKeys": [
"XXXX-XXXX-XXXX-XXXX",
"YYYY-YYYY-YYYY-YYYY",
"ZZZZ-ZZZZ-ZZZZ-ZZZZ"
]
}
Response
{
"licenses": [
{
"activationKey": "XXXX-XXXX-XXXX-XXXX",
"found": true,
"email": "customer@example.com",
"productName": "MyProduct",
"productId": 123,
"hardwareId": "ABC123...",
"isActive": true,
"activationDate": "2025-01-15T10:30:00Z",
"expirationDate": "2026-01-15T23:59:59Z",
"createdAt": "2025-01-10T08:00:00Z",
"note": "Enterprise customer",
"features": ["Feature1", "Feature2", "Pro"],
"isCorporate": false,
"maxSeats": null,
"currentSeats": null,
"corporateName": null,
"isOffline": false
},
{
"activationKey": "INVALID-KEY",
"found": false
}
],
"totalRequested": 3,
"foundCount": 2,
"notFoundCount": 1
}
Bulk by Customer Email
POST /api/license/bulk-by-email
Gets all licenses for multiple customer email addresses. Use this for customer support tools or CRM integrations.
Request Body
{
"emails": [
"customer1@example.com",
"customer2@example.com",
"enterprise@company.com"
]
}
Response
{
"customers": [
{
"email": "customer1@example.com",
"licenses": [
{
"activationKey": "XXXX-XXXX-XXXX-XXXX",
"found": true,
"productName": "MyProduct",
"isActive": true,
"expirationDate": "2026-01-15T23:59:59Z",
"features": ["Feature1", "Feature2"]
// ... full license details
},
{
"activationKey": "AAAA-AAAA-AAAA-AAAA",
"found": true,
"productName": "OtherProduct",
"isActive": false,
"expirationDate": "2024-06-01T23:59:59Z",
"features": ["Basic"]
}
],
"licenseCount": 2
},
{
"email": "newcustomer@example.com",
"licenses": [],
"licenseCount": 0
}
],
"totalCustomers": 3,
"totalLicenses": 5
}
Bulk by Hardware ID
POST /api/license/bulk-by-hardware
Gets all licenses associated with multiple hardware IDs. Use this for device fleet management or multi-machine deployments.
Request Body
{
"hardwareIds": [
"ABC123DEF456GHI789...",
"JKL012MNO345PQR678...",
"STU901VWX234YZA567..."
]
}
Response
{
"devices": [
{
"hardwareId": "ABC123DEF456GHI789...",
"licenses": [
{
"activationKey": "XXXX-XXXX-XXXX-XXXX",
"found": true,
"email": "customer@example.com",
"productName": "MyProduct",
"isActive": true,
"expirationDate": "2026-01-15T23:59:59Z",
"features": ["Feature1", "Feature2"],
"isCorporate": false
}
],
"licenseCount": 1
},
{
"hardwareId": "JKL012MNO345PQR678...",
"licenses": [
{
"activationKey": "CORP-XXXX-XXXX-XXXX",
"found": true,
"email": "enterprise@company.com",
"productName": "MyProduct",
"isActive": true,
"isCorporate": true,
"maxSeats": 50,
"currentSeats": 23,
"corporateName": "Acme Corporation"
}
],
"licenseCount": 1
},
{
"hardwareId": "UNKNOWN-HARDWARE-ID",
"licenses": [],
"licenseCount": 0
}
],
"totalDevices": 3,
"totalLicenses": 2
}
Response Fields
License Info Object
| Field | Type | Description |
|---|---|---|
activationKey | string | The license activation key |
found | boolean | Whether the license was found in the system |
email | string? | Customer email associated with the license |
productName | string? | Name of the licensed product |
productId | int? | Internal product ID |
hardwareId | string? | Hardware ID the license is bound to |
isActive | boolean | Whether the license is currently activated |
activationDate | datetime? | When the license was activated |
expirationDate | datetime? | When the license expires |
createdAt | datetime? | When the license was created |
note | string? | Admin notes on the license |
features | string[] | Array of enabled feature names |
isCorporate | boolean | Whether this is a multi-seat corporate license |
maxSeats | int? | Maximum allowed seats (corporate only) |
currentSeats | int? | Currently used seats (corporate only) |
corporateName | string? | Company name (corporate only) |
isOffline | boolean | Whether this is an offline license |
Validation Status Codes
These status codes are returned by the /validate-bulk endpoint:
| Status | Valid | Description |
|---|---|---|
licensed |
Yes | License is active and valid for this hardware |
trial |
Yes | Trial period is active |
expired |
No | License or trial has expired |
invalid |
No | License is invalid (hardware mismatch, inactive, etc.) |
invalid_key |
No | Activation key does not exist |
invalid_product |
No | Activation key is for a different product |
trial_unavailable |
No | Trial is not available for this product |
invalid_request |
No | Missing required fields in the request |
error |
No | An unexpected error occurred |
Code Examples
using System.Net.Http;
using System.Net.Http.Json;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "ExisOneApi your-api-token");
// Bulk Validate
var validateRequest = new {
licenses = new[] {
new { activationKey = "XXXX-XXXX-XXXX-XXXX", hardwareId = "ABC123..." },
new { activationKey = "YYYY-YYYY-YYYY-YYYY", hardwareId = "DEF456..." }
}
};
var validateResponse = await client.PostAsJsonAsync(
"https://api.exisone.com/api/license/validate-bulk", validateRequest);
// Bulk Info by Keys
var infoRequest = new {
activationKeys = new[] { "XXXX-XXXX-XXXX-XXXX", "YYYY-YYYY-YYYY-YYYY" }
};
var infoResponse = await client.PostAsJsonAsync(
"https://api.exisone.com/api/license/bulk-info", infoRequest);
// Bulk by Email
var emailRequest = new {
emails = new[] { "customer1@example.com", "customer2@example.com" }
};
var emailResponse = await client.PostAsJsonAsync(
"https://api.exisone.com/api/license/bulk-by-email", emailRequest);
// Bulk by Hardware
var hardwareRequest = new {
hardwareIds = new[] { "ABC123...", "DEF456..." }
};
var hardwareResponse = await client.PostAsJsonAsync(
"https://api.exisone.com/api/license/bulk-by-hardware", hardwareRequest);
import requests
headers = {
"Authorization": "ExisOneApi your-api-token",
"Content-Type": "application/json"
}
base_url = "https://api.exisone.com/api/license"
# Bulk Validate
validate_response = requests.post(f"{base_url}/validate-bulk", json={
"licenses": [
{"activationKey": "XXXX-XXXX-XXXX-XXXX", "hardwareId": "ABC123..."},
{"activationKey": "YYYY-YYYY-YYYY-YYYY", "hardwareId": "DEF456..."}
]
}, headers=headers)
# Bulk Info by Keys
info_response = requests.post(f"{base_url}/bulk-info", json={
"activationKeys": ["XXXX-XXXX-XXXX-XXXX", "YYYY-YYYY-YYYY-YYYY"]
}, headers=headers)
# Bulk by Email
email_response = requests.post(f"{base_url}/bulk-by-email", json={
"emails": ["customer1@example.com", "customer2@example.com"]
}, headers=headers)
# Bulk by Hardware
hardware_response = requests.post(f"{base_url}/bulk-by-hardware", json={
"hardwareIds": ["ABC123...", "DEF456..."]
}, headers=headers)
# Process results
for customer in email_response.json()["customers"]:
print(f"{customer['email']}: {customer['licenseCount']} licenses")
for lic in customer["licenses"]:
print(f" - {lic['productName']}: {'Active' if lic['isActive'] else 'Inactive'}")
const headers = {
'Authorization': 'ExisOneApi your-api-token',
'Content-Type': 'application/json'
};
const baseUrl = 'https://api.exisone.com/api/license';
// Bulk Validate
const validateResponse = await fetch(`${baseUrl}/validate-bulk`, {
method: 'POST',
headers,
body: JSON.stringify({
licenses: [
{ activationKey: 'XXXX-XXXX-XXXX-XXXX', hardwareId: 'ABC123...' },
{ activationKey: 'YYYY-YYYY-YYYY-YYYY', hardwareId: 'DEF456...' }
]
})
});
// Bulk Info by Keys
const infoResponse = await fetch(`${baseUrl}/bulk-info`, {
method: 'POST',
headers,
body: JSON.stringify({
activationKeys: ['XXXX-XXXX-XXXX-XXXX', 'YYYY-YYYY-YYYY-YYYY']
})
});
// Bulk by Email
const emailResponse = await fetch(`${baseUrl}/bulk-by-email`, {
method: 'POST',
headers,
body: JSON.stringify({
emails: ['customer1@example.com', 'customer2@example.com']
})
});
// Bulk by Hardware
const hardwareResponse = await fetch(`${baseUrl}/bulk-by-hardware`, {
method: 'POST',
headers,
body: JSON.stringify({
hardwareIds: ['ABC123...', 'DEF456...']
})
});
// Process results
const emailData = await emailResponse.json();
for (const customer of emailData.customers) {
console.log(`${customer.email}: ${customer.licenseCount} licenses`);
}
# Bulk Validate
curl -X POST https://api.exisone.com/api/license/validate-bulk \
-H "Authorization: ExisOneApi your-api-token" \
-H "Content-Type: application/json" \
-d '{"licenses": [{"activationKey": "XXXX-XXXX-XXXX-XXXX", "hardwareId": "ABC123..."}]}'
# Bulk Info by Keys
curl -X POST https://api.exisone.com/api/license/bulk-info \
-H "Authorization: ExisOneApi your-api-token" \
-H "Content-Type: application/json" \
-d '{"activationKeys": ["XXXX-XXXX-XXXX-XXXX", "YYYY-YYYY-YYYY-YYYY"]}'
# Bulk by Email
curl -X POST https://api.exisone.com/api/license/bulk-by-email \
-H "Authorization: ExisOneApi your-api-token" \
-H "Content-Type: application/json" \
-d '{"emails": ["customer1@example.com", "customer2@example.com"]}'
# Bulk by Hardware
curl -X POST https://api.exisone.com/api/license/bulk-by-hardware \
-H "Authorization: ExisOneApi your-api-token" \
-H "Content-Type: application/json" \
-d '{"hardwareIds": ["ABC123...", "DEF456..."]}'
Rate Limits
Limits by Endpoint
| Endpoint | Max Items | Notes |
|---|---|---|
/validate-bulk |
100 licenses | Each license validated and logged |
/bulk-info |
100 keys | Read-only, no logging |
/bulk-by-email |
100 emails | May return many licenses per email |
/bulk-by-hardware |
100 hardware IDs | Includes corporate seat lookups |
Best Practices
1. Choose the Right Endpoint
- Validate when you need to check if licenses are currently valid for specific hardware
- Info when you know the keys and need full details without validation
- By Email when looking up all licenses for customers (support, CRM)
- By Hardware when managing devices or checking fleet status
2. Handle Partial Results
All bulk endpoints return results for each item, even if some items fail or aren't found. Always check individual results.
// Check each result individually
foreach (var license in response.Licenses)
{
if (license.Found)
{
ProcessLicense(license);
}
else
{
LogNotFound(license.ActivationKey);
}
}
3. Cache Appropriately
- Validate results: Cache for 5-15 minutes (security-sensitive)
- Info/Email/Hardware results: Cache for 15-60 minutes (read-only data)
4. Batch Strategically
Group related items together. For example, query all licenses for a single customer or product in one request rather than mixing unrelated data.
5. Use for Administrative Tools
These endpoints are designed for server-side administrative use. Don't expose them directly to end users.
Frequently Asked Questions
How do I verify a license via API?
Send a POST request to https://www.exisone.com/api/license/validate with your API token in the Authorization: ExisOneApi <token> header and a JSON body containing the activationKey, hardwareId, and productName. ExisOne returns a JSON response with isValid, the license status, expiration date, and any enabled feature flags — typically in milliseconds.
How do I bulk-validate licenses?
Use the bulk endpoint to validate up to 100 licenses in a single API call instead of making one request per key. Send a POST to the bulk validation endpoint with an array of licenses (each with its activation key and hardware ID), and ExisOne returns a per-license result set in one response. You can also look up licenses in bulk by customer email or hardware ID, which is ideal for enterprise dashboards and CRM integrations.
Is there a limit on how many licenses I can query at once?
Yes — each bulk request accepts up to 100 licenses. For larger datasets, page through your keys in batches of 100. There are no per-activation fees, so validating licenses does not add to your bill.