PHP code example of jcolombo / optmyzr-api-php

1. Go to this page and download the library: Download jcolombo/optmyzr-api-php library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

jcolombo / optmyzr-api-php example snippets


use Jcolombo\OptmyzrApiPhp\Optmyzr;

$optmyzr = Optmyzr::connect(getenv('OPTMYZR_API_TOKEN'));

use Jcolombo\OptmyzrApiPhp\Optmyzr;

$optmyzr = Optmyzr::connect(getenv('OPTMYZR_API_TOKEN'));

// Which operations does this token actually have access to?
// (Also the cheapest call in the API, so a good liveness check.)
if (!$optmyzr->supports('Accounts')) {
    throw new RuntimeException('This token has no Accounts access.');
}

// Every ad account the token can see
foreach ($optmyzr->accounts()->fetch() as $id => $account) {
    // $id is a stable synthetic identity — safe as a local database key
    echo $id, ' ', $account->accountName(), ' (', $account->accountType(), ")\n";
}

// One client's pending work
$acct = $optmyzr->account('123-456-7890', 'AdWords');

$suggestions = $acct->suggestions()->fetch();
echo $suggestions->totalChanges(), " pending changes\n";

foreach ($acct->alerts()->fetch() as $alert) {
    echo $alert->alertType(), ': ', $alert->alertDetails(), "\n";
}

// Who applied what, last month
$history = $optmyzr->history()
    ->between('2026-07-01', '2026-07-31')
    ->fetch();

foreach ($history->changesByUser() as $email => $changes) {
    echo $email, ': ', $changes, " changes\n";
}

// Overdue Blueprint tasks, across every page
$overdue = $optmyzr->blueprintTasks()->overdue()->fetchAll();
echo $overdue->count(), ' overdue across ', $overdue->pagesFetched(), " pages\n";

Optmyzr::disconnect();

$suggestion = $optmyzr->suggestions()->fetch()->first();

$suggestion->naturalKey();   // "google|123-456-7890|Search Terms"
$suggestion->id();           // "optsug_1f3c8a…"   stable
$suggestion->fingerprint();  // "9b21ef…"          moves on any change

// If real data shows a key is not unique, correct it without a package release:
Configuration::set('identity.keys.activeAlert', ['accountType', 'accountId', 'alertType', 'link', 'alertDetails']);

$alerts = $optmyzr->alerts()->fetch();
if ($alerts->hasCollisions()) {
    // Two distinct records share an id — the configured key is missing a field.
    print_r($alerts->collisions());
}

// Server-side: the endpoint has an accountId parameter
$optmyzr->metrics()->accountId('123-456-7890');

// Client-side: the Accounts endpoint has no accountId parameter, so where()
// filters in PHP after the rows arrive
$accounts = $optmyzr->accounts()->where('accountId', '123-456-7890');
$accounts->fetch();

print_r($accounts->explain());
// [
//   'endpoint'  => 'Accounts',
//   'paginated' => false,
//   'server'    => [],
//   'client'    => ['accountId = 123-456-7890'],
//   'sort'      => null,
//   'take'      => null,
// ]

$optmyzr->suggestions()
    ->filter(fn ($s) => $s->changes() > 5, 'changes > 5')
    ->sortBy('changes', SortDirection::DESC)   // no sort parameter exists in the API
    ->take(10)
    ->fetch();

$acct = $optmyzr->account('123-456-7890', 'AdWords');

$acct->metrics()->fetch();          // accountId + accountType server-side
$acct->alerts()->fetch();           // accountId + accountType server-side
$acct->suggestions()->fetch();      // accountId + accountType server-side
$acct->history()->fetch();          // accountId + accountType server-side
$acct->workoutHistory()->fetch();   // accountId server-side, platform matched in PHP
$acct->blueprintTasks()->fetch();   // accountId server-side

$acct->detail();                    // the Accounts row for this account, or null

foreach ($optmyzr->metrics()->fetch()->byAccount() as $key => $group) {
    // $key is 'google|123-456-7890'; $group is a full sub-collection
    echo $key, ': ', $group->averageQualityScore(), "\n";
}

$optmyzr->account('123-456-7890')->blueprintTasks()->fetchAll();

$tasks = $optmyzr->blueprintTasks()->status('Open')->fetchAll();
echo $tasks->count(), ' tasks across ', $tasks->pagesFetched(), " pages\n";

// Resume a partial sweep
$optmyzr->blueprintTasks()->page(4)->fetchAll();

$metrics = $optmyzr->metrics()->fetch();
$metrics->entryCount();   // raw rows the API returned — exactly 1000 is suspicious
$metrics->totalCount();   // distinct records held

$previous = $store->loadSnapshot('optmyzr.suggestions');   // [id => fingerprint]
$current  = $optmyzr->suggestions()->fetch();

$diff = $current->diff($previous);

$store->insert($diff->added());       // identities never seen before
$store->update($diff->changed());     // same identity, different contents
$store->retire($diff->removed());     // identities absent from this fetch
// $diff->unchanged() is skipped entirely — no write, no churn

$store->saveSnapshot('optmyzr.suggestions', $diff->snapshot());

try {
    $account->save();
} catch (ReadOnlyResourceException $e) {
    // "Optmyzr Account is read-only: save() is not available. The Optmyzr User
    //  Data API v1 exposes GET operations only — it has no write endpoints."
}

$account->accountType();       // 'AdWords' — exactly what the API sent
$account->accountTypeEnum();   // AccountType::ADWORDS, or null if unrecognised
$account->platform();          // 'google' — normalised, rename-proof

$optmyzr->blueprintTasks()->fetch()->distinct('status');

Configuration::set('enabled.cache', true);
Configuration::set('path.cache', '/var/cache/myapp');
Configuration::set('cache.lifespan', 900);   // seconds

Cache::registerCacheMethods($readCallable, $writeCallable, $clearCallable);

ScrubCache::invalidate($token);   // this connection's entries only
ScrubCache::invalidate();         // everything

Configuration::set('rateLimit.minDelayMs', 100);
Configuration::set('rateLimit.perMinute', 600);

Configuration::set('enabled.logging', true);
Configuration::set('path.logs', '/var/log/myapp');
Configuration::set('error.handlers.fatal', ['log']);   // drop the default 'echo'
Configuration::set('error.triggerPhpErrors', true);    // escalate to PHP errors

use Jcolombo\OptmyzrApiPhp\Configuration;

Configuration::load('/path/to/optmyzrapi.config.json');   // merge a file
Configuration::overload('/path/to/dir');                  // dir/optmyzrapi.config.json, ignored if absent
Configuration::set('devMode', true);                      // one value

use Jcolombo\OptmyzrApiPhp\Entity\EntityMap;

class MyAccount extends \Jcolombo\OptmyzrApiPhp\Entity\Resource\Account
{
    public function customerNumber(): ?string
    {
        return $this->accountName() === null ? null : substr($this->accountName(), 0, 4);
    }
}

EntityMap::overload('account', MyAccount::class);

// The facade now hydrates your subclass
$optmyzr->accounts()->fetch()->first()->customerNumber();

$body = $optmyzr->rawGet('UserData/V1/SomeNewEndpoint', ['accountId' => '123']);
$response = $optmyzr->request('GET', 'SomeOther/Path');
bash
composer