Appearance
API Reference
Raw HTTP endpoints for implementing Keycrate authentication.
Quick Start
We recommend using a pre-built SDK for the best developer experience:
- Python -
pip install keycrate - JavaScript -
npm install keycrate - Go -
go get github.com/keycrate/keycrate-sdk/sdks/go - C# -
dotnet add package Keycrate - Rust -
cargo add keycrate
Not using one of these languages? Continue below to implement the HTTP API directly.
Base URL
https://api.keycrate.devAuthentication Endpoint
POST /auth
Authenticate a user using either a license key or a username/password combination. Validates blacklist, application, team, subscription, HWID, and license status. Returns sanitized license data.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
app_id | string (UUID) | Yes | Application ID in UUID format |
license | string | One of two | License key for authentication |
username | string | One of two | Username for password authentication |
password | string | One of two | Password (bcrypt hashed in DB) |
hwid | string | No | Hardware ID of the device |
Authentication Methods
You must provide either license OR both username and password. At least one authentication method is required.
Example Requests
License Key:
json
{
"app_id": "550e8400-e29b-41d4-a716-446655440000",
"license": "XXXX-XXXX-XXXX-XXXX"
}License Key + HWID:
json
{
"app_id": "550e8400-e29b-41d4-a716-446655440000",
"license": "XXXX-XXXX-XXXX-XXXX",
"hwid": "44454C4C-5900-1038-8059-B5C04F46334A"
}Username/Password:
json
{
"app_id": "550e8400-e29b-41d4-a716-446655440000",
"username": "user@example.com",
"password": "secure_password"
}Username/Password + HWID:
json
{
"app_id": "550e8400-e29b-41d4-a716-446655440000",
"username": "user@example.com",
"password": "secure_password",
"hwid": "44454C4C-5900-1038-8059-B5C04F46334A"
}Responses
✅ 200 OK - Authentication Successful
User credentials validated and license is active.
json
{
"success": true,
"message": "LICENSE_VERIFIED_USED_AND_LOCKED_KEY",
"data": {
"key": "XXXX-XXXX-XXXX-XXXX",
"created_at": "2024-01-15T10:30:00.000Z",
"expires_at": "2025-01-15T10:30:00.000Z",
"initial_duration": "31536000",
"first_used_at": "2024-01-15T10:45:00.000Z",
"hwid_lock": true,
"last_hwid_reset_at": null,
"hwid_reset_cooldown": 86400,
"hwid_reset_allowed": true,
"username": "user@example.com",
"last_login": "2024-01-20T14:22:00.000Z",
"subscription_level": 2,
"subscription_name": "Professional"
}
}Success Message Codes:
License State Indicators
LICENSE_VERIFIED_UNUSED_AND_UNLOCKED_KEY- First activation, no HWID lockLICENSE_VERIFIED_UNUSED_AND_LOCKED_KEY- First activation, with HWID lockLICENSE_VERIFIED_USED_AND_UNLOCKED_KEY- Subsequent use, no HWID lockLICENSE_VERIFIED_USED_AND_LOCKED_KEY- Subsequent use, with HWID lock
Response Data Fields:
| Field | Type | Description |
|---|---|---|
key | string | Unique license key identifier |
created_at | datetime | When the license was created |
expires_at | datetime | When the license expires |
initial_duration | string | Duration in seconds |
first_used_at | datetime | null | First activation timestamp |
hwid_lock | boolean | Whether HWID locking is enabled |
last_hwid_reset_at | datetime | null | Last HWID reset timestamp |
hwid_reset_cooldown | number | Seconds until next HWID reset allowed |
hwid_reset_allowed | boolean | Whether HWID reset is available now |
username | string | null | Associated username |
last_login | datetime | Last authentication timestamp |
subscription_level | integer | Subscription tier level |
subscription_name | string | Subscription plan name |
⚠️ 400 Bad Request
Invalid request - Invalid JSON, missing required fields, or wrong format.
Common Issues
- Invalid JSON - Malformed JSON in request body
- Missing app_id - Application ID is required for all requests
- Invalid UUID - App ID must be a valid UUID format
- No Auth Method - Missing both license and username/password :::
Error Messages:
- Invalid JSON in request body
- App ID is required
- Invalid App ID format (must be a valid UUID)
- No valid authentication method provided (missing license key or username/password)🚫 403 Forbidden
Authentication failed - Invalid credentials, expired, blacklisted, or validation failed.
Authentication Failures:
Invalid Credentials or State
| Code | Description |
|---|---|
LICENSE_NOT_FOUND | License key does not exist |
INVALID_USERNAME_OR_PASSWORD | Wrong username or password |
LICENSE_NOT_ACTIVE | License status is not 'active' |
LICENSE_EXPIRED | License has passed expiration date |
HWID Validation:
Hardware ID Issues
| Code | Description |
|---|---|
HWID_NOT_PROVIDED | License requires HWID but none provided |
HWID_MISMATCH | Provided HWID doesn't match stored HWID |
DEVICE_ALREADY_REGISTERED_WITH_OTHER_LICENSE | HWID is bound to different license |
Application & Team Validation:
Configuration Issues
| Code | Description |
|---|---|
INVALID_APP_ID | Application ID is invalid or missing |
APPLICATION_NOT_FOUND | Application does not exist |
APPLICATION_NOT_ACTIVE | Application status is not 'active' |
TEAM_ERROR | Team not found or plan expired |
Subscription Validation:
Subscription Issues
| Code | Description |
|---|---|
SUBSCRIPTION_ERROR | Subscription not found |
SUBSCRIPTION_NOT_ACTIVE | Subscription status is not 'active' |
Blacklist Blocks:
Geographic & Security Blocks
| Code | Description |
|---|---|
COUNTRY_BLACKLISTED | Request country is blacklisted |
ASN_BLACKLISTED | Request ASN is blacklisted |
IP_BLACKLISTED | Request IP address is blacklisted |
HWID_BLACKLISTED | Hardware ID is blacklisted |
💥 500 Internal Server Error
Server error - An unexpected error occurred processing the request.
Debug Information
Response includes debug_error field only when DEBUG=true environment variable is set.
json
{
"success": false,
"message": "Server error occurred",
"debug_error": "DB_ERROR: connection timeout"
}Registration Endpoint
POST /register
Register or update credentials for a license key. Associates a username and password with an existing license, allowing authentication via credentials instead of just the license key.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
app_id | string (UUID) | Yes | Your application ID in UUID format |
license | string | Yes | License key to register credentials for |
username | string | Yes | Username for this license |
password | string | Yes | Password (will be bcrypt hashed server-side) |
Registration Flow
All fields are required. The password is automatically hashed using bcrypt before storage.
Example Request
json
{
"app_id": "550e8400-e29b-41d4-a716-446655440000",
"license": "XXXX-XXXX-XXXX-XXXX",
"username": "newuser@example.com",
"password": "securepassword123"
}Responses
✅ 200 OK - Credentials Updated
Credentials successfully registered and stored.
json
{
"success": true,
"message": "License credentials updated successfully"
}⚠️ 400 Bad Request
Missing required fields or invalid JSON.
Missing Fields
"License key is required"- license parameter missing"Username is required"- username parameter missing"Password is required"- password parameter missing"App ID is required"- app_id parameter missing"Invalid JSON in request body"- Malformed JSON :::
💥 500 Internal Server Error
Server error during credential update.
json
{
"success": false,
"message": "Server error occurred"
}Possible Issues
"Failed to update license credentials"- Database update failed- License key doesn't exist in database
- Database connection issues
- Invalid app_id and license combination :::
Debug Information: When DEBUG=true environment variable is set, responses include debug_error and debug_type fields for troubleshooting.
CORS Support
Both endpoints support Cross-Origin Resource Sharing (CORS) for browser-based flows.
CORS Configuration
- Access-Control-Allow-Origin:
* - Access-Control-Allow-Methods:
POST, OPTIONS - Access-Control-Allow-Headers:
Content-Type, Authorization - Access-Control-Max-Age:
86400
An OPTIONS request to either endpoint will return a 204 response.
HTTP Details
Headers
Content-Type: application/jsonMethods
- POST for both
/authand/register - OPTIONS for CORS preflight
Integration Examples
cURL
Authenticate with License:
bash
curl -X POST https://api.keycrate.dev/auth \
-H "Content-Type: application/json" \
-d '{
"app_id": "550e8400-e29b-41d4-a716-446655440000",
"license": "XXXX-XXXX-XXXX-XXXX"
}'Authenticate with Username/Password:
bash
curl -X POST https://api.keycrate.dev/auth \
-H "Content-Type: application/json" \
-d '{
"app_id": "550e8400-e29b-41d4-a716-446655440000",
"username": "user@example.com",
"password": "password123"
}'Register Credentials:
bash
curl -X POST https://api.keycrate.dev/register \
-H "Content-Type: application/json" \
-d '{
"app_id": "550e8400-e29b-41d4-a716-446655440000",
"license": "XXXX-XXXX-XXXX-XXXX",
"username": "newuser@example.com",
"password": "securepassword"
}'JavaScript/Fetch
Authenticate:
javascript
const response = await fetch("https://api.keycrate.dev/auth", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
app_id: "550e8400-e29b-41d4-a716-446655440000",
license: "XXXX-XXXX-XXXX-XXXX",
}),
});
const data = await response.json();
if (data.success) {
console.log("Licensed:", data.data);
} else {
console.error("Auth failed:", data.message);
}Python
Authenticate:
python
import requests
response = requests.post(
'https://api.keycrate.dev/auth',
json={
'app_id': '550e8400-e29b-41d4-a716-446655440000',
'license': 'XXXX-XXXX-XXXX-XXXX'
}
)
data = response.json()
if data['success']:
print(f"License expires at: {data['data']['expires_at']}")
else:
print(f"Error: {data['message']}")Validation Flow
Processing Order
- JSON Validation - Parse and validate request body
- App ID Validation - Check UUID format and existence
- Blacklist Checks - Country, ASN, IP, HWID blacklists
- Authentication - Verify license key or username/password
- License Validation - Check status and active state
- Application Validation - Verify app exists and is active
- Team Validation - Verify team exists and plan not expired
- Subscription Validation - Verify subscription exists and active
- HWID Processing - Handle first-time or subsequent activation
License Lifecycle
Creation
↓
First Activation (expires_at set, hwid optionally bound)
↓
Subsequent Uses (last_login updated, hwid validated)
↓
Expiration or DeactivationFirst Activation
- License
first_used_atis set to current timestamp expires_atis calculated frominitial_duration- If HWID locking enabled, device ID is bound
- Generates one of two success codes (locked/unlocked)
Subsequent Uses
- License
last_loginis updated - HWID is validated against stored value (if locked)
- Expiration date is checked
- Generates one of two success codes (locked/unlocked)
Error Handling Best Practices
Implementation Guidelines
- Check the
successfield (true/false) to determine outcome - Use the
messagefield for display or programmatic matching - Implement retries for 5xx errors with exponential backoff
- Handle timeouts as authentication failures
- Log failed attempts server-side for security monitoring
- Cache successful responses when appropriate (consider expiration)
- Never log passwords or full license keys
- Validate app_id format before making requests