REST API Reference¶
Complete reference for the PyLocket REST API. All endpoints are prefixed with /v1/.
Base URL: https://api.pylocket.com/v1/
Authentication¶
All authenticated endpoints require a Bearer token in the Authorization header:
Obtain tokens via the login endpoint or use an API key.
Auth Endpoints¶
POST /v1/auth/register¶
Register a new developer account.
Request Body:
Response (201):
{
"id": "dev_abc123",
"email": "dev@example.com",
"company_name": "My Company",
"created_at": "2026-03-01T00:00:00Z"
}
POST /v1/auth/login¶
Authenticate and receive JWT tokens.
Request Body:
Response (200) — without 2FA:
{
"access_token": "eyJhbGc...",
"refresh_token": "eyJhbGc...",
"token_type": "bearer",
"expires_in": 3600
}
Response (200) — with 2FA:
POST /v1/auth/login/verify-2fa¶
Complete login with a TOTP code.
Request Body:
Response (200):
{
"access_token": "eyJhbGc...",
"refresh_token": "eyJhbGc...",
"token_type": "bearer",
"expires_in": 3600
}
POST /v1/auth/refresh¶
Refresh an expired access token.
Request Body:
Response (200):
GET /v1/auth/me¶
Get the authenticated developer's profile.
Response (200):
{
"id": "dev_abc123",
"email": "dev@example.com",
"company_name": "My Company",
"two_factor_enabled": true,
"created_at": "2026-03-01T00:00:00Z"
}
POST /v1/auth/api-keys/rotate¶
Generate a new API key. Invalidates the previous key.
Response (200):
POST /v1/auth/2fa/setup¶
Start 2FA setup. Returns a provisioning URI for authenticator apps.
Response (200):
{
"provisioning_uri": "otpauth://totp/PyLocket:dev@example.com?secret=...",
"backup_codes": ["abc123", "def456", "ghi789", "jkl012"]
}
POST /v1/auth/2fa/confirm¶
Confirm 2FA setup with a TOTP code.
Request Body:
Response (200):
POST /v1/auth/2fa/disable¶
Disable 2FA.
Request Body:
GET /v1/auth/2fa/status¶
Check 2FA status.
Response (200):
App Endpoints¶
GET /v1/apps¶
List all apps for the authenticated developer.
Response (200):
[
{
"id": "app_abc123",
"name": "MyApp",
"platforms": ["win-x64", "linux-x64"],
"protection_level": "maximum",
"created_at": "2026-03-01T00:00:00Z"
}
]
POST /v1/apps¶
Create a new application.
Request Body:
Response (201):
{
"id": "app_abc123",
"name": "MyApp",
"platforms": ["win-x64", "linux-x64", "mac-arm64"],
"protection_level": "maximum",
"created_at": "2026-03-01T00:00:00Z"
}
GET /v1/apps/{app_id}¶
Get details for a specific app.
PUT /v1/apps/{app_id}¶
Update an application.
Request Body:
DELETE /v1/apps/{app_id}¶
Delete an application and all associated builds and licenses.
Warning: This action is irreversible.
Build Endpoints¶
POST /v1/apps/{app_id}/builds¶
Create a new protection build by uploading an artifact.
Request: multipart/form-data
| Field | Type | Description |
|---|---|---|
artifact |
File | The artifact to protect |
platform |
String | Target platform |
python_version |
String | Python version |
Response (201):
{
"id": "build_abc789",
"app_id": "app_abc123",
"status": "QUEUED",
"platform": "win-x64",
"python_version": "3.12",
"protection_level": "maximum",
"created_at": "2026-03-01T00:00:00Z"
}
GET /v1/apps/{app_id}/builds¶
List all builds for an app.
Query Parameters:
| Parameter | Description |
|---|---|
status |
Filter by status |
limit |
Max results (default: 20) |
offset |
Pagination offset |
GET /v1/apps/{app_id}/builds/{build_id}¶
Get build details including status.
Response (200):
{
"id": "build_abc789",
"app_id": "app_abc123",
"status": "READY",
"platform": "win-x64",
"python_version": "3.12",
"protection_level": "maximum",
"scan_status": "CLEAN",
"artifact_size_bytes": 2457600,
"protected_size_bytes": 3145728,
"created_at": "2026-03-01T00:00:00Z",
"completed_at": "2026-03-01T00:02:30Z"
}
GET /v1/apps/{app_id}/builds/{build_id}/download¶
Get a signed download URL for the protected artifact.
Response (200):
The download URL is valid for 7 days.
License Endpoints¶
POST /v1/licenses/activate¶
Activate an end-user license. Called by the protected application at runtime.
Request Body:
{
"license_key": "XXXX-XXXX-XXXX-XXXX",
"device_fingerprint": "hashed_device_identifier",
"build_id": "build_abc789"
}
Response (200):
{
"token": "<signed_runtime_token>",
"expires_at": "2026-03-02T00:00:00Z",
"policy": {
"device_limit": 2,
"offline_grace_hours": 72
}
}
Error Responses:
| Status | Meaning |
|---|---|
401 |
Invalid or revoked license key |
403 |
Device limit exceeded |
429 |
Velocity limit exceeded (too many activations) |
POST /v1/licenses/refresh¶
Refresh a runtime token. Called periodically by the protected application.
Request Body:
GET /v1/licenses¶
List licenses for the authenticated developer.
Query Parameters:
| Parameter | Description |
|---|---|
app_id |
Filter by app |
status |
Filter by status: active, revoked, expired, demo |
limit |
Max results (default: 20) |
offset |
Pagination offset |
POST /v1/licenses/{license_id}/revoke¶
Revoke a license immediately.
Public Endpoints¶
GET /v1/public/pricing¶
Get public pricing information. No authentication required.
Response (200):
{
"base_fee_annual_usd": 9.00,
"license_fee_usd": 4.00,
"free_download_limit": 10,
"storage_fee_per_gb_month_usd": 0.03
}
Webhook Endpoints¶
POST /v1/webhooks/stripe¶
Receives Stripe webhook events. Requires a valid Stripe signature.
Handled Events:
| Event | Action |
|---|---|
invoice.paid |
Activates/renews subscription |
invoice.payment_failed |
Sends notification, schedules grace period |
customer.subscription.updated |
Updates subscription metadata |
customer.subscription.deleted |
Deactivates developer account |
Error Response Format¶
All errors follow a consistent format:
{
"detail": "Human-readable error message",
"error_code": "INVALID_LICENSE_KEY",
"status_code": 401
}
Rate Limiting¶
| Endpoint Group | Limit |
|---|---|
| Authentication | 10 requests/minute |
| App management | 60 requests/minute |
| Build operations | 30 requests/minute |
| License activation | 5 requests/10 minutes per license |
| General API | 100 requests/minute |
Rate limit headers are included in all responses:
Pagination¶
List endpoints support pagination:
| Parameter | Description | Default |
|---|---|---|
limit |
Max items per page | 20 |
offset |
Number of items to skip | 0 |
Response includes pagination metadata: