zammad/zammad-api-client-php
Installation:
composer require zammad/zammad-api-client-php
Ensure your project uses PHP 7.2+.
Basic Client Initialization:
use ZammadAPIClient\Client;
$client = new Client([
'url' => 'https://your-zammad-instance.com',
'username' => 'api-user@example.com',
'password' => 'secure-password',
]);
First Use Case:
Fetch a ticket by ID (e.g., ID 1):
use ZammadAPIClient\ResourceType;
$ticket = $client->resource(ResourceType::TICKET)->get(1);
echo $ticket->getValue('title'); // Output ticket title
examples directory in the repo for practical use cases.search, save, delete).$ticket = $client->resource(ResourceType::TICKET);
$ticket->setValue('title', 'New Issue');
$ticket->setValue('priority_id', 1);
$ticket->save(); // Persists to Zammad
$ticket = $client->resource(ResourceType::TICKET)->get(1);
$title = $ticket->getValue('title');
$ticket->setValue('title', 'Updated Title');
$ticket->save();
$ticket->delete(); // Requires fetching the resource first
$tickets = $client->resource(ResourceType::TICKET)->search('urgent');
$tickets = $client->resource(ResourceType::TICKET)->search('title:"High Priority" AND state_id:3');
$tickets = $client->resource(ResourceType::TICKET)->all(2, 20); // Page 2, 20 items
$article = $ticket->getTicketArticles()[0];
$content = $article->getAttachmentContent(1); // Attachment ID 1
$csvData = file_get_contents('modules.csv');
$client->resource(ResourceType::TEXT_MODULE)->import($csvData);
$client->resource(ResourceType::TAG)->add(1, 'urgent', 'Ticket');
$client->resource(ResourceType::TAG)->remove(1, 'urgent', 'Ticket');
if ($ticket->hasError()) {
log::error($ticket->getError());
}
$client = new Client(['url' => '...', 'debug' => true]);
http_token or oauth2_token for token-based auth:
$client = new Client(['url' => '...', 'http_token' => 'your-token']);
$client->setOnBehalfOfUser('impersonated-user@example.com');
Field Validation:
The client does not validate fields before save(). Zammad will reject invalid data (e.g., non-existent priority_id). Always check the API docs for valid values.
Resource Reuse:
get(), search(), or all(), the Resource object is "consumed." Create a new one for subsequent operations:
// ❌ Wrong: Reusing a consumed object
$ticket->get(2); // Fetches ticket 2
$ticket->get(3); // Fails silently or errors
// ✅ Correct: New object
$ticket2 = $client->resource(ResourceType::TICKET)->get(3);
Pagination Limits: Zammad enforces server-side limits (e.g., 500 items/page). Ignoring this may return truncated results.
Attachment IDs: Attachment IDs are local to the article. Fetch the article first to get valid IDs:
$article = $ticket->getTicketArticles()[0];
$attachments = $article->getValue('attachments'); // List IDs here
CSV Import Quirks:
max_execution_time.$response = $client->getLastResponse();
echo $response->getStatusCode(); // HTTP status
echo $response->getBody(); // Raw response
'debug' => true in the client config to log HTTP requests/responses.Custom HTTP Client: Inject a PSR-18 client (e.g., Guzzle) for advanced use cases:
use ZammadAPIClient\Client;
use GuzzleHttp\Client as GuzzleClient;
$httpClient = new GuzzleClient(['timeout' => 30]);
$client = new Client(['url' => '...', 'http_client' => $httpClient]);
Event Hooks:
Extend the Client or Resource classes to intercept requests/responses (e.g., logging, retries):
$client->onRequest(function ($request) {
logger()->debug('API Request:', ['url' => $request->getUri()]);
});
Resource Extensions:
Add custom methods to Resource objects via traits or inheritance:
class ExtendedTicketResource extends \ZammadAPIClient\Resource {
public function getCustomerName() {
return $this->getValue('customer_user__name');
}
}
'verify' => false (insecure) or provide a CA bundle path:
$client = new Client(['url' => '...', 'verify' => '/path/to/cabundle.pem']);
0 for no timeout:
$client = new Client(['url' => '...', 'timeout' => 15]);
all() with pagination for large datasets instead of looping get().$tickets = Cache::remember('tickets', 300, function () {
return $client->resource(ResourceType::TICKET)->all();
});
How can I help you explore Laravel packages today?