PHPackages                             porkbun-php/client - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. porkbun-php/client

ActiveLibrary[API Development](/categories/api)

porkbun-php/client
==================

PHP client for the Porkbun API v3 with domain-centric design, typed DTOs, and complete endpoint coverage

v1.1.0(3mo ago)02[6 PRs](https://github.com/porkbun-php/client/pulls)MITPHPPHP ^8.4CI passing

Since Mar 14Pushed 2w agoCompare

[ Source](https://github.com/porkbun-php/client)[ Packagist](https://packagist.org/packages/porkbun-php/client)[ Docs](https://github.com/porkbun-php/client)[ RSS](/packages/porkbun-php-client/feed)WikiDiscussions main Synced 2w ago

READMEChangelog (2)Dependencies (16)Versions (13)Used By (0)

 [![Porkbun PHP API Client](art/example.png)](art/example.png)

Porkbun PHP API Client
======================

[](#porkbun-php-api-client)

[![Tests](https://github.com/porkbun-php/client/actions/workflows/tests.yml/badge.svg)](https://github.com/porkbun-php/client/actions/workflows/tests.yml)[![Code Quality](https://github.com/porkbun-php/client/actions/workflows/code-quality.yml/badge.svg)](https://github.com/porkbun-php/client/actions/workflows/code-quality.yml)[![Latest Stable Version](https://camo.githubusercontent.com/32555aadd012caa2cfea1eb61c6fffcc9ab0291bc94275d60c995b0ef8143e5d/68747470733a2f2f706f7365722e707567782e6f72672f706f726b62756e2d7068702f636c69656e742f76)](https://packagist.org/packages/porkbun-php/client)[![License](https://camo.githubusercontent.com/e1dd086ad2cc7e394696105773a154d71113298a136751338f733f7aff3719dd/68747470733a2f2f706f7365722e707567782e6f72672f706f726b62756e2d7068702f636c69656e742f6c6963656e7365)](https://packagist.org/packages/porkbun-php/client)

A community-maintained PHP 8.4+ client for the [Porkbun API v3](https://porkbun.com/api/json/v3/documentation) with complete endpoint coverage, domain-centric design, and Laravel integration.

Features
--------

[](#features)

- **Complete API coverage** — all 27 Porkbun API v3 endpoints: DNS, DNSSEC, SSL, nameservers, URL forwarding, glue records, domains, pricing, and more
- **Domain-centric design** — fluent API: `$client->domain('example.com')->dns()->all()`
- **Typed everything** — immutable DTOs, backed enums, strict return types throughout
- **Fluent builders** — validated DNS record construction with convenience methods
- **Structured errors** — typed exception hierarchy with request/response context
- **Laravel integration** — service provider, facade, and config publishing out of the box
- **PSR-18 compatible** — works with any HTTP client (Guzzle, Symfony, curl, etc.)
- **Strict quality** — Pint, Pest, PHPStan, PHP 8.4+ with Rector

Requirements
------------

[](#requirements)

- PHP 8.4+
- A PSR-18 HTTP client (Guzzle, Symfony HttpClient, or any other)

Installation
------------

[](#installation)

```
composer require porkbun-php/client
```

If you don't already have a PSR-18 HTTP client installed, add one:

```
composer require guzzlehttp/guzzle
# or
composer require symfony/http-client nyholm/psr7
```

Tip

Most frameworks already ship with a PSR-18 client — Laravel includes Guzzle, Symfony includes its HttpClient. The package auto-discovers it, so `new Porkbun\Client()` just works.

Quick Start
-----------

[](#quick-start)

Generate your API key and secret on the [API Access](https://porkbun.com/account/api) page. To manage a specific domain via API, enable **API Access** for that domain in your Porkbun control panel.

```
$client = new Porkbun\Client();
$client->authenticate('pk1_your_api_key', 'sk1_your_secret_key');

// Test connectivity
$ping = $client->ping();
echo "Your IP: {$ping->resolvedIp}";

// Domain pricing (no auth required)
$pricing = $client->pricing()->all();
echo "COM: $" . $pricing->find('com')?->registrationPrice;

// Domain-centric operations
$domain = $client->domain('example.com');

// List DNS records
foreach ($domain->dns()->all() as $record) {
    echo "{$record->name} {$record->type->value} {$record->content}\n";
}

// Get SSL certificate
$cert = $domain->ssl();
echo $cert->certificateChain;
```

Advanced configuration```
// Custom PSR-18 HTTP client
$client = new Porkbun\Client($myPsr18Client);

// IPv4-only endpoint (useful for dynamic DNS)
$client->useIpv4Endpoint();
$client->useDefaultEndpoint(); // back to dual-stack

// Switch accounts at runtime
$client->authenticate($account2Key, $account2Secret);
$client->clearAuth(); // back to unauthenticated
```

API Reference
-------------

[](#api-reference)

Note

All endpoints require authentication except **Pricing** — you can query TLD pricing without API keys.

### Pricing (No Auth Required)

[](#pricing-no-auth-required)

```
$pricing = $client->pricing()->all();

$pricing->find('com')?->registrationPrice;  // float
$pricing->find('com')?->renewalPrice;       // float
$pricing->cheapest(10);                     // Top 10 cheapest TLDs
$pricing->tlds();                           // All available TLD keys
```

### Ping (Auth Test)

[](#ping-auth-test)

```
$ping = $client->ping();

$ping->resolvedIp;  // Your IP address (prefers forwarded IP)
$ping->forwardedIp; // Forwarded IP (from X-Forwarded-For header)
$ping->yourIp;      // Raw IP from API response
```

### Domains

[](#domains)

```
// List all domains (iterates all pages automatically)
foreach ($client->domains()->all() as $domain) {
    echo "{$domain->domain} expires {$domain->expireDate?->format('Y-m-d')}\n";
}

// Single page with pagination metadata
$page = $client->domains()->list();
$page->domains(); // DomainCollection (also available via iteration/count/json on $page itself)
$page->hasMore;    // bool — true if more pages exist
$page->nextStart;  // ?int — pass to list() for the next page
$page->start;      // int — current offset

// PaginatedResult is iterable, countable, and JSON-serializable:
count($page);              // number of domains on this page
json_encode($page);        // serializes with pagination metadata
foreach ($page as $domain) { /* ... */ }

// Paginate manually
$page = $client->domains()->list(start: 0, includeLabels: true);
while ($page->hasMore) {
    $page = $client->domains()->list(start: $page->nextStart);
}

// Find a specific domain
$domain = $client->domains()->find('example.com'); // Domain DTO or null

// Bulk auto-renewal management
$client->domains()->enableAutoRenew('example.com', 'other.com');
$client->domains()->disableAutoRenew('example.com');
```

### Domain Details

[](#domain-details)

```
$domain = $client->domain('example.com');
$info = $domain->details();      // Domain DTO (from your account)

$info->domain;                   // 'example.com'
$info->status;                   // 'ACTIVE'
$info->expireDate;               // ?DateTimeImmutable
$info->autoRenew;                // ?bool
$info->tld;                      // 'com'
```

### Domain Availability

[](#domain-availability)

```
$result = $client->domain('example.com')->check();

$result->isAvailable;           // bool
$result->price;                 // ?float (registration price)
$result->type;                  // string — 'standard', 'premium', etc.
$result->priceInCents;          // ?int (e.g., 999 for $9.99)
$result->effectivePrice;        // ?float (promo price if available, else regular)
```

### Domain Registration

[](#domain-registration)

```
$result = $client->domain('newdomain.com')->register(868);

$result->domain;                 // 'newdomain.com'
$result->orderId;                // int
$result->costInCents;            // int
$result->costInDollars;          // float (computed)
$result->balanceInCents;         // int
$result->balanceInDollars;       // float (computed)
```

### DNS Records

[](#dns-records)

Tip

Use the **builder** for validated record creation, or **direct methods** when you need to bypass client-side validation.

```
$dns = $client->domain('example.com')->dns();

// Retrieve
$dns->all();                          // DnsRecordCollection
$dns->find($recordId);               // DnsRecord or null
$dns->findByType('A');                // DnsRecordCollection
$dns->findByType('A', 'www');         // By type and subdomain
// Create (direct)
$result = $dns->create('A', 'www', '192.0.2.1', ttl: 3600);
echo "Created record: {$result->id}";

// Create (builder — recommended)
$result = $dns->createFromBuilder(
    $dns->record()
        ->a('192.0.2.2')
        ->name('api')
        ->ttl(3600)
        ->notes('API server')
);

// Builder convenience methods
$dns->record()->mx('mail.provider.com', priority: 10)->name('mail');
$dns->record()->txt('v=DMARC1; p=reject')->name('_dmarc');
$dns->record()->cname('blog.provider.com')->name('blog');
$dns->record()->aaaa('2001:db8::1')->name('app');

// Enum types are also accepted
use Porkbun\Enum\DnsRecordType;
$dns->findByType(DnsRecordType::A);
$dns->create(DnsRecordType::A, 'www', '192.0.2.1');

// Update (direct or builder)
$dns->update($recordId, 'A', 'www', '192.0.2.3');
$dns->updateFromBuilder($recordId, $dns->record()->a('192.0.2.3')->name('www'));
$dns->updateByType('A', 'www', '192.0.2.3');

// Delete
$dns->delete($recordId);
$dns->deleteByType('A', 'old-subdomain');

// Collection helpers (all collections support first(), last(), count())
$records = $dns->all();
$records->byType('MX');
$records->byName('www');
$records->rootRecords;
$records->byType('A')->first();
```

### DNSSEC Records

[](#dnssec-records)

```
$dnssec = $client->domain('example.com')->dnssec();

$dnssec->all();              // DnssecRecordCollection
$result = $dnssec->create(keyTag: 12345, algorithm: 13, digestType: 2, digest: 'abc123...');
$result->message;          // ?string
$dnssec->delete($keyTag);
```

### Batch DNS Operations

[](#batch-dns-operations)

```
$dns = $client->domain('example.com')->dns();

// Pre-wired batch builder — no need to pass $dns to execute()
$results = $dns->batch()
    ->addRecord('A', 'www', '192.0.2.1')
    ->addRecord('A', 'api', '192.0.2.2')
    ->add($dns->record()->mx('mail.example.com', priority: 10))  // builder-based add
    ->updateRecord($existingId, 'A', 'www', '192.0.2.3', ttl: 3600)
    ->deleteRecord($oldRecordId)
    ->deleteByType('TXT', 'old-subdomain')
    ->execute();

if ($results->hasFailures()) {
    echo "Some operations failed!\n";
}

foreach ($results as $result) {
    if ($result->success) {
        echo "OK: {$result->operation->value}\n";
    } else {
        echo "Failed: {$result->error}\n";
    }
}
```

### SSL Certificates

[](#ssl-certificates)

```
$cert = $client->domain('example.com')->ssl();

$cert->certificateChain;
$cert->privateKey;
$cert->publicKey;
$cert->fullChain;                   // Chain + intermediate
$cert->hasPrivateKey;               // bool
$cert->hasCertificate;              // bool
$cert->hasIntermediateCertificate;  // bool
```

### Nameservers

[](#nameservers)

```
$ns = $client->domain('example.com')->nameservers();

$ns->all();              // NameserverCollection: ['ns1.porkbun.com', 'ns2.porkbun.com']
$ns->update('ns1.custom.com', 'ns2.custom.com');
```

### URL Forwarding

[](#url-forwarding)

```
$forwards = $client->domain('example.com')->urlForwarding();

$forwards->all();              // UrlForwardCollection
$result = $forwards->create('https://destination.example.com', 'temporary', subdomain: 'go');
$result->message;              // ?string
$forwards->delete($recordId);
```

### Glue Records

[](#glue-records)

```
$glue = $client->domain('example.com')->glueRecords();

$glue->all();              // GlueRecordCollection
$result = $glue->create('ns1', '192.0.2.1', '192.0.2.2');
$result->message;          // ?string
$glue->update('ns1', '192.0.2.10');
$glue->delete('ns1');      // OperationResult
```

### Auto-Renewal

[](#auto-renewal)

```
$autoRenew = $client->domain('example.com')->autoRenew();

$result = $autoRenew->enable();   // AutoRenewResult
$result->success;                 // bool
$result->message;                 // ?string

$autoRenew->disable();
```

Error Handling
--------------

[](#error-handling)

All exceptions implement `Porkbun\Exception\ExceptionInterface` for unified catching:

```
use Porkbun\Exception\ApiException;
use Porkbun\Exception\AuthenticationException;
use Porkbun\Exception\InvalidArgumentException;
use Porkbun\Exception\NetworkException;
use Porkbun\Exception\ExceptionInterface;

try {
    $client->domains()->list();
} catch (AuthenticationException $e) {
    // Invalid or missing API credentials (403)
} catch (ApiException $e) {
    // API returned an error (4xx/5xx)
    $e->getStatusCode();
    $e->getRequest();
    $e->getResponse();
} catch (NetworkException $e) {
    // HTTP/connection failure
    $e->getRequest();
} catch (InvalidArgumentException $e) {
    // Invalid parameters (bad DNS type, empty domain list, etc.)
} catch (ExceptionInterface $e) {
    // Catch-all for any library exception
}
```

Tip

If the default endpoint is unreachable, fall back to `$client->useIpv4Endpoint()`. See [`08-error-handling.php`](examples/08-error-handling.php) for the full pattern.

Laravel Integration
-------------------

[](#laravel-integration)

The package auto-registers via Laravel's package discovery. The service provider is deferred — the client is only instantiated when you use it.

Add credentials to `.env`:

```
PORKBUN_API_KEY=pk1_your_key
PORKBUN_SECRET_KEY=sk1_your_secret
PORKBUN_ENDPOINT=default   # or 'ipv4' for IPv4-only
```

Optionally publish the config:

```
php artisan vendor:publish --tag=porkbun-config
```

### Facade

[](#facade)

```
use Porkbun\Laravel\Facades\Porkbun;

$domains = Porkbun::domains()->list();
$records = Porkbun::domain('example.com')->dns()->all();
```

### Dependency Injection

[](#dependency-injection)

```
use Porkbun\Client;

class DnsController
{
    public function index(Client $client)
    {
        return $client->domain('example.com')->dns()->all();
    }
}
```

Examples
--------

[](#examples)

See the [`examples/`](examples/) directory for runnable scripts:

- [`01-ping.php`](examples/01-ping.php) - Auth test and IPv4 endpoint switching
- [`02-pricing.php`](examples/02-pricing.php) - Public pricing API, cheapest TLDs, iteration
- [`03-domains.php`](examples/03-domains.php) - List domains, pagination, expiring soon, availability check
- [`04-dns.php`](examples/04-dns.php) - DNS CRUD with direct methods, collection helpers
- [`05-dns-builder.php`](examples/05-dns-builder.php) - Fluent builder, convenience methods, immutable templates
- [`06-dns-batch.php`](examples/06-dns-batch.php) - Batch operations, mixed create/edit/delete
- [`07-domain-services.php`](examples/07-domain-services.php) - Nameservers, URL forwarding, glue records, SSL, auto-renew
- [`08-error-handling.php`](examples/08-error-handling.php) - Exception hierarchy, endpoint fallback pattern
- [`09-dynamic-dns.php`](examples/09-dynamic-dns.php) - Real-world dynamic DNS updater recipe
- [`10-multi-account.php`](examples/10-multi-account.php) - Account switching, public/auth/clearAuth flow
- [`11-laravel.php`](examples/11-laravel.php) - Facade usage, dependency injection, Artisan commands

Development
-----------

[](#development)

```
composer install
composer run check    # code style + static analysis + tests
composer run fix      # auto-fix style issues
composer run test     # run test suite
```

License
-------

[](#license)

MIT License. See [LICENSE](LICENSE) for details.

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance90

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity58

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

2

Last Release

100d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/cda30b9e506cc0471aaff9890f9a144d8ef2cd2cb2d90ed090ce129f09c3e7db?d=identicon)[glebovdev](/maintainers/glebovdev)

---

Top Contributors

[![glebovdev](https://avatars.githubusercontent.com/u/2257771?v=4)](https://github.com/glebovdev "glebovdev (21 commits)")

---

Tags

api-clientdnsdomainlaravelphpporkbunpsr-18sslapidnssslapi clientdomainporkbundomain registration

###  Code Quality

TestsPest

Static AnalysisPHPStan, Rector

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/porkbun-php-client/health.svg)

```
[![Health](https://phpackages.com/badges/porkbun-php-client/health.svg)](https://phpackages.com/packages/porkbun-php-client)
```

###  Alternatives

[telnyx/telnyx-php

Official Telnyx PHP SDK — APIs for Voice, SMS, MMS, WhatsApp, Fax, SIP Trunking, Wireless IoT, Call Control, and more. Build global communications on Telnyx's private carrier-grade network.

35729.6k2](/packages/telnyx-telnyx-php)[mollie/mollie-api-php

Mollie API client library for PHP. Mollie is a European Payment Service provider and offers international payment methods such as Mastercard, VISA, American Express and PayPal, and local payment methods such as iDEAL, Bancontact, SOFORT Banking, SEPA direct debit, Belfius Direct Net, KBC Payment Button and various gift cards such as Podiumcadeaukaart and fashioncheque.

60315.4M74](/packages/mollie-mollie-api-php)[openai-php/client

OpenAI PHP is a supercharged PHP API client that allows you to interact with the Open AI API

5.8k26.1M294](/packages/openai-php-client)[tempest/framework

The PHP framework that gets out of your way.

2.2k31.1k12](/packages/tempest-framework)[getbrevo/brevo-php

Official Brevo provided RESTFul API V3 php library

1003.6M46](/packages/getbrevo-brevo-php)[flow-php/flow

PHP ETL - Extract Transform Load - Data processing framework

84735.1k](/packages/flow-php-flow)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
