API Access
Understanding API access levels and permissions is essential for building applications with 0.link. This guide covers API key scopes, permission management, and how to handle access-related errors.
API Key Scopes
Every API key has a scope that determines what operations it can perform. 0.link uses three scope levels:
| Scope | Description | Capabilities |
|---|---|---|
READ | Read-only access | View domains, list DNS records, search availability |
WRITE | Read and write access | All READ operations, plus register domains, create/update DNS records, modify domain settings |
ADMIN | Full administrative access | All WRITE operations, plus manage API keys, account settings |
Default Scope
When creating an API key without specifying a scope, it defaults to ADMIN. For production applications, we recommend using the minimum scope required.
Read-Only Access (READ Scope)
What You Can Do
With a READ scope API key:
// ✅ List your domains
const response = await fetch('https://api.0.link/api/domains', {
headers: { 'Authorization': 'Bearer YOUR_API_KEY' }
});
const domains = await response.json();
// ✅ Get domain details
const domain = await fetch('https://api.0.link/api/domains/dom_abc123', {
headers: { 'Authorization': 'Bearer YOUR_API_KEY' }
}).then(res => res.json());
// ✅ List DNS records
const records = await fetch('https://api.0.link/api/domains/dom_abc123/dns/records', {
headers: { 'Authorization': 'Bearer YOUR_API_KEY' }
}).then(res => res.json());
// ✅ Search domain availability
const availability = await fetch('https://api.0.link/api/domains/search', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({ query: 'mysite', tlds: ['com', 'io'] })
}).then(res => res.json());What You Cannot Do
// ❌ Register a domain
await fetch('https://api.0.link/api/domains', {
method: 'POST',
headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'example.com', years: 1, contacts: { ... } })
});
// Error: 403 Forbidden - WRITE scope required
// ❌ Create DNS records
await fetch('https://api.0.link/api/domains/dom_abc123/dns/records', {
method: 'POST',
headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' },
body: JSON.stringify({ type: 'A', name: '@', content: '192.0.2.1' })
});
// Error: 403 Forbidden - WRITE scope requiredUse Cases for READ Scope
- Monitoring dashboards: Display domain expiration dates and DNS status
- Availability checkers: Build tools to search for available domains
- Reporting systems: Generate reports from domain and DNS data
- Third-party integrations: Sync domain data to external systems
Read-Write Access (WRITE Scope)
Additional Capabilities
With a WRITE scope API key, you can also:
// ✅ Register a new domain
const newDomain = await fetch('https://api.0.link/api/domains', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'example.com',
years: 1,
contacts: {
registrant: {
first_name: 'John',
last_name: 'Doe',
email: '[email protected]',
phone: '+1.5551234567',
address: {
street: '123 Main St',
city: 'San Francisco',
state: 'CA',
postal_code: '94102',
country: 'US'
}
}
}
})
}).then(res => res.json());
// ✅ Create DNS records
const record = await fetch('https://api.0.link/api/domains/dom_abc123/dns/records', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
type: 'A',
name: '@',
content: '192.0.2.1',
ttl: 3600
})
}).then(res => res.json());
// ✅ Update nameservers
await fetch('https://api.0.link/api/domains/dom_abc123/nameservers', {
method: 'PUT',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
nameservers: ['ns1.cloudflare.com', 'ns2.cloudflare.com']
})
});
// ✅ Update auto-renew setting
await fetch('https://api.0.link/api/domains/dom_abc123/autorenew', {
method: 'PUT',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({ auto_renew: true })
});
// ✅ Renew a domain
await fetch('https://api.0.link/api/domains/dom_abc123/renew', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({ years: 1 })
});Use Cases for WRITE Scope
- Domain management platforms: Register and configure domains
- Automated DNS management: Deploy DNS changes programmatically
- Infrastructure automation: Manage domains as part of CI/CD pipelines
- Reseller applications: Build domain reseller tools
Administrative Access (ADMIN Scope)
Additional Capabilities
With an ADMIN scope API key, you can also manage API keys programmatically via GraphQL:
# List all API keys
query {
apiKeys {
keyId
name
scope
createdAt
lastUsedAt
validFrom
validUntil
}
}
# Create a new API key
mutation {
issueApiKey(name: "Production Backend", scope: WRITE) {
keyId
token # Only shown once - store securely!
name
scope
validFrom
}
}
# Rotate an existing API key
mutation {
rotateApiKey(keyId: "abc123", graceSeconds: 3600) {
keyId
token # New token - update your applications
name
scope
}
}
# Revoke an API key
mutation {
revokeApiKey(keyId: "abc123")
}Use Cases for ADMIN Scope
- API key management: Programmatically create and rotate keys
- Administrative tools: Build internal tools for account management
- Security automation: Automatically rotate keys on a schedule
Managing API Keys
Creating Keys in Dashboard
- Navigate to API Keys in your 0.link dashboard
- Click Create API Key
- Enter a descriptive name (e.g., "Production Backend")
- Select the appropriate scope:
READfor read-only applicationsWRITEfor applications that need to modify resourcesADMINfor administrative tools
- Optionally set an expiration date
- Copy and securely store the generated token
Token Security
The API token is only displayed once when created. Store it securely - you cannot retrieve it later. If lost, you'll need to create a new key.
Token Format
API keys follow this format:
zlk_live_<key_id>.<secret>For example: zlk_live_abc123xyz.dGhpcyBpcyBhIHNlY3JldA
Understanding Access-Related Errors
401 Unauthorized
Cause: Invalid, missing, or expired API key
{
"type": "https://api.0.link/problems/unauthorized",
"title": "Unauthorized",
"status": 401,
"detail": "Authentication required"
}Solutions:
- Verify the API key is included in the
Authorizationheader - Check the key hasn't been revoked
- Ensure proper formatting:
Authorization: Bearer zlk_live_...
403 Forbidden
Cause: Valid key but insufficient scope for the operation
{
"type": "https://api.0.link/problems/insufficient-scope",
"title": "Forbidden",
"status": 403,
"detail": "This action requires WRITE scope"
}Solutions:
- Create a new API key with the required scope
- Use a different key that has appropriate permissions
Best Practices
Principle of Least Privilege
Grant the minimum scope needed for each use case:
// ✅ Good: Specific scope for each use case
const dashboardKey = {
name: 'Domain Dashboard',
scope: 'READ', // Only needs to display data
};
const backendKey = {
name: 'Backend Service',
scope: 'WRITE', // Needs to manage domains and DNS
};
// ❌ Avoid: Using ADMIN scope when not needed
const unnecessaryAdminKey = {
name: 'Simple Display Widget',
scope: 'ADMIN', // Overly broad for just displaying data
};Environment Separation
Use different API keys for each environment:
| Environment | Recommended Scope | Rationale |
|---|---|---|
| Development | WRITE | Full testing capabilities |
| Staging | WRITE | Production-like testing |
| Production | Minimum required | Security best practice |
Key Rotation
Regularly rotate API keys to maintain security:
- Create a new key with the same scope
- Update your applications to use the new key
- Verify the new key is working
- Revoke the old key
For programmatic rotation with a grace period:
mutation {
rotateApiKey(
keyId: "old_key_id",
graceSeconds: 86400 # 24 hours for both keys to work
) {
token
}
}Regular Security Reviews
- Audit existing keys: Remove unused keys
- Review scopes: Downgrade over-privileged keys
- Check last used dates: Identify potentially compromised keys
- Set expiration dates: Use
validUntilfor temporary access
Next Steps
Now that you understand API access:
- Explore the API Reference - See all available endpoints
- Interactive API Docs - Try the API with Swagger UI
- Learn About Authentication - Deep dive into security
- Choose an SDK - Use our official libraries
Getting Help
Questions about API access?
- Dashboard: Manage keys at 0.link/app/api-keys
- Support: Email [email protected] for access issues
- Security: Report security concerns to [email protected]