foundry-co/cloudflare

PHP SDK for the Cloudflare API, generated from the official OpenAPI spec

Maintainers

Package info

github.com/foundry-co/php-cloudflare-sdk

pkg:composer/foundry-co/cloudflare

Statistics

Installs: 3

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.2.1 2026-06-10 02:27 UTC

This package is auto-updated.

Last update: 2026-06-10 02:28:23 UTC


README

A PHP SDK for the Cloudflare API, auto-generated from the official OpenAPI spec. Uses Guzzle for HTTP and Valinor for typed response deserialization.

Requirements

  • PHP 8.1+
  • guzzlehttp/guzzle ^7.0
  • cuyz/valinor ^2.0

Installation

composer require foundry-co/cloudflare

Laravel

The package includes first-class Laravel support via a service provider and facade that are auto-discovered by Laravel's package auto-discovery.

Installation

composer require foundry-co/cloudflare

Add the following to your .env:

CLOUDFLARE_API_TOKEN=your-api-token
CLOUDFLARE_ACCOUNT_ID=your-account-id   # optional
CLOUDFLARE_BASE_URL=https://api.cloudflare.com/client/v4  # optional

That's it — the CloudflareServiceProvider is registered automatically and the Cloudflare facade is available immediately.

Publishing the config

php artisan vendor:publish --tag=cloudflare-config

This copies config/cloudflare.php into your application's config directory.

Usage

use FoundryCo\Cloudflare\Laravel\Facades\Cloudflare;

// Via facade
$records = Cloudflare::zone('zone-id')->dnsRecords()->list();

// Via dependency injection
use FoundryCo\Cloudflare\CloudflareClient;

class MyController extends Controller
{
    public function __construct(private CloudflareClient $cloudflare) {}

    public function index()
    {
        return $this->cloudflare->zone('zone-id')->dnsRecords()->list();
    }
}

Authentication

All requests authenticate with a Cloudflare API Token. Create tokens in the Cloudflare dashboard under My Profile > API Tokens.

use FoundryCo\Cloudflare\CloudflareClient;

$cf = new CloudflareClient(apiToken: 'your-api-token');

Working with Responses

Methods return typed PHP objects deserialized via Valinor. List endpoints that include pagination metadata return a PaginatedResponse:

use FoundryCo\Cloudflare\Support\PaginatedResponse;

$result = $cf->accounts()->list();

// PaginatedResponse
$result->items;       // array of typed objects
$result->total;       // total record count
$result->page;        // current page
$result->perPage;     // records per page
$result->totalPages;  // total pages
$result->hasMorePages(); // bool
foreach ($result as $account) { ... }

// Single-item responses return typed objects directly
$account = $cf->accounts()->listGet(); // AccountsDetails object
$account->id;
$account->name;

Error Handling

The client throws CloudflareException on any non-2xx response. It is thrown automatically — you do not need to check the response yourself.

use FoundryCo\Cloudflare\Exceptions\CloudflareException;

try {
    $result = $cf->dnsRecords()->get('zone-id', 'record-id');
} catch (CloudflareException $e) {
    $e->statusCode; // HTTP status
    $e->errors;     // array of ['code' => int, 'message' => string]
    $e->getMessage(); // concatenated error messages
}

Resource Access

Resources are available directly from the client or scoped to a zone via zone().

Direct access (account-scoped or global resources)

$cf->accounts()->list();
$cf->members()->list();
$cf->dnsRecords();        // zone ID must be baked in via zone()

Zone-scoped access

Pass a zone ID to zone() and then chain the resource:

$zone = $cf->zone('zone-id');

$zone->dnsRecords()->list();
$zone->dnsRecords()->get('record-id');
$zone->cacheSettings()->get();
$zone->rulesets()->list();

Resources

Accounts

$cf->accounts()->list();
$cf->accounts()->list(name: 'Acme', direction: AccountsDirection::Asc);
$cf->accounts()->listGet(); // single account details

Account Members

$cf->members()->list();

DNS Records

$dns = $cf->zone('zone-id')->dnsRecords();

$dns->list();
$dns->list(type: DNSRecordsForAZoneType::A, name: 'www.example.com');
$dns->list(proxied: true, perPage: 100);
$dns->get('record-id');
$dns->create();   // pass a request object
$dns->update('record-id');
$dns->delete('record-id');

// Batch operations
$dns->batch($request);

// BIND zone file
$dns->export();
$dns->import();
$dns->scan();
$dns->review();

DNS Settings

$cf->zone('zone-id')->dnsSettings()->get();

Zones

$cf->zone()->list();           // ZoneResource also exposes zone-level list/get

Rulesets

$rulesets = $cf->zone('zone-id')->rulesets();

$rulesets->list();
$rulesets->get('ruleset-id');
$rulesets->create($request);
$rulesets->update('ruleset-id', $request);
$rulesets->delete('ruleset-id');

Cache

$cf->zone('zone-id')->cacheSettings()->get();
$cf->zone('zone-id')->cacheSettings()->update($request);

Workers

$cf->workerScript()->list();
$cf->workerScript()->get('script-name');
$cf->workers()->list();

Workers KV

$cf->workersKVNamespace()->list();
$cf->workersKVNamespace()->create($request);
$cf->workersKVNamespace()->delete('namespace-id');

$cf->keys()->list();
$cf->values()->get('namespace-id', 'key');

