graystackit / laravel-helpspace-api
Laravel package for the HelpSpace API, built on Saloon 4
Package info
github.com/GraystackIT/laravel-helpspace-api
pkg:composer/graystackit/laravel-helpspace-api
Requires
- php: ^8.2
- illuminate/http: ^10.0|^11.0|^12.0|^13.0
- illuminate/support: ^10.0|^11.0|^12.0|^13.0
- saloonphp/saloon: ^4.0
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0|^10.0|^11.0
- pestphp/pest: ^2.0|^3.0
- pestphp/pest-plugin-laravel: ^2.0|^3.0
This package is auto-updated.
Last update: 2026-05-05 18:47:25 UTC
README
A Laravel package for the HelpSpace API, built on Saloon 4.
Supports Tickets, Messages, Reports, and Webhooks.
Requirements
- PHP 8.3+
- Laravel 11, 12, or 13
Installation
composer require graystackit/laravel-helpspace-api
The service provider is auto-discovered by Laravel.
Publish the config file:
php artisan vendor:publish --tag=helpspace-config
Add your credentials to .env:
HELPSPACE_API_KEY=your-bearer-token HELPSPACE_CLIENT_ID=your-client-id HELPSPACE_BASE_URL=https://api.helpspace.com
Configuration
After publishing, the config file lives at config/helpspace.php:
return [ 'api_key' => env('HELPSPACE_API_KEY'), 'client_id' => env('HELPSPACE_CLIENT_ID'), 'base_url' => env('HELPSPACE_BASE_URL', 'https://api.helpspace.com'), 'defaults' => [ 'per_page' => 20, ], ];
Usage
Resolve HelpSpaceClient from the container or inject it via the constructor:
use GraystackIT\HelpSpace\HelpSpaceClient; class SupportController extends Controller { public function __construct(private HelpSpaceClient $helpspace) {} }
Tickets
API reference: https://documentation.helpspace.com/api-tickets
List tickets
$result = $this->helpspace->listTickets( perPage: 25, statuses: ['open', 'escalated'], contacts: ['customer@example.com'], tags: ['billing'], createdBetween: '2024-01-01/2024-01-31', ); foreach ($result['data'] as $ticket) { echo $ticket->id; // int echo $ticket->subject; // string echo $ticket->status; // string (open|closed|waiting|escalated|spam|unassigned) echo $ticket->contactEmail; // string|null echo $ticket->contactName; // string|null echo $ticket->assigneeName; // string|null echo $ticket->teamName; // string|null print_r($ticket->tags); // array echo $ticket->createdAt; // ISO 8601 string } // Pagination metadata $result['meta']; // ['current_page' => 1, 'total' => 120, ...] $result['links']; // ['next' => '...', 'prev' => null, ...]
listTickets() parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
$perPage |
int |
20 (max 50) |
Results per page |
$statuses |
string[] |
[] |
Filter by status values |
$contacts |
string[] |
[] |
Filter by contact email |
$assignees |
string[] |
[] |
Filter by assignee name or ID |
$tags |
string[] |
[] |
Filter by tag names |
$subjects |
string[] |
[] |
Filter by subject text |
$bodies |
string[] |
[] |
Filter by body text |
$subjectOrBody |
string[] |
[] |
Filter by subject or body |
$organizations |
string[] |
[] |
Filter by organization |
$teams |
string[] |
[] |
Filter by team |
$createdBetween |
string|null |
null |
Date range YYYY-MM-DD/YYYY-MM-DD |
$lastContactBetween |
string|null |
null |
Date range YYYY-MM-DD/YYYY-MM-DD |
TicketStatus enum values:
| Case | API value |
|---|---|
Unassigned |
unassigned |
Open |
open |
Escalated |
escalated |
Spam |
spam |
Waiting |
waiting |
Closed |
closed |
Get a ticket
$ticket = $this->helpspace->getTicket(101);
Create a ticket
$ticket = $this->helpspace->createTicket([ 'subject' => 'Cannot access my account', 'channel' => ['id' => 'channel-uuid'], 'from_contact' => ['email' => 'user@example.com', 'name' => 'John Doe'], 'message' => ['body' => '<p>I cannot log in since yesterday.</p>'], 'tags' => ['access', 'urgent'], // Optional: 'skip_autoreply' => false, 'skip_notifications' => false, ]);
Update a ticket
$ticket = $this->helpspace->updateTicket(101, [ 'status' => 'closed', 'assignee' => ['id' => 'agent-uuid'], ]);
Delete a ticket
Soft-deleted tickets are permanently removed after 30 days.
$this->helpspace->deleteTicket(101); // returns true
Messages
API reference: https://documentation.helpspace.com/api-message
List messages
Default types returned: external, widget, forward.
// Default message types $messages = $this->helpspace->listMessages(101); // Include internal notes as well $messages = $this->helpspace->listMessages(101, additionalTypes: ['internal']); // Only return internal notes $messages = $this->helpspace->listMessages(101, types: ['internal']); foreach ($messages as $message) { echo $message->id; // int echo $message->type; // external|internal|forward|widget|... echo $message->fromContactEmail; // string echo $message->fromContactName; // string echo $message->body; // HTML string echo $message->createdAt; // ISO 8601 string print_r($message->attachments); // array print_r($message->to); // array of recipient addresses }
MessageType enum values:
| Case | API value | Default returned |
|---|---|---|
External |
external |
Yes |
Widget |
widget |
Yes |
Forward |
forward |
Yes |
Internal |
internal |
No |
Error |
error |
No |
Bounce |
bounce |
No |
Event |
event |
No |
AiSummary |
ai-summary |
No |
Get a message
$message = $this->helpspace->getMessage(ticketId: 101, messageId: 77);
Create a message
$message = $this->helpspace->createMessage(101, [ 'from_contact' => ['email' => 'agent@example.com', 'name' => 'Support Agent'], 'subject' => 'Re: Cannot access my account', 'body' => '<p>We have reset your password. Please check your email.</p>', // Optional: 'type' => 'external', // default 'to' => ['user@example.com'], 'cc' => [], 'bcc' => [], 'skip_notifications' => false, 'send_mail_to_recipients' => true, // Attachments as base64 (max 5 MB combined) 'attachments' => [ ['file_name' => 'guide.pdf', 'mime_type' => 'application/pdf', 'data' => base64_encode($pdfBytes)], ], ]);
Reports
API reference: https://documentation.helpspace.com/api-reports
Channels report
$report = $this->helpspace->getChannelsReport('2024-01-01', '2024-01-31'); print_r($report->dailyCounts); // per-day opened/closed ticket counts print_r($report->metrics); // new, closed, open, waiting, escalated counts print_r($report->channels); // ticket volume by channel print_r($report->tags); // ticket volume by tag print_r($report->topCustomers); // customers with most tickets print_r($report->raw); // full raw API response
Performance report
$report = $this->helpspace->getPerformanceReport('2024-01-01', '2024-01-31'); print_r($report->dailyCounts); // per-day opened/closed counts print_r($report->metrics); // avg resolution time breakdown (days/hours/minutes) print_r($report->topAgents); // agents with most resolved tickets print_r($report->raw); // full raw API response
Both methods accept date strings in YYYY-MM-DD format. An InvalidArgumentException is thrown if either date is empty.
Webhooks
API reference: https://documentation.helpspace.com/article/340/webhook
Get webhook configuration
$config = $this->helpspace->getWebhook(); echo $config->enabled; // bool echo $config->url; // destination URL echo $config->secret; // validation hash (string|null) print_r($config->headers); // custom headers [['key' => '...', 'value' => '...']] print_r($config->trigger); // enabled event types per resource echo $config->failedCount; // consecutive failure count (auto-disables on too many)
Update webhook configuration
$config = $this->helpspace->updateWebhook([ 'enabled' => true, 'url' => 'https://myapp.example.com/webhooks/helpspace', 'secret' => 'my-validation-secret', 'headers' => [ ['key' => 'X-App-Key', 'value' => 'my-app-key'], ], 'trigger' => [ 'ticket' => ['created' => true, 'updated' => true, 'deleted' => false], 'customer' => ['created' => false], 'tag' => ['created' => false], ], ]);
Get webhook error logs
$logs = $this->helpspace->getWebhookLogs(); foreach ($logs as $log) { echo $log['status']; // HTTP status code returned by your endpoint echo $log['response']; // response body echo $log['created_at']; // when the failure occurred }
Exceptions
| Exception | When thrown |
|---|---|
HelpSpaceApiException |
API returned 4xx/5xx, network failure, or non-JSON response |
InvalidArgumentException |
Empty subject on createTicket(), empty body on createMessage(), or empty dates on report methods |
Testing
This package uses Saloon's MockClient so you can test without real HTTP calls:
use GraystackIT\HelpSpace\HelpSpaceClient; use GraystackIT\HelpSpace\Connectors\HelpSpaceConnector; use GraystackIT\HelpSpace\Requests\Tickets\ListTicketsRequest; use Saloon\Http\Faking\MockClient; use Saloon\Http\Faking\MockResponse; $mockClient = new MockClient([ ListTicketsRequest::class => MockResponse::make([ 'data' => [ [ 'id' => 1, 'subject' => 'Test ticket', 'status' => 'open', 'from_contact' => ['email' => 'user@example.com', 'name' => 'User'], 'created_at' => '2024-01-01T00:00:00Z', ], ], 'meta' => [], 'links' => [], ], 200), ]); $connector = app(HelpSpaceConnector::class); $connector->withMockClient($mockClient); $result = (new HelpSpaceClient($connector))->listTickets();
Run the package test suite:
composer install vendor/bin/pest
API Endpoints Reference
| Method | HTTP | HelpSpace API Endpoint |
|---|---|---|
listTickets() |
GET | /api/v1/tickets |
getTicket() |
GET | /api/v1/tickets/{id} |
createTicket() |
POST | /api/v1/tickets |
updateTicket() |
PATCH | /api/v1/tickets/{id} |
deleteTicket() |
DELETE | /api/v1/tickets/{id} |
listMessages() |
GET | /api/v1/tickets/{id}/messages |
getMessage() |
GET | /api/v1/tickets/{id}/messages/{messageId} |
createMessage() |
POST | /api/v1/tickets/{id}/messages |
getChannelsReport() |
POST | /api/v1/reports/channels |
getPerformanceReport() |
POST | /api/v1/reports/performance |
getWebhook() |
GET | /api/v1/webhook |
updateWebhook() |
POST | /api/v1/webhook |
getWebhookLogs() |
GET | /api/v1/webhook/logs |
License
MIT