-
-
Notifications
You must be signed in to change notification settings - Fork 0
Quotations
Manage quotations in Teamleader Focus.
The Quotations resource provides full CRUD operations for quotations attached to deals, plus accept(), send(), and download() lifecycle methods.
Pagination differs from other resources. Quotations uses
options['page']['size']andoptions['page']['number']β not the standardpage_size/page_numberkeys used elsewhere in the SDK.
quotations
| Capability | Supported |
|---|---|
| Pagination | β Supported (non-standard format β see below) |
| Filtering | β
Supported (ids, status) |
| Sorting | β Not supported |
| Sideloading | β
Supported (expiry β feature-gated) |
| Creation | β Supported |
| Update | β Supported |
| Deletion | β Supported |
Pagination is passed as a nested page object under $options, not as flat page_size/page_number keys.
use McoreServices\TeamleaderSDK\Facades\Teamleader;
// All quotations
$quotations = Teamleader::quotations()->list();
// Filtered by status
$quotations = Teamleader::quotations()->list(['status' => ['open', 'accepted']]);
// With pagination β note the nested 'page' key
$quotations = Teamleader::quotations()->list([], [
'page' => ['size' => 50, 'number' => 1],
]);$quotation = Teamleader::quotations()->info('quotation-uuid');
// With expiry sideload (only if feature is enabled on the account)
$quotation = Teamleader::quotations()->info('quotation-uuid', 'expiry');
$quotation = Teamleader::quotations()->with('expiry')->info('quotation-uuid');Required (validated before the request):
-
deal_idβ UUID of the deal this quotation belongs to -
grouped_linesORtextβ at least one must be present
$quotation = Teamleader::quotations()->create([
'deal_id' => 'deal-uuid',
'grouped_lines' => [
[
'section' => ['title' => 'Professional Services'],
'line_items' => [
[
'quantity' => 5,
'description' => 'Consulting days',
'unit_price' => [
'amount' => 1200,
'currency' => 'EUR',
'tax' => 'excluding',
],
],
],
],
],
]);
// Text-only quotation (Markdown)
$quotation = Teamleader::quotations()->create([
'deal_id' => 'deal-uuid',
'text' => '## Proposal\n\nPlease find our offer below.',
]);The id is injected into the request body before posting. Returns empty (HTTP 204).
Teamleader::quotations()->update('quotation-uuid', [
'grouped_lines' => [...],
]);Returns empty (HTTP 204).
Teamleader::quotations()->delete('quotation-uuid');Marks a quotation as accepted. Returns empty (HTTP 204).
Teamleader::quotations()->accept('quotation-uuid');Sends one or more quotations by email. All six keys are required and validated before the request β an InvalidArgumentException is thrown for any missing field.
| Required key | Description |
|---|---|
quotations |
Non-empty array of quotation UUIDs |
from.sender |
Sender object (type + id) |
recipients.to |
Non-empty array of recipient objects |
subject |
Email subject line |
content |
Email body text |
language |
Language code (e.g. en, nl) |
Returns empty (HTTP 204).
Teamleader::quotations()->send([
'quotations' => ['quotation-uuid'],
'from' => [
'sender' => ['type' => 'user', 'id' => 'user-uuid'],
],
'recipients' => [
'to' => [
['type' => 'contact', 'id' => 'contact-uuid'],
],
],
'subject' => 'Your quotation from Acme Corp',
'content' => 'Please review the attached quotation.',
'language' => 'nl',
]);Downloads a quotation as a temporary URL. Only pdf is a valid format β InvalidArgumentException is thrown for any other value.
$result = Teamleader::quotations()->download('quotation-uuid', 'pdf');
$url = $result['data']['location']; // temporary download URL
$expires = $result['data']['expires']; // expiration time
file_put_contents('quotation.pdf', file_get_contents($url));$quotations = Teamleader::quotations()->byIds(['uuid-1', 'uuid-2']);Validates each status against the allowed list before calling list(). Throws InvalidArgumentException for any invalid value.
$quotations = Teamleader::quotations()->byStatus('open');
$quotations = Teamleader::quotations()->byStatus(['open', 'accepted']);Valid statuses: open, accepted, expired, rejected, closed
| Filter | Type | Description |
|---|---|---|
ids |
array | Filter by quotation UUIDs |
status |
array | Filter by status β string is coerced to array |
| Include | Description |
|---|---|
expiry |
Expiry date and action after expiry. Only returned if the account has the quotation expiry feature enabled. |
$quotation = Teamleader::quotations()->with('expiry')->info('quotation-uuid');
$expiresAfter = $quotation['data']['expiry']['expires_after']; // YYYY-MM-DD
$actionAfterExpiry = $quotation['data']['expiry']['action_after_expiry']; // 'lock' or 'none'| Method | Returns |
|---|---|
list() |
Array of quotation summaries |
info() |
Full quotation with grouped_lines
|
create() |
['data' => ['type' => 'quotation', 'id' => 'uuid']] |
update() |
Empty array (HTTP 204) |
delete() |
Empty array (HTTP 204) |
accept() |
Empty array (HTTP 204) |
send() |
Empty array (HTTP 204) |
download() |
['data' => ['location' => '...', 'expires' => '...']] |
$deal = Teamleader::deals()->withCustomer()->info('deal-uuid');
$customer = $deal['data']['lead']['customer'];
$quotation = Teamleader::quotations()->create([
'deal_id' => 'deal-uuid',
'grouped_lines' => [[
'section' => ['title' => 'Proposed Solution'],
'line_items' => [[
'quantity' => 1,
'description' => 'Implementation package',
'unit_price' => ['amount' => 5000, 'currency' => 'EUR', 'tax' => 'excluding'],
]],
]],
]);
Teamleader::quotations()->send([
'quotations' => [$quotation['data']['id']],
'from' => ['sender' => ['type' => 'user', 'id' => 'responsible-user-uuid']],
'recipients' => ['to' => [['type' => $customer['type'], 'id' => $customer['id']]]],
'subject' => 'Your quotation',
'content' => 'Please find the attached quotation.',
'language' => 'nl',
]);$download = Teamleader::quotations()->download('quotation-uuid', 'pdf');
$filename = 'quotation_' . date('Ymd') . '.pdf';
Storage::put("quotations/{$filename}", file_get_contents($download['data']['location']));use InvalidArgumentException;
use McoreServices\TeamleaderSDK\Exceptions\TeamleaderException;
// Missing deal_id
try {
Teamleader::quotations()->create(['grouped_lines' => [...]]);
} catch (InvalidArgumentException $e) {
// 'deal_id is required to create a quotation'
}
// Neither grouped_lines nor text
try {
Teamleader::quotations()->create(['deal_id' => 'uuid']);
} catch (InvalidArgumentException $e) {
// 'A quotation needs either grouped_lines or text to be valid'
}
// Invalid download format
try {
Teamleader::quotations()->download('uuid', 'docx');
} catch (InvalidArgumentException $e) {
// "Invalid format 'docx'. Supported formats: pdf"
}
// Invalid status in byStatus()
try {
Teamleader::quotations()->byStatus('draft');
} catch (InvalidArgumentException $e) {
// "Invalid status 'draft'. Must be one of: open, accepted, expired, rejected, closed"
}Last Updated: August 2026 β’ SDK Version: 2.2.2 β’ Made with β€οΈ by MCore Services
- Departments
- Users
- Teams
- Custom Fields
- Work Types
- Document Templates
- Currencies
- Notes
- Email Tracking
- Closing Days
- Day Off Types
- Days Off
- User Schedules
- Invoices
- Credit Notes
- Subscriptions
- Payment Methods
- Payment Terms
- Tax Rates
- Withholding Tax Rates
- Commercial Discounts
Next Gen Projects
Legacy Projects