Documentation
Guides, references, and everything you need to get started.
Getting Started
Go from zero to protected in under five minutes
Step 1: Create your account
Sign up at obfuscura.com/register. Every account starts with a 14-day free trial with full access. No credit card required.
Step 2: Create a project
From your dashboard, click New Project. Give it a name (e.g., "My WordPress Plugin"). Each project gets its own API key and can have multiple license types.
Step 3: Encode your files
Navigate to the Encode tab. Upload a single PHP file or ZIP archive. Select encoding options and click Encode. Protected files are ready in seconds.
Step 4: Include the loader
Download the runtime loader from your project settings. Place obfuscura-loader.php in your project root and add:
require_once __DIR__ . '/obfuscura-loader.php';
Your encoded files now execute normally. The loader handles license validation transparently.
Step 5: Issue a license
Go to Licenses > Create License. Choose a license type, set restrictions, and generate the key. Send it to your customer with the encoded files.
Encoding Your Code
How to prepare and encode your PHP files for distribution
What gets encoded
Obfuscura encodes .php files only. Non-PHP files (images, CSS, JavaScript, configs) pass through unchanged. Upload your entire project as a ZIP and only PHP files are transformed.
Encoding options
String Encryption: Encrypts all string literals. Enabled by default.
Control Flow Flattening: Restructures logic flow to resist decompilation. Enabled by default. May increase file size 10-20%.
Dead Code Injection: Inserts realistic non-functional code paths. Optional. Increases analysis time significantly.
License Binding: Requires valid license at runtime. Disable for open-core models where some files are free.
Batch encoding via API
curl -X POST https://obfuscura.com/api/v1/encode \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "file=@my-plugin.zip" \
-F "options[string_encryption]=true" \
-F "options[control_flow]=true" \
-o my-plugin-encoded.zip
The Runtime Loader
A single PHP file that powers everything
How it works
The loader registers a custom stream wrapper and autoloader. When an encoded file is included, the loader intercepts the request, decodes the file in memory, and passes it to PHP's execution engine. The decoded source never touches disk.
The loader also handles license validation on a configurable schedule, caching results locally.
Configuration
The loader reads from environment variables or obfuscura.json:
{
"license_key": "OBF-XXXX-XXXX-XXXX-XXXX",
"project_api_key": "proj_xxxxxxxxxxxxx",
"validation_interval": "daily",
"offline_grace_hours": 72,
"log_level": "error"
}
Hosting compatibility
Works on any environment running PHP 8.0+. No PECL extensions, no php.ini changes. Tested on:
- Shared hosting (cPanel, Plesk, DreamHost)
- VPS (DigitalOcean, Linode, Vultr)
- Cloud (AWS EC2, GCP, Azure)
- Managed platforms (Laravel Forge, Ploi, ServerPilot)
- Containers (Docker, Kubernetes)
License Management
Creating and managing licenses for your customers
License types
Define license types as templates with rules:
- Duration: Perpetual, fixed-date, or relative (365 days from activation)
- Activation limit: How many domains/servers per key
- Domain locking: Bind to specific domains
- Features: Feature-gated licensing
- Validation interval: Per-request, hourly, or daily
- Offline grace: How long files work without API access
Issuing licenses via API
curl -X POST https://obfuscura.com/api/v1/licenses \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"license_type_id": 1,
"customer_email": "client@example.com",
"customer_name": "Acme Corp",
"domains": ["acme.com", "staging.acme.com"],
"expires_at": "2027-01-01"
}'
Returns a key like OBF-A1B2-C3D4-E5F6-G7H8. Include this key in the obfuscura.json that ships with your encoded project.
Revoking licenses
Revoke instantly from the dashboard. Encoded files stop after the offline grace period expires. Modify domains, expiration, or activation limits at any time.
CI/CD Integration
Encode protected builds automatically on every release
Overview
Obfuscura's REST API lets you encode files as part of your deployment pipeline. Add a single step to your workflow and ship protected artifacts without manual intervention.
GitHub Actions
# .github/workflows/release.yml
- name: Encode PHP files
run: |
curl -X POST https://obfuscura.com/api/v1/encode \
-H "Authorization: Bearer ${{ secrets.OBFUSCURA_KEY }}" \
-F "file=@dist/my-plugin.zip" \
-F "options[string_encryption]=true" \
-F "options[control_flow]=true" \
-o dist/my-plugin-encoded.zip
GitLab CI
# .gitlab-ci.yml
encode:
stage: build
script:
- curl -X POST https://obfuscura.com/api/v1/encode
-H "Authorization: Bearer $OBFUSCURA_KEY"
-F "file=@dist/my-plugin.zip"
-o dist/my-plugin-encoded.zip
artifacts:
paths:
- dist/my-plugin-encoded.zip
Any REST-capable runner
Jenkins, Bitbucket Pipelines, CircleCI, or any system that can execute a curl command works. Store your API key as a secret and call the encode endpoint. Results are streamed back as a download — no temporary storage on our side.
Unlimited encoding
All plans include unlimited encoding runs via the API. No per-encode fees and no per-server charges.
API Reference
RESTful endpoints for every operation
Obfuscura API
v1.0Include your project API key in the header:
Authorization: Bearer proj_xxxxxxxxxxxxxGet your API key from Dashboard → Project Settings → API Keys.
POST /license/validate Validate a license key
Request Body — application/json
| Name | Type | Description |
|---|---|---|
| license_key *required | string | The license key to validate (e.g. OBF-XXXX-XXXX-XXXX-XXXX) |
| project_api_key *required | string | Your project API key |
| domain *required | string | Domain requesting validation |
| ip | string | Server IP address (auto-detected if omitted) |
Example Request
Responses
POST /license/activate Activate a license on a domain
Request Body — application/json
| Name | Type | Description |
|---|---|---|
| license_key *required | string | The license key to activate |
| project_api_key *required | string | Your project API key |
| domain *required | string | Domain to bind this activation to |
| device_name | string | Human-readable label (e.g. "Production Server") |
| ip | string | Server IP for IP-locked licenses |
| hostname | string | Server hostname for hostname-locked licenses |
Example Request
Responses
DELETE /license/deactivate Remove a domain activation
Request Body — application/json
| Name | Type | Description |
|---|---|---|
| license_key *required | string | The license key |
| project_api_key *required | string | Your project API key |
| domain *required | string | Domain to deactivate |
Example Request
Responses
GET /licenses List all licenses for a project
Query Parameters
| Name | Type | Description |
|---|---|---|
| status | string | Filter by status: active, expired, revoked, suspended |
| customer_email | string | Filter by customer email |
| page | integer | Page number (default: 1) |
| per_page | integer | Results per page (default: 25, max: 100) |
Responses
POST /licenses Create a new license
Request Body — application/json
| Name | Type | Description |
|---|---|---|
| license_type_id *required | integer | ID of the license type template |
| customer_email *required | string | Customer email address |
| customer_name | string | Customer or company name |
| domains | array | Pre-authorized domains |
| expires_at | string | ISO 8601 expiration date (null for perpetual) |
| features | array | Feature flags to enable |
| metadata | object | Custom key-value pairs |
Example Request
Responses
PUT /licenses/{license_key} Update a license
Path Parameters
| Name | Type | Description |
|---|---|---|
| license_key *required | string | The license key to update |
Request Body — application/json
| Name | Type | Description |
|---|---|---|
| status | string | active, suspended, or revoked |
| expires_at | string | New expiration date (ISO 8601) |
| features | array | Replace feature flags |
| activations_limit | integer | Max concurrent activations |
| metadata | object | Merge with existing metadata |
Responses
DELETE /licenses/{license_key} Revoke a license permanently
Path Parameters
| Name | Type | Description |
|---|---|---|
| license_key *required | string | The license key to revoke |
Responses
POST /encode Encode PHP files
Request Body — multipart/form-data
| Name | Type | Description |
|---|---|---|
| file *required | file | PHP file or ZIP archive to encode |
| options[string_encryption] | boolean | Encrypt string literals (default: true) |
| options[control_flow] | boolean | Flatten control flow (default: true) |
| options[dead_code] | boolean | Inject dead code paths (default: false) |
| options[license_binding] | boolean | Require license at runtime (default: true) |
Example Request (cURL)
Responses
GET /encode/{job_id}/status Check encoding job status
Path Parameters
| Name | Type | Description |
|---|---|---|
| job_id *required | string | Encoding job ID (returned in X-Job-Id header for async jobs) |
Responses
GET /webhooks List configured webhook endpoints
Responses
POST /webhooks Register a webhook endpoint
Request Body — application/json
| Name | Type | Description |
|---|---|---|
| url *required | string | HTTPS endpoint URL |
| events *required | array | Events to subscribe to (see list below) |
| secret | string | Signing secret for payload verification |
Available Events
Responses
Stripe Integration
Automate license provisioning with Stripe subscriptions
Connect your Stripe account, map products to license types, and Obfuscura will automatically:
- Create a license when a new subscription starts
- Suspend a license when a payment fails
- Reactivate a license when payment succeeds
- Revoke a license when a subscription is canceled
Your entire sales workflow — from checkout to code protection — is fully automated.
Troubleshooting
Common issues and solutions
"License validation failed"
Check license_key and project_api_key in obfuscura.json. Verify the license is active and domain matches. Check firewall rules for outbound HTTPS on port 443.
"Loader integrity check failed"
The loader file was modified. Re-download a fresh copy from your project settings. The loader includes a self-verification checksum.
Encoded files not executing
Ensure the loader is required before any encoded files. It must be the first require in your entry point. Verify PHP 8.0+: php -v.