D1

$cf->d1()->list();
$cf->d1()->create($request);
$cf->d1()->get('database-id');
$cf->d1()->delete('database-id');

R2

$cf->r2Bucket()->list();
$cf->r2Bucket()->create($request);
$cf->r2Bucket()->get('bucket-name');
$cf->r2Bucket()->delete('bucket-name');
$cf->r2Object()->get('bucket-name', 'object-key');

Pages

$cf->pagesProject()->list();
$cf->pagesProject()->get('project-name');
$cf->pagesProject()->create($request);
$cf->pagesProject()->delete('project-name');

$cf->pagesDeployment()->list('project-name');
$cf->pagesDeployment()->delete('project-name', 'deployment-id');

Stream

$cf->streamVideos()->list();
$cf->streamVideos()->get('video-id');
$cf->streamVideos()->delete('video-id');
$cf->streamLiveInputs()->list();
$cf->streamSigningKeys()->list();

Cloudflare Images

$cf->cloudflareImages()->list();
$cf->cloudflareImages()->get('image-id');
$cf->cloudflareImages()->delete('image-id');
$cf->cloudflareImagesVariants()->list();

Cloudflare Tunnels

$cf->cloudflareTunnel()->list();
$cf->cloudflareTunnel()->create($request);
$cf->cloudflareTunnel()->delete('tunnel-id');
$cf->cloudflareTunnelConfiguration()->get('tunnel-id');
$cf->cloudflareTunnelConfiguration()->update('tunnel-id', $request);

Zero Trust / Access

$cf->accessApplications()->list();
$cf->accessApplications()->get('app-id');
$cf->accessApplications()->create($request);
$cf->accessApplications()->update('app-id', $request);
$cf->accessApplications()->delete('app-id');

$cf->accessGroups()->list();
$cf->accessIdentityProviders()->list();
$cf->accessServiceTokens()->list();
$cf->accessReusablePolicies()->list();
$cf->zeroTrustOrganization()->get();
$cf->zeroTrustGatewayRules()->list();
$cf->zeroTrustLists()->list();

Load Balancing

$cf->loadBalancerPools()->list();
$cf->loadBalancerPools()->create($request);
$cf->loadBalancerMonitors()->list();
$cf->loadBalancerMonitors()->create($request);

Logpush

$cf->logpushJobs()->list();
$cf->logpushJobs()->create($request);
$cf->logpushJobs()->update('job-id', $request);
$cf->logpushJobs()->delete('job-id');

Vectorize

$cf->vectorize()->list();
$cf->vectorize()->create($request);
$cf->vectorize()->get('index-name');
$cf->vectorize()->delete('index-name');

AI Gateway

$cf->aiGatewayGateways()->list();
$cf->aiGatewayLogs()->list('gateway-id');

Workers AI

$cf->workersAI()->run($request);
$cf->workersAITextGeneration()->run($request);
$cf->workersAITextEmbeddings()->run($request);

Hyperdrive

$cf->hyperdrive()->list();
$cf->hyperdrive()->create($request);
$cf->hyperdrive()->get('config-id');
$cf->hyperdrive()->delete('config-id');

Queues

$cf->queue()->list();
$cf->queue()->create($request);
$cf->queue()->delete('queue-id');

Radar

$cf->radarHTTP()->timeseries($request);
$cf->radarLayer7Attacks()->timeseries($request);
$cf->radarBGP()->timeseries($request);
$cf->radarDNS()->timeseries($request);

Notifications

$cf->notificationPolicies()->list();
$cf->notificationPolicies()->create($request);
$cf->notificationWebhooks()->list();
$cf->notificationAlertTypes()->list();

Registrar

$cf->registrarDomains()->list();
$cf->registrarDomains()->get('domain-name');
$cf->registrarDomains()->update('domain-name', $request);

URL Scanner

$cf->urlScanner()->scan($request);
$cf->urlScanner()->get('scan-id');

Intelligence

$cf->ipIntelligence()->get('1.2.3.4');
$cf->domainIntelligence()->get('example.com');
$cf->urlIntelligence()->get('https://example.com');
$cf->whoisRecord()->get('example.com');
$cf->asnIntelligence()->get(13335);

Turnstile

$cf->turnstile()->list();
$cf->turnstile()->create($request);
$cf->turnstile()->delete('widget-id');

User

$cf->user()->get();
$cf->user()->update($request);
$cf->userAPITokens()->list();
$cf->usersAccountMemberships()->list();

Pagination

List endpoints that return result_info automatically return a PaginatedResponse. Iterate pages manually:

$page = 1;
$allRecords = [];

do {
    $result = $cf->zone('zone-id')->dnsRecords()->list(page: $page, perPage: 100);
    $allRecords = array_merge($allRecords, $result->items);
    $page++;
} while ($result->hasMorePages());

Testing

The CloudflareClient constructor accepts a custom HttpClient instance, which you can substitute in tests:

use FoundryCo\Cloudflare\CloudflareClient;
use FoundryCo\Cloudflare\Http\HttpClient;

$mockHttp = $this->createMock(HttpClient::class);
// configure expectations...

$cf = new CloudflareClient(apiToken: 'fake', http: $mockHttp);

Code Generation

The SDK is auto-generated from the official Cloudflare OpenAPI spec. To regenerate:

php generator/bin/generate

License

MIT