Skip to content

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:

Authorization: Bearer <ACCESS_TOKEN>

Obtain tokens via the login endpoint or use an API key.


Auth Endpoints

POST /v1/auth/register

Register a new developer account.

Request Body:

{
  "email": "dev@example.com",
  "password": "SecureP@ss123",
  "company_name": "My Company"
}

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:

{
  "email": "dev@example.com",
  "password": "SecureP@ss123"
}

Response (200) — without 2FA:

{
  "access_token": "eyJhbGc...",
  "refresh_token": "eyJhbGc...",
  "token_type": "bearer",
  "expires_in": 3600
}

Response (200) — with 2FA:

{
  "mfa_required": true,
  "mfa_token": "mfa_abc123"
}

POST /v1/auth/login/verify-2fa

Complete login with a TOTP code.

Request Body:

{
  "mfa_token": "mfa_abc123",
  "code": "123456"
}

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:

{
  "refresh_token": "eyJhbGc..."
}

Response (200):

{
  "access_token": "eyJhbGc...",
  "token_type": "bearer",
  "expires_in": 3600
}

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):

{
  "api_key": "pk_live_abc123...",
  "created_at": "2026-03-01T00:00:00Z"
}

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:

{
  "code": "123456"
}

Response (200):

{
  "two_factor_enabled": true
}

POST /v1/auth/2fa/disable

Disable 2FA.

Request Body:

{
  "code": "123456"
}

GET /v1/auth/2fa/status

Check 2FA status.

Response (200):

{
  "two_factor_enabled": true,
  "backup_codes_remaining": 3
}

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:

{
  "name": "MyApp",
  "platforms": ["win-x64", "linux-x64", "mac-arm64"]
}

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:

{
  "name": "MyApp Pro",
  "platforms": ["win-x64", "linux-x64", "mac-arm64", "mac-x64"]
}

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):

{
  "download_url": "https://cdn.pylocket.com/...",
  "expires_at": "2026-03-08T00:00:00Z"
}

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:

{
  "token": "<signed_runtime_token>",
  "device_fingerprint": "hashed_device_identifier"
}

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:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1709337600

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:

{
  "items": [...],
  "total": 150,
  "limit": 20,
  "offset": 0
}