OpenProvider Skill
OpenProvider (openprovider.eu) is the domain registrar and DNS provider for Atlas Frontline.
This skill handles all domain, DNS, SSL, and customer handle operations via the
OpenProvider REST API v1beta.
Auth Flow
Always obtain a token before making any API call.
- Load credentials:
OPENPROVIDER_USERNAME / OPENPROVIDER_PASSWORD (env vars), with legacy fallback from OPENPROVIDER_USER / OPENPROVIDER_PASS, or DB table system_settings (key: integration_credentials_openprovider)
- Get token:
POST https://api.openprovider.eu/v1beta/auth/login
- Use token as
Authorization: Bearer {token} header
- Token valid for 48h (Atlas caches for 24h)
- On HTTP 401: invalidate token → re-authenticate → retry request
# Get token
OP_USER="${OPENPROVIDER_USERNAME:-${OPENPROVIDER_USER:-}}"
OP_PASS="${OPENPROVIDER_PASSWORD:-${OPENPROVIDER_PASS:-}}"
TOKEN=$(curl -s -X POST https://api.openprovider.eu/v1beta/auth/login \
-H "Content-Type: application/json" \
-d '{"username": "'"$OP_USER"'", "password": "'"$OP_PASS"'"}' \
| jq -r '.data.token')
→ Full auth docs: references/auth.md
API Base
| Setting | Value |
|---|
| Base URL | https://api.openprovider.eu/v1beta/ |
| Auth | Bearer Token |
| Content-Type | application/json |
| Timeout | 30s |
| Retries | 3 (backoff: 1s, 3s, 9s) |
Routing Matrix
Use this table to find the right action and reference file:
Domain Operations
| Request | Endpoint | Method | Reference |
|---|
| Is domain available? / Check domain | /domains/check | POST | domains.md |
| Register / buy domain | /domains | POST | domains.md |
| Get domain status | /domains/{id} | GET | domains.md |
| List all domains | /domains | GET | domains.md |
| Renew domain | /domains/{id}/renew | POST | domains.md |
| Update domain settings | /domains/{id} | PUT | domains.md |
| Transfer domain | /domains/transfer | POST | domains.md |
| Delete / cancel domain | /domains/{id} | DELETE | domains.md |
| Restore domain | /domains/{id}/restore | POST | domains.md |
DNS Operations
| Request | Endpoint | Method | Reference |
|---|
| Create DNS zone | /dns/zones | POST | dns.md |
| Get DNS zone | /dns/zones/{domain} | GET | dns.md |
| Add/remove DNS records | /dns/zones/{domain} | PUT | dns.md |
| List DNS records | /dns/zones/{domain}/records | GET | dns.md |
| Delete DNS zone | /dns/zones/{domain} | DELETE | dns.md |
| List all DNS zones | /dns/zones | GET | dns.md |
SSL Operations
| Request | Endpoint | Method | Reference |
|---|
| Order SSL certificate | /ssl/orders | POST | ssl.md |
| List SSL certificates | /ssl/orders | GET | ssl.md |
| Get SSL certificate details | /ssl/orders/{id} | GET | ssl.md |
| Reissue SSL certificate | /ssl/orders/{id}/reissue | POST | ssl.md |
| Renew SSL certificate | /ssl/orders/{id}/renew | POST | ssl.md |
| Cancel SSL certificate | /ssl/orders/{id} | DELETE | ssl.md |
| List SSL products/prices | /ssl/products | GET | ssl.md |
Nameserver Operations
TLD Information
| Request | Endpoint | Method | Reference |
|---|
| List all TLDs | /tlds | GET | tlds.md |
| Get TLD details & prices | /tlds/{name} | GET | tlds.md |
Customers & Resellers
Workflow: Register Domain (End-to-End)
Full flow when a user says "register the domain example.com":
- Check availability →
POST /domains/check with with_price: true
- Ensure customer handle →
GET /customers or POST /customers
- Register domain →
POST /domains with owner_handle, ns_group
- Create DNS zone →
POST /dns/zones
- Set DNS records →
PUT /dns/zones/{domain} (A, MX, SPF, DKIM, DMARC)
- Check status →
GET /domains/{id}
Workflow: Change DNS Record
- Load current records →
GET /dns/zones/{domain}/records
- Normalize the record name to zone-relative form
- Remove old record →
PUT /dns/zones/{domain} with records.remove
- Add new record →
PUT /dns/zones/{domain} with records.add
- Verify the resulting record names →
GET /dns/zones/{domain}/records
Important: Do NOT combine remove and add in a single PUT call! Two separate calls required (Error 817).
DNS Record Naming Rule (CRITICAL)
When updating records in zone /dns/zones/{domain}, OpenProvider expects the
record name in zone-relative form for subdomains.
Use:
phone for phone.example.com in zone example.com
_dmarc for _dmarc.example.com in zone example.com
www for www.example.com in zone example.com
Do NOT use the full FQDN as name when writing records inside a zone unless
you have verified OpenProvider expects it for that exact operation.
If you send phone.example.com as name inside zone example.com, OpenProvider may
append the zone again and create the wrong record:
- intended:
phone.example.com
- accidental result:
phone.example.com.example.com
Safe Name Normalization
Before any DNS write:
- Identify the zone apex, e.g.
example.com
- Convert requested host to zone-relative label:
example.com → apex/root ("" empty string for OpenProvider zone writes, not the full domain, and not @ unless explicitly verified)
phone.example.com → phone
_dmarc.example.com → _dmarc
- Read back the zone records after the write and confirm the final record name is correct
Apex / Root Record Rule (CRITICAL)
For OpenProvider PUT /dns/zones/{domain} writes, the zone apex must be sent as an empty string name:
{
"name": "",
"type": "TXT",
"value": "google-site-verification=...",
"ttl": 600
}
Do not send the full domain name as name for apex writes inside the zone payload.
If you send example.com as name while writing inside zone example.com, OpenProvider may create:
- intended:
example.com
- accidental result:
example.com.example.com
Also do not assume @ works for OpenProvider. It may be rejected as an invalid record name.
Safe DNS Change Pattern
For any add/replace of a record:
- Read current zone records
- Check whether the target record already exists
- If replacing, remove conflicting record first
- Add the new record using the zone-relative
name
- Re-read the zone and verify the exact final FQDN
- Optionally check public resolution separately (
dig) because provider acceptance ≠ public propagation
MX / Mail Provider Rule (CRITICAL)
For OpenProvider DNS writes, MX records use the field name prio, not priority.
Correct example for a mail subdomain inside zone example.com:
{
"records": {
"add": [
{
"name": "send",
"type": "MX",
"value": "feedback-smtp.eu-west-1.amazonses.com",
"ttl": 600,
"prio": 10
}
]
}
}
Do not use priority in the payload unless you have verified a different endpoint/schema.
For Resend/Amazon SES sender domains, a known-good public result is:
dig +short MX send.example.com
# 10 feedback-smtp.eu-west-1.amazonses.com.
Example
Zone: example.com
Correct add payload for phone.example.com:
{
"records": {
"add": [
{
"name": "phone",
"type": "A",
"value": "46.225.220.40",
"ttl": 900
}
]
}
}
Incorrect payload:
{
"records": {
"add": [
{
"name": "phone.example.com",
"type": "A",
"value": "46.225.220.40",
"ttl": 900
}
]
}
}
That incorrect payload can create phone.example.com.example.com.
Apex TXT example for example.com:
Correct:
{
"records": {
"add": [
{
"name": "",
"type": "TXT",
"value": "google-site-verification=...",
"ttl": 600
}
]
}
}
Incorrect:
{
"records": {
"add": [
{
"name": "example.com",
"type": "TXT",
"value": "google-site-verification=...",
"ttl": 600
}
]
}
}
That incorrect payload can create example.com.example.com.
Workflow: Domain Transfer
- Get auth code from current registrar (EPP/transfer code)
- Ensure customer handle →
POST /customers if needed
- Initiate transfer →
POST /domains/transfer with auth_code + owner_handle
Error Handling
All API responses follow this structure:
{"code": 0, "desc": "...", "data": {...}}
code: 0 = success
code: != 0 = error (details in desc)
- HTTP 401 = token expired → re-authenticate
- HTTP 429 = rate limit → wait and retry
- If env lookup fails, check whether the instance still uses legacy names
OPENPROVIDER_USER / OPENPROVIDER_PASS
Common errors:
| Code | Meaning | Solution |
|---|
| 817 | Duplicate DNS record | Remove existing record first, then add new one |
| 816 | Validation error / invalid field value | Re-check record schema; for MX use prio instead of priority |
| 801 | Domain already exists | Domain is already registered |
| 899 | Rate limit | Reduce batch size, wait |
| 1000 | Auth failed | Check credentials |
→ Full error reference: references/auth.md
Atlas Integration (Context)
OpenProvider is integrated into Atlas via the Frontline module:
- Service:
api/services/frontline/openprovider.ts — API client
- DNS:
api/services/frontline/dns.ts — DNS configuration & verification
- Handles:
api/services/frontline/handles.ts — Workspace handle management
- Search:
api/services/frontline/domain-search.ts — Domain availability search
- Domains:
api/services/frontline/domains.ts — Domain lifecycle
- Types:
shared/types/frontline.ts — TypeScript definitions
- Credentials:
system_settings table, key integration_credentials_openprovider
Key Limits
| Limit | Value |
|---|
| Domain check batch size | Max 5 per request |
| Suggestions per search | Max 20 |
| Token validity | 48h (cache: 24h) |
| Request timeout | 30s |
| DNS TTL minimum | 600s |
| Domain registrations per workspace/day | Max 3 (Atlas limit) |
Reference Files
| File | Contents |
|---|
| references/auth.md | Authentication, tokens, credentials, error handling |
| references/domains.md | Domain CRUD, check, transfer, renew, restore |
| references/dns.md | DNS zones & records (CRUD, patterns, pitfalls) |
| references/ssl.md | SSL certificates (order, reissue, renew, cancel) |
| references/nameservers.md | Nameserver group management |
| references/tlds.md | TLD information & pricing |
| references/customers-resellers.md | Customer handles & reseller info |