budgetlens/laravel-copernica-rest-client

A fluent PHP (Laravel) REST client for the Copernica Marketing Software API v4

Maintainers

Package info

github.com/123lens/laravel-copernica-rest-client

pkg:composer/budgetlens/laravel-copernica-rest-client

Statistics

Installs: 19

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.2 2026-04-10 07:55 UTC

This package is auto-updated.

Last update: 2026-04-10 07:56:17 UTC


README

A fluent, modern PHP (Laravel) client for the Copernica Marketing Software REST API v4. Built with clean architecture, strongly-typed DTOs, and first-class Laravel support.

Requirements

  • PHP 8.3 or higher
  • Composer
  • A Copernica account with a REST API v4 access token - Generate your access_token
  • GuzzleHTTP 7.0+ (installed automatically via Composer)

Installation

composer require budgetlens/laravel-copernica-rest-client

Laravel

The package supports Laravel auto-discovery. After installation, add your access token to .env:

COPERNICA_ACCESS_TOKEN=your-api-token-here

Optionally publish the configuration file:

php artisan vendor:publish --provider="Budgetlens\Copernica\RestClient\CopernicaServiceProvider"

This publishes config/copernica.php where you can configure:

Option Env Variable Default
access_token COPERNICA_ACCESS_TOKEN ""
base_url COPERNICA_BASE_URL https://api.copernica.com/v4
timeout COPERNICA_TIMEOUT 30

Tip: Use https://rest.copernica.com/v4 as base URL for large dataset retrieval.

Standalone (without Laravel)

use Budgetlens\Copernica\RestClient\CopernicaClient;

$client = new CopernicaClient(
    accessToken: 'your-api-token-here',
    baseUrl: 'https://api.copernica.com/v4', // optional
    timeout: 30, // optional
);

Quick Start

// Laravel (via Facade)
use Budgetlens\Copernica\RestClient\Facades\Copernica;

$databases = Copernica::databases()->list();

// Laravel (via dependency injection)
use Budgetlens\Copernica\RestClient\CopernicaClient;

public function index(CopernicaClient $copernica)
{
    $databases = $copernica->databases()->list();
}

// Standalone
$client = new CopernicaClient('your-token');
$databases = $client->databases()->list();

Usage

Account Information

// Get account identity
$identity = $client->identity();

// Get API consumption/usage
$consumption = $client->consumption();

Databases

// List all databases
$databases = $client->databases()->list();

// Get a single database
$database = $client->database(123)->get();

echo $database->name;
echo $database->description;

// Create a new database
$id = $client->databases()->create([
    'name' => 'Newsletter',
    'description' => 'Newsletter subscribers',
]);

// Update a database
$client->database(123)->update([
    'description' => 'Updated description',
]);

// Copy a database
$newId = $client->database(123)->copy([
    'name' => 'Newsletter Copy',
]);

// Delete a database
$client->database(123)->delete();

Fields

// List database fields
$fields = $client->database(123)->fields()->list();

// Create a field
$fieldId = $client->database(123)->fields()->create([
    'name' => 'email',
    'type' => 'email',
]);

// Update a field
$client->database(123)->fields()->update($fieldId, [
    'name' => 'email_address',
]);

// Delete a field
$client->database(123)->fields()->delete($fieldId);

// Collection fields work the same way
$fields = $client->database(123)->collection(456)->fields()->list();

Profiles

// List profiles in a database
$profiles = $client->database(123)->profiles()->list();

// Paginated iteration (lazy-loads all pages)
foreach ($client->database(123)->profiles()->each() as $profile) {
    echo $profile->field('email');
}

// Filter profiles by field values
$results = $client->database(123)->profiles()->where('email', 'john@example.com');

// Filter by multiple fields
$results = $client->database(123)->profiles()->where([
    'city' => 'Amsterdam',
    'newsletter' => 'yes',
]);

// Get a single profile
$profile = $client->database(123)->profile(456)->get();

echo $profile->id;
echo $profile->field('email');
echo $profile->fields;    // all fields as array
echo $profile->interests; // interests array
echo $profile->createdAt; // DateTimeImmutable

// Create a profile
$profileId = $client->database(123)->profiles()->create([
    'fields' => [
        'email' => 'john@example.com',
        'firstname' => 'John',
        'lastname' => 'Doe',
    ],
    'interests' => [
        'newsletter' => true,
    ],
]);

// Update a profile
$client->database(123)->profile(456)->update([
    'fields' => [
        'lastname' => 'Smith',
    ],
]);

// Get/update profile fields directly
$fields = $client->database(123)->profile(456)->fields();
$client->database(123)->profile(456)->updateFields(['city' => 'Rotterdam']);

// Get/update interests
$interests = $client->database(123)->profile(456)->interests();
$client->database(123)->profile(456)->updateInterests(['newsletter' => true]);

// Delete a profile
$client->database(123)->profile(456)->delete();

Subprofiles

// List subprofiles of a profile (optionally scoped to a collection)
$subprofiles = $client->database(123)->profile(456)->subprofiles()->list();
$subprofiles = $client->database(123)->profile(456)->subprofiles(collectionId: 789)->list();

// List subprofiles in a collection
$subprofiles = $client->database(123)->collection(789)->subprofiles()->list();

// Paginated iteration
foreach ($client->database(123)->profile(456)->subprofiles()->each() as $subprofile) {
    echo $subprofile->field('order_number');
}

// Get a single subprofile
$subprofile = $client->database(123)->profile(456)->subprofile(101)->get();

// Create a subprofile
$subId = $client->database(123)->profile(456)->subprofiles()->create([
    'fields' => [
        'order_number' => 'ORD-001',
        'amount' => '49.95',
    ],
]);

// Update a subprofile
$client->database(123)->profile(456)->subprofile(101)->update([
    'fields' => ['amount' => '59.95'],
]);

// Delete a subprofile
$client->database(123)->profile(456)->subprofile(101)->delete();

Collections

// List collections in a database
$collections = $client->database(123)->collections()->list();

// Get a single collection
$collection = $client->database(123)->collection(456)->get();

// Create a collection
$id = $client->database(123)->collections()->create([
    'name' => 'Orders',
]);

// Update a collection
$client->database(123)->collection(456)->update([
    'name' => 'Purchase Orders',
]);

// Manage unsubscribe behavior
$settings = $client->database(123)->collection(456)->unsubscribe();
$client->database(123)->collection(456)->setUnsubscribe([
    'behavior' => 'update',
    'field' => 'newsletter',
]);

Views

// List views for a database
$views = $client->database(123)->views()->list();

// Get a single view
$view = $client->database(123)->view(456)->get();

// Create a view
$viewId = $client->database(123)->views()->create([
    'name' => 'Active subscribers',
    'description' => 'All active newsletter subscribers',
]);

// Get profiles from a view
$profiles = $client->database(123)->view(456)->profiles()->list();

// Paginate profiles in a view
foreach ($client->database(123)->view(456)->eachProfile() as $profile) {
    // ...
}

// Get profile IDs from a view
$ids = $client->database(123)->view(456)->profileIds();

// Manage view rules
$rules = $client->database(123)->view(456)->rules();
$ruleId = $client->database(123)->view(456)->createRule([
    'name' => 'Is active',
    'conditions' => [
        ['type' => 'field', 'field' => 'active', 'value' => 'yes'],
    ],
]);

// Rebuild a view
$client->database(123)->view(456)->rebuild();

// Update / delete
$client->database(123)->view(456)->update(['name' => 'Renamed view']);
$client->database(123)->view(456)->delete();

Emailings

// --- HTML Emailings ---

// List all HTML emailings
$emailings = $client->emailings()->list();

// Paginate emailings
foreach ($client->emailings()->each() as $emailing) {
    echo $emailing->subject;
}

// Get scheduled emailings
$scheduled = $client->emailings()->scheduled();

// Get a single emailing
$emailing = $client->emailing(123)->get();

echo $emailing->id;
echo $emailing->subject;
echo $emailing->fromAddress;

// Create an emailing
$id = $client->emailings()->create([
    'subject' => 'Monthly newsletter',
    'database' => 123,
    'template' => 456,
]);

// --- Drag & Drop Emailings ---

$emailings = $client->dragAndDropEmailings()->list();
$emailing = $client->dragAndDropEmailing(123)->get();

// --- Statistics ---

$stats = $client->emailing(123)->statistics();

echo $stats->destinations;
echo $stats->deliveries;
echo $stats->impressions;
echo $stats->clicks;
echo $stats->unsubscribes;
echo $stats->abuses;
echo $stats->errors;

// --- Destinations ---

$destinations = $client->emailing(123)->destinations();

// Paginate destinations
foreach ($client->emailing(123)->eachDestination() as $dest) {
    echo $dest->profileId;
    echo $dest->timestamp; // DateTimeImmutable
}

// --- Result details ---

$deliveries   = $client->emailing(123)->deliveries();
$impressions  = $client->emailing(123)->impressions();
$clicks       = $client->emailing(123)->clicks();
$errors       = $client->emailing(123)->errors();
$unsubscribes = $client->emailing(123)->unsubscribes();
$abuses       = $client->emailing(123)->abuses();

// Get the emailing snapshot (the email as it was sent)
$snapshot = $client->emailing(123)->snapshot();

Webhooks

// List all webhooks
$webhooks = $client->webhooks()->list();

// Get a single webhook
$webhook = $client->webhook(123)->get();

echo $webhook->handler;
echo $webhook->url;
echo $webhook->trigger;

// Create a webhook
$id = $client->webhooks()->create([
    'handler' => 'profile',
    'url' => 'https://example.com/webhook',
    'trigger' => 'create',
    'database' => 123,
]);

// Update a webhook
$client->webhook(123)->update([
    'url' => 'https://example.com/webhook-v2',
]);

// Delete a webhook
$client->webhook(123)->delete();

Raw API Access

For endpoints not yet covered by the client, you can use the raw HTTP methods:

$response = $client->get('some/endpoint', ['param' => 'value']);
$response = $client->post('some/endpoint', ['key' => 'value']);
$response = $client->put('some/endpoint', ['key' => 'value']);
$response = $client->delete('some/endpoint');

Error Handling

The client throws specific exceptions for different error scenarios:

use Budgetlens\Copernica\RestClient\Exceptions\AuthenticationException;
use Budgetlens\Copernica\RestClient\Exceptions\NotFoundException;
use Budgetlens\Copernica\RestClient\Exceptions\ValidationException;
use Budgetlens\Copernica\RestClient\Exceptions\RateLimitException;
use Budgetlens\Copernica\RestClient\Exceptions\CopernicaException;

try {
    $profile = $client->database(123)->profile(999)->get();
} catch (AuthenticationException $e) {
    // 401/403 - Invalid or expired access token
} catch (NotFoundException $e) {
    // 404 - Resource not found
} catch (ValidationException $e) {
    // 400/422 - Invalid request data
    $details = $e->errors; // detailed error info from the API
} catch (RateLimitException $e) {
    // 429 - Too many requests
} catch (CopernicaException $e) {
    // Any other API error
}

All exceptions extend CopernicaException, which extends RuntimeException. You can catch CopernicaException to handle all API errors at once.

DTOs

All API responses are mapped to strongly-typed Data Transfer Objects:

DTO Description
Database Database with ID, name, description, archived status, fields, interests, collections
Collection Database collection with ID, name, parent database, and fields
Field Database/collection field with type, length, and display settings
Profile Contact record with fields, interests, and timestamps
Subprofile Collection subprofile with fields and timestamps
View Database view with rules and rebuild status
Emailing Email campaign (HTML or Drag & Drop) with content details
EmailingDestination Single emailing recipient with profile/subprofile ID
EmailingStatistics Aggregated statistics (deliveries, impressions, clicks, etc.)
Webhook Webhook subscription with handler, URL, and trigger type

All DTOs implement the FromArray contract and are immutable (readonly properties).

Architecture

src/
├── CopernicaClient.php          # Main entry point
├── CopernicaServiceProvider.php # Laravel service provider
├── Facades/
│   └── Copernica.php            # Laravel facade
├── Http/
│   ├── CopernicaHttpClient.php  # Guzzle-based HTTP layer
│   └── PaginatedResponse.php    # Lazy-loading paginator
├── Resources/
│   ├── Resource.php             # Abstract base resource
│   ├── DatabaseResource.php     # /database endpoints
│   ├── ProfileResource.php      # /profile endpoints
│   ├── SubprofileResource.php   # /subprofile endpoints
│   ├── CollectionResource.php   # /collection endpoints
│   ├── FieldResource.php        # Field management
│   ├── ViewResource.php         # /view endpoints
│   ├── EmailingResource.php     # Emailing endpoints
│   └── WebhookResource.php      # /webhook endpoints
├── DTOs/
│   ├── Contracts/FromArray.php  # DTO factory contract
│   ├── Concerns/ParsesDate.php  # Date parsing trait
│   ├── Database.php
│   ├── Collection.php
│   ├── Field.php
│   ├── Profile.php
│   ├── Subprofile.php
│   ├── View.php
│   ├── Emailing.php
│   ├── EmailingDestination.php
│   ├── EmailingStatistics.php
│   └── Webhook.php
└── Exceptions/
    ├── CopernicaException.php        # Base exception
    ├── AuthenticationException.php   # 401/403
    ├── NotFoundException.php         # 404
    ├── ValidationException.php       # 400/422
    └── RateLimitException.php        # 429

Testing

composer test

Tests use PHPUnit 11 and Orchestra Testbench for Laravel integration testing.

License

MIT License. See LICENSE for details.