Skip to content

Accounts

MC0RE edited this page Aug 18, 2026 · 3 revisions

Accounts

Read account-level settings in Teamleader Focus.

Overview

The Accounts resource exposes the Projects version status for the connected Teamleader account. This determines whether the account is on the current ("nextgen") project system or the legacy one β€” which in turn determines which project-related SDK resources will actually return useful data.

Access via Teamleader::accounts().

This is the answer to "which project system is this account on?" Both project endpoints answer, so you cannot tell by calling one and seeing whether rows come back. See Why this resource matters.

list() and info() throw InvalidArgumentException. The API exposes exactly one endpoint here, accounts.projects-v2-status.

Every convenience method calls the API. isUsingProjectsV2(), getProjectsVersion() and the rest all call projectsV2Status() internally. Cache the result if you need more than one.

Endpoint

accounts

Capabilities

Capability Supported
Pagination ❌ Not supported
Filtering ❌ Not supported
Sorting ❌ Not supported
Sideloading ❌ Not supported
Creation ❌ Not supported
Update ❌ Not supported
Deletion ❌ Not supported

Why this resource matters

Teamleader uses three different names across the two project systems, and they do not line up:

Current system Legacy system
SDK method projects() / nextgenProjects() legacyProjects()
API path projects-v2/projects.* projects.*
Webhooks nextgenProject.* project.*

Reading the webhook names, it is natural to assume projects() is the legacy resource. It isn't. And because both endpoints answer on any account, a list call that returns twenty real projects tells you nothing about which system is in use β€” that exact mistake is what this resource exists to prevent.

// Do not do this
$projects = Teamleader::projects()->list();
$isOnNextgen = ! empty($projects['data']);   // meaningless

// Do this
$isOnNextgen = Teamleader::accounts()->isUsingProjectsV2();

See Projects and Legacy Projects.


Methods

projectsV2Status()

The only API call in this resource. Posts to accounts.projects-v2-status.

use McoreServices\TeamleaderSDK\Facades\Teamleader;

$status = Teamleader::accounts()->projectsV2Status();

Response:

[
    'data' => [
        'status'                            => 'legacy',      // or 'projects-v2'
        'will_be_automatically_switched_on' => '2025-12-31',  // optional β€” only for legacy accounts scheduled to migrate
    ],
    'headers' => ['X-RateLimit-Remaining' => ['199'], /* ... */],
]

status is one of exactly two values: projects-v2 or legacy. will_be_automatically_switched_on is absent, not null, when no migration is scheduled β€” use ?? rather than checking for null.


Helper Methods

All helpers call projectsV2Status() internally, so each one is its own API request.

Method Returns
isUsingProjectsV2(): bool true if status is projects-v2
isUsingLegacyProjects(): bool true if status is legacy
getProjectsVersion(): string 'projects-v2' or 'legacy'
getAutoSwitchDate(): ?string YYYY-MM-DD or null
hasScheduledAutoSwitch(): bool true if an auto-switch date is set
getDaysUntilAutoSwitch(): ?int Days remaining (negative if the date has passed), or null
isAutoSwitchApproaching(int $days = 30): bool true if the switch is within $days days
getAccountStatus(): array Formatted summary of all status fields
getProjectVersions(): array ['projects-v2', 'legacy'] β€” local, no API call
getResponseStructure(): array Field-level documentation β€” local, no API call

There is no getDefaultId() on this resource. Earlier versions of this page listed one, described as an alias for getAutoSwitchDate(). No such method exists in the source β€” calling it raises Error: Call to undefined method. Use getAutoSwitchDate().


Resource availability by version

Resource Current (projects-v2) Legacy
Teamleader::projects() βœ… ❌
Teamleader::nextgenProjects() βœ… ❌
Teamleader::projectLines() βœ… ❌
Teamleader::projectTasks() βœ… ❌
Teamleader::groups() βœ… ❌
Teamleader::materials() βœ… ❌
Teamleader::external_parties() βœ… ❌
Teamleader::legacyProjects() ❌ βœ…
Teamleader::legacyMilestones() ❌ βœ…

"❌" here means the endpoint will not return meaningful data for that account β€” not that the SDK method throws. Calling the wrong one generally succeeds and returns an empty or unrelated result, which is why checking first matters.


Usage Examples

Route project API calls by version

if (Teamleader::accounts()->isUsingProjectsV2()) {
    $projects = Teamleader::projects()->list(['status' => 'open']);
} else {
    $projects = Teamleader::legacyProjects()->active();
}

Remember the two systems use different status vocabularies β€” open versus active β€” and different customer filter shapes. See the comparison table on Legacy Projects.

Cache the status and derive everything locally

Each helper is a request, so chaining four of them costs four calls. Fetch once:

$status   = Teamleader::accounts()->projectsV2Status();
$isV2     = $status['data']['status'] === 'projects-v2';
$switchOn = $status['data']['will_be_automatically_switched_on'] ?? null;

if (! $isV2 && $switchOn) {
    $days = (new DateTime)->diff(new DateTime($switchOn))->days;
    Log::warning("Account migrates to Projects v2 in {$days} days ({$switchOn})");
}

The version changes rarely β€” at most once per account, on migration β€” so it is a good candidate for a long cache:

$isV2 = Cache::remember('tl_projects_v2', 3600, fn () =>
    Teamleader::accounts()->isUsingProjectsV2()
);

Keep the TTL well short of the auto-switch date if one is scheduled, or your integration will keep calling the legacy endpoints after the account has moved.

Display a migration warning

if (Teamleader::accounts()->isAutoSwitchApproaching(30)) {
    $days = Teamleader::accounts()->getDaysUntilAutoSwitch();
    $date = Teamleader::accounts()->getAutoSwitchDate();
    // show banner: "Your account migrates to Projects v2 in $days days ($date)."
}

That is three API calls. For a banner rendered on every page load, use getAccountStatus() once, or cache.

Subscribe to the right webhooks

Since an account only fires one project event family, subscribing to both keeps an integration working straight through a migration:

Teamleader::webhooks()->register(
    config('app.url').'/webhooks/teamleader',
    Teamleader::webhooks()->getProjectEventTypes()  // project.* + nextgenProject.*
);

See Webhooks.


Error Handling

use InvalidArgumentException;

// list() not supported
try {
    Teamleader::accounts()->list();
} catch (InvalidArgumentException $e) {
    // 'The accounts resource does not support list operations. Use projectsV2Status() method instead.'
}

// info() not supported
try {
    Teamleader::accounts()->info('uuid');
} catch (InvalidArgumentException $e) {
    // 'The accounts resource does not support info operations. Use projectsV2Status() method instead.'
}

Related Resources

  • Projects β€” The current system; fires nextgenProject.* despite the method name
  • Legacy Projects β€” The older system, on the bare projects.* path
  • Legacy Milestones β€” Phases within a legacy project
  • Project Tasks β€” Tasks in the current system
  • Time Tracking β€” relates_to accepts both project and nextgenProject
  • Files β€” Subject types include both project and nextgenProject
  • Webhooks β€” Both project.* and nextgenProject.* event families
  • Migrate β€” Translate legacy numeric IDs to new UUIDs

Clone this wiki locally