Download the PHP package spits-online/laravel-openprovider-api without Composer
On this page you can find all versions of the php package spits-online/laravel-openprovider-api. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download spits-online/laravel-openprovider-api
More information about spits-online/laravel-openprovider-api
Files in spits-online/laravel-openprovider-api
Package laravel-openprovider-api
Short Description Manage Openprovider domains and DNS in Laravel
License MIT
Homepage https://github.com/Spits-online/laravel-openprovider
Informations about the package laravel-openprovider-api
Manage Openprovider domains and DNS in Laravel
[](https://packagist.org/packages/spits-online/laravel-openprovider) [](https://github.com/Spits-online/laravel-openprovider/actions/workflows/run-tests.yml) [](https://github.com/Spits-online/laravel-openprovider/actions/workflows/phpstan.yml) [](https://packagist.org/packages/spits-online/laravel-openprovider)Work with the domains and DNS records in your Openprovider account from Laravel. Add a record, register a domain, or export a zone to Excel with a single call.
Requirements
- PHP 8.3+
- Laravel 12 or 13
- An Openprovider account with API access
Installation
Add your Openprovider login to .env:
The account needs API access, which you enable in the Openprovider control panel.
That's all the configuration most apps need, so you don't have to publish a config file. When you do want to change something, such as package defaults key by key, so everything you leave out keeps its default:
Don't copy keys at their default value. A copied default looks like a deliberate choice, and it stops following the package when the default changes. To see every option, you can publish the full file with php artisan vendor:publish --tag="openprovider-config". Keep the keys you change and delete the rest.
Testing against the sandbox
Openprovider has a sandbox for trying things without buying anything. Point the package at it with:
Dates and timezones
Dates such as $domain->expirationDate and $zone->createdAt are immutable Carbon instances. Openprovider sends them without an offset (2026-09-27 07:03:04) and doesn't document their timezone, so the package reads them in your app's timezone. Set another one if you know Openprovider's dates are in it:
Using another account
The facade uses the account in your config. Build a client for another account with fromConfig(), which takes the same keys:
Openprovider::fake() only replaces the client behind the facade. A client you build with fromConfig() still calls Openprovider, so fake its requests in your tests with Http::fake().
How the login works
The package logs in on the first request and caches the token for 47 hours. Openprovider's tokens are valid for 48, so a cached token never expires mid-request. Each account has its own cached token, and a failed login caches nothing.
Managing DNS records
Pick a zone with Openprovider::zone(), then work with its records(). Picking a zone sends no request; every action after it sends exactly one:
Building a record
Build a record with Record::create():
nameis the host before the zone name, such aswww. Leave it out for the domain itself.ttlis one of the TTLs Openprovider accepts:Ttl::FIFTEEN_MINUTES(the default),Ttl::HOUR,Ttl::THREE_HOURS,Ttl::SIX_HOURS,Ttl::TWELVE_HOURSorTtl::DAY. Openprovider would silently save any other value as a day. Records with the same name and type share one TTL, as DNS requires. A record you add takes the TTL the others already have, and updating one record's TTL changes it for all of them. Adding a TXT verification record to a domain with a one-day SPF record and then updating it withTtl::FIFTEEN_MINUTESgives the SPF record a 15-minute TTL too.priorityis for MX and SRV records. An MX record gets priority10when you leave it out (Record::DEFAULT_MX_PRIORITY), because Openprovider requires one.
Every type in RecordType can be built except SOA, which Openprovider generates: Record::create(RecordType::SOA, …) throws InvalidRecord.
Reading records
records()->get() returns every record of the zone as a lazy collection that fetches them 500 at a time, as you use them. ofType() lets Openprovider filter them:
Changing and deleting records
A record you read from a zone is a ZoneRecord. It knows its zone, so it can update or delete itself, with one request each:
To delete several records at once, pass them all to delete(). It sends one request however many you pass:
Unlike Eloquent's $user->posts()->delete(), this never deletes every record: it needs at least one, and only deletes the ones you pass.
Openprovider returns full names (www.example.com), but only matches a record to update or delete by its name relative to the zone (www). With a full name, it reports success and does nothing: an update adds the new record and keeps the old one. The package always sends relative names, so this is handled for you, including when you build a record with a full name.
records()->update() and records()->delete() also take a record you built, matched by its name, type, value, TTL and priority. Openprovider saves TXT values wrapped in quotes and only matches a TXT record quoted the same way, so the package adds the quotes for you:
To compare records or send them on yourself:
The SOA record
Openprovider generates every zone's SOA record, so it can't be added, changed or deleted. It isn't one of the zone's records(), and there is no Record::soa(). Read it from the zone:
Premium DNS
For a zone hosted by a premium DNS provider, name the provider after the zone. Everything after it works the same:
Records read from a premium zone remember their provider, so $record->delete() goes to the right place.
Managing zones
List every zone lazily, a page at a time as you use them, and create or delete zones:
Openprovider can't restore a deleted zone.
Managing domains
Openprovider addresses a domain by its id. Pick one with Openprovider::domain(), which sends no request; every action after it sends one:
With only the name, look the domain up first. That's one request, because Openprovider needs the id. The Domain you get back can act on itself, like an Eloquent model:
Reading a domain
Rely on renewalDate for when a domain has to be renewed. Openprovider documents expirationDate as not being its primary reference for expiry.
List every domain lazily. The pattern matches the name without its extension:
Every method that takes a domain name accepts a string or a DomainName. DomainName::parse() splits a name the way Openprovider wants it, and throws InvalidDomainName for a name without an extension:
Registering a domain
Check whether it's available first:
Then register it. Contact handles are Openprovider customer handles. Openprovider charges your account for the registration.
Name servers are names, or Nameserver objects when they need a glue IP (ip, ip6). Nameserver::from() turns either into a Nameserver. Pass nsGroup instead to use a name server group from your Openprovider account.
To transfer a domain in, use transfer() with the same arguments, except period, plus its authCode:
register(), transfer() and update() take an attributes array for any other field Openprovider documents for that request, such as ['promo_code' => 'SPRING'].
Changing a domain
update() only changes the arguments you pass:
It also takes nameServers, isLocked, isPrivateWhoisEnabled, the four contact handles (owner, admin, tech, billing) and comments.
The other domain actions, the same on Openprovider::domain($id) and on a Domain you fetched:
A Domain or ZoneRecord in a queued job is serialized without the Openprovider client, so the password never ends up in your queue. After it's unserialized, it acts through the account in your config.
DNS record routes
The package can register JSON routes for apps that manage DNS records from their own front end. They are off until you enable them:
| Method | URI | Name | Does |
|---|---|---|---|
GET |
dns-zone/records/{domain} |
dns-zone.records.show |
Returns the zone with its records as data |
POST |
dns-zone/records/{domain} |
dns-zone.records.store |
Adds the record |
PUT |
dns-zone/records/{domain} |
dns-zone.records.update |
Changes original_record into record |
DELETE |
dns-zone/records/{domain} |
dns-zone.records.destroy |
Removes the records |
The routes change live DNS, so they run behind web and auth by default. Any signed-in user can change any zone in the account, so add your own middleware when users may only manage some domains. Set the middleware and a URI prefix in the config:
A record in a request body uses Openprovider's fields:
Invalid requests get Laravel's standard 422 validation response. Changes answer 204 No Content. Each request may send a provider (sectigo) to work with a premium DNS zone. MX records need a prio.
Exporting a zone to Excel
A route that downloads a zone's records as .xlsx has its own switch, separate from the DNS record routes. It needs Laravel Excel:
Like the DNS record routes, it runs behind web and auth by default, and takes its own exports.prefix and exports.middleware.
| Method | URI | Name | Does |
|---|---|---|---|
GET |
dns-zone/export/records/{domain} |
dns-zone.export |
Downloads the records as .xlsx |
The download is named dns_zone_{domain}.xlsx. Pass ?filename=example to name it example.xlsx instead. The name may contain letters, digits, spaces, dots, dashes and underscores.
You can also use the export in your own code. ZoneExport::fromZone() exports every record, the SOA record first; new ZoneExport($records) exports the records you pass:
Error handling
Every exception extends SpitsOnline\Openprovider\Exceptions\OpenproviderException:
| Exception | When |
|---|---|
RequestFailed |
Openprovider returned an error. $status, $errorCode and $body hold what it sent back. |
ConnectionFailed |
Openprovider couldn't be reached. |
MissingConfiguration |
The username or password isn't set. The message names the env key. |
InvalidDomainName |
A domain name has no extension, such as localhost. |
InvalidRecord |
Record::fromArray() gets an SOA record, which Openprovider generates and can't be added, changed or deleted. |
MissingDependency |
The export route is used without maatwebsite/excel. |
Testing your app
Openprovider::fake() swaps the client for an in-memory Openprovider. It answers the same requests Openprovider does, so everything in this README works on it, including $record->delete() and $domain->renew(). Seed it with zones and domains; changes apply to the seeded data, and you can assert on them:
The record callbacks get each record as your code sent it. assertDomainUpdated() gets the changed fields in Openprovider's keys.
The fake stores records the way Openprovider does: under their full name (www becomes www.example.com) and with TXT values quoted. A zone or domain that wasn't seeded throws RequestFailed with status 404. check() reports seeded domains as in use and every other name as free, and authCode() returns OpenproviderFake::AUTH_CODE.
Testing
Changelog
Please see UPGRADE.
Contributing
Please see CONTRIBUTING for details.
Security vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
- SpitsOnline
- All Contributors
License
The MIT License (MIT). Please see License File for more information.
All versions of laravel-openprovider-api with dependencies
illuminate/cache Version ^12.0||^13.0
illuminate/contracts Version ^12.0||^13.0
illuminate/http Version ^12.0||^13.0
illuminate/routing Version ^12.0||^13.0
illuminate/support Version ^12.0||^13.0
illuminate/validation Version ^12.0||^13.0
spatie/laravel-package-tools Version ^1.16