PHPackages                             teamtools/php-sdk - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. teamtools/php-sdk

ActiveLibrary[API Development](/categories/api)

teamtools/php-sdk
=================

PHP SDK for teamtools API

1.4.0(9y ago)013.6k[1 PRs](https://github.com/shiftplanning/teamtools-php-sdk/pulls)MITPHPPHP &gt;=5.6

Since Nov 25Pushed 4y ago13 watchersCompare

[ Source](https://github.com/shiftplanning/teamtools-php-sdk)[ Packagist](https://packagist.org/packages/teamtools/php-sdk)[ RSS](/packages/teamtools-php-sdk/feed)WikiDiscussions master Synced today

READMEChangelog (10)Dependencies (1)Versions (48)Used By (0)

Teamtools PHP SDK
=================

[](#teamtools-php-sdk)

- List of all [SDK methods](functions.md)

#### Installation

[](#installation)

TeamTools PHP SDK is on Packagist:

TeamTools PHP SDK can be installed using composer () by issuing following command:

```
composer require teamtools/php-sdk
```

All dependencies will be imported into working directory and you can start using SDK by including appropriate file. *Example:* if you create your application directory in same level as `vendor` directory, and your directory structure looks like this:

```
teamtools-php-sdk
├── app
│   └── index.php
├── vendor
├── composer.json
└── composer.lock

```

than you can start using teamtools SDK by including `autoload.php` in your `app/index.php` file like this:

```
require '../vendor/autoload.php';
```

You should not modify contents of `vendor` directory since its contents will be overwritten by composer updates.

#### Registering client

[](#registering-client)

Before calling any method, client must be authenticated to work with API. This is achieved by supplying client credentials to static method `initialize`:

```
use teamtools\TeamToolsClient;

TeamToolsClient::initialize([
    'client_id'     => 'your_api_client_id',
    'client_secret' => 'your_api_client_secret',
    'salt'          => 'your_salt'
]);
```

If the authentication is successful, from now on we can make calls to SDK methods.

#### Retrieving access token

[](#retrieving-access-token)

If access token is needed for making additional requests to TeamTools API, it can be retrieved after registering client, like this:

```
$accessToken = TeamToolsClient::getInstance()->getAccessToken();
```

### Customer entity

[](#customer-entity)

#### Customer namespace

[](#customer-namespace)

To work with customers, include the following namespace:

```
use teamtools\Entities\Customer;
use teamtools\Exceptions\TTException;   // this will be needed for error-handling
```

#### Create customer

[](#create-customer)

```
$data = [
    'name'    => 'Awesome customer',
    'email'   => 'customer@awesome.com',
    'phone'   => '+1234567890',
    'city'    => 'Berlin',
    'country' => 'Germany'
];

$customer = new Customer($data);

try {
    var_dump($customer->save(true));
} catch (TTException $ex) {
    echo $ex->getMessage();
}
```

#### Update customer

[](#update-customer)

Updating entity flow is: instantiate object from database, set its attributes to desired value and save back to database. Entity can be retrieved by `id`, or `tag` and search in which case a collection of objects will be returned. Ways of retrieving entities are described in next section (Get customers).

```
$customer = Customer::getByID('580a0ffcbffebc8b0e8b456a');
$customer->name = 'New Customer Name';

try {
    var_dump($customer->save());
} catch (TTException $ex) {
    echo $ex->getMessage();
}
```

#### Get customer

[](#get-customer)

Single customer object can be retrived by its `id`.

```
try {
    $customer = Customer::getByID('580a0ffcbffebc8b0e8b456a');
    var_dump($customer);
} catch (TTException $ex) {
    echo $ex->getMessage();
}
```

It's also possible to retrieve entities by tag, in which case a collection of entities will be returned.

```
try {
    $customers = $customer = Customer::getByTag('new');
    var_dump($customers);
} catch (TTException $ex) {
    echo $ex->getMessage();
}
```

Finally, entities can be searched by keyword using static method `getAll` which is provided in all entities. Also returns collection of entities.

```
// all customers
$customers = Customer::getAll();

foreach ($customers as $customer) {
    var_dump($customer->name);
}

// search customers for 'awesome' in searchable attributes
$customers = Customer::getAll(['keyword' => 'awesome']);

foreach ($customers as $customer) {
    var_dump($customer->name);
}
```

#### Delete customer

[](#delete-customer)

Deleting customer is done by instantiating it from database and calling its `delete` method. Data is being soft-deleted.

```
try {
    $customer = Customer::getByID('580a0ffcbffebc8b0e8b456aff');
    var_dump($customer->delete());
} catch (TTException $ex) {
    echo $ex->getMessage();
}
```

#### Migrate endusers to another customer

[](#migrate-endusers-to-another-customer)

```
try {
    $customer = Customer::getByID('57e3a147bffebc75388b4571');
    $newCustomerId = '57ecf1f6bffebcc5098b4585';

    //migrate specific endusers
    $ids = ['57ecf1b0bffebcc3098b4582', '57ecf1b0bffebcc3098b4587'];

    var_dump($customer->migrateEndusers($newCustomerId, $ids));
} catch (TTException $ex) {
    echo $ex->getMessage();
}
```

```
try {
    $customer = Customer::getByID('57e3a147bffebc75388b4571');
    $newCustomerId = '57ecf1f6bffebcc5098b4585';

    //migrate all endusers

    var_dump($customer->migrateEndusers($newCustomerId));
} catch (TTException $ex) {
    echo $ex->getMessage();
}
```

#### Get customer's endusers

[](#get-customers-endusers)

```
try {
    $customer = Customer::getByID('582191a10957473545bdff43');
    $endUsers = $customer->getEndUsers();

    var_dump($endUsers);
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

#### Get customer's events

[](#get-customers-events)

```
try {
    $customer = Customer::getByID('57fbe76c0957475156bdff59');
    $events = $customer -> getEvents();

    var_dump($events);
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

#### Restore deleted customer

[](#restore-deleted-customer)

```
try {
    var_dump(Customer::restore('57fce361bffebc231c8b45cb'));
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

#### Restore deleted end user

[](#restore-deleted-end-user)

```
try {
    var_dump(EndUser::restore('5822eaccbffebcaa088b458e'));
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

### Attributes

[](#attributes)

Attributes are properties that can be defined and attached to entity. There is a set of predefined attributes for each entity and arbitrary number of additional user-defined attributes may be created.

#### Get customer attributes

[](#get-customer-attributes)

Retrieve a list of attributes for an entity. Contains default and custom attributes, as well as description of relationships with other entities.

```
Customer::getAttributes();
```

#### Create or update customer attribute

[](#create-or-update-customer-attribute)

Custom attributes can be defined by instantiating `Attribute` object with corresponding properties and calling `saveAttribute` method on corresponding entity, as shown below. New custom attribute `department` will be created and attached to `Customer`. This attribute will be included in validations when working with `Customer` entity. For example: after creating this attribute, it won't be possible to create `Customer` entity if `department` is not provided, since `department` is required custom attribute (`'required' => true`).

```
$data = [
    'name'         => 'department',
    'prettyName'   => 'Department',
    'type'         => 'text',
    'description'  => "Customer's department",
    'required'     => true,
    'editable'     => true,
    'searchable'   => true,
    'default'      => false,
    'defaultValue' => '',
    'unique'       => false
];

$attribute = new Attribute($data);

try {
    Customer::saveAttribute($attribute);
} catch (TTException $ex) {
    echo $ex->getMessage();
}
```

##### Parameter descriptions

[](#parameter-descriptions)

Parameter nameTypeDescriptionname\*stringName of the attributeprettyName\*stringHuman readable attribute nametype\*stringAttribute typedescriptionstringDescription of attributerequiredbooleanIs attribute required?editablebooleanIs attribute editable?searchablebooleanIs attribute searchable?defaultValuestringDefault value of the attributevalidationstringValidation for attribute valueuniquebooleanIf set to true, attribute value is unique#### Delete customer attribute

[](#delete-customer-attribute)

Attribute can be deleted by supplying its `id` to static method `deleteAttribute` of corresponding entity. Attributes are soft-deleted, ie. record is marked as deleted and not physically removed from database.

```
try {
    Customer::deleteAttribute('56571718095747cc4b9215f4');
} catch (TTException $ex) {
    echo $ex->getMessage();
}
```

#### Get enduser attributes

[](#get-enduser-attributes)

Retrieve a list of attributes for an entity. Contains default and custom attributes, as well as description of relationships with other entities.

```
EndUser::getAttributes();
```

#### Create or update enduser attribute

[](#create-or-update-enduser-attribute)

Custom attributes can be defined by instantiating `Attribute` object with corresponding properties and calling `saveAttribute` method on corresponding entity, as shown below. New custom attribute `testAttribute` will be created and attached to `EndUser`. This attribute will be included in validations when working with `EndUser` entity. For example: after creating this attribute, it won't be possible to create `EndUser` entity if `testAttribute` is not provided, since `testAttribute` is required custom attribute (`'required' => true`).

```
$data = [
    'name'         => 'testAttribute',
    'prettyName'   => 'Test attribute',
    'type'         => 'text',
    'description'  => "EndUser's test attribute",
    'required'     => true,
    'editable'     => true,
    'searchable'   => true,
    'default'      => false,
    'defaultValue' => '',
    'unique'       => false
];

$attribute = new Attribute($data);

try {
    EndUser::saveAttribute($attribute);
} catch (TTException $ex) {
    echo $ex->getMessage();
}
```

#### Delete enduser attribute

[](#delete-enduser-attribute)

Attribute can be deleted by supplying its `id` to static method `deleteAttribute` of corresponding entity. Attributes are soft-deleted, ie. record is marked as deleted and not physically removed from database.

```
try {
    EndUser::deleteAttribute('56571718095747cc4b9215f4');
} catch (TTException $ex) {
    echo $ex->getMessage();
}
```

### TeamTools SDK response formats

[](#teamtools-sdk-response-formats)

Every interaction with TeamTools SDK will return response, even delete operation returns deleted resource. There are two types of responses: PHP object and raw JSON response as API returns it. Default format is PHP object (Entity or ArrayIterator when collections are returned) and raw response can be received by:

- supplying `true` to instance methods

    - Update customer and return raw response ```
        try {
            $customer       = Customer::getByID('56582c53095747b64b9215f7');
            $customer->name = 'SDK awesome customer';

            $response   = $customer->save(true);
        } catch (TTException $ex) {
            echo $ex->getMessage();
        }
        ```
    - Update customer and return `teamtools\Entities\Customer` object ```
        try {
            $customer       = Customer::getByID('56582c53095747b64b9215f7');
            $customer->name = 'SDK awesome customer';

            $response   = $customer->save();
        } catch (TTException $ex) {
            echo $ex->getMessage();
        }
        ```
- calling methods with suffix `Raw` when working with static methods

    - `$customer = Customer::getByID('565719f3095747906a9215f5');` - returns `teamtools\Entities\Customer` object
    - `$customer = Customer::getByIDRaw('565719f3095747906a9215f5');` - returns raw JSON response

##### Methods with corresponding "raw response" methods:

[](#methods-with-corresponding-raw-response-methods)

ObjectRaw`getByID``getByIDRaw``getByTag``getByTagRaw``getAll``getAllRaw``getAttributes``getAttributesRaw````
            |

```

### Embedding related objects in response

[](#embedding-related-objects-in-response)

Normally, related objects will be represented with ID in response. For example, customer will contain subscription ID in response which can be used to fetch subscription object. It is possible to embed related object directly into response and save additional server request.

Example embedding subscription object into customer response:

```
try {
    $customer = Customer::getByID('5739c7fbbffebc4c0b8b4567', 'subscription');
    var_dump($customer);
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

Related data can be nested, and more than one relation can be included. Parameter format should be string with comma separated relations to embed.

Examples for include parameter are:

- embed single relation:
    - include=events
- embed multiple relations:
    - include=events,customer
- nesting data:
    - include=events,customer.invoices

Some example of related object manipulations (not wrapped in try - catch blocks for the sake of clarity):

```
// retrieve all features from package that customer is currently subscribed to:
$customer = Customer::getByID('5739c7fbbffebc4c0b8b4567', 'subscription.package.features');
var_dump($customer->subscription->package->features);

// change property of related object
$customer = Customer::getByID('5739c7fbbffebc4c0b8b4567', 'subscription.package');
$package = $customer->subscription->package;
$package->name = 'Pro plan changed name';

var_dump($package->save());

// include more than one relation and response examples
$customer = Customer::getByID('5739c7fbbffebc4c0b8b4567', 'subscription.package,users');
var_dump($customer);
var_dump($customer->subscription);
var_dump($customer->subscription->package);
var_dump($customer->users);

// search and include
$customers = Customer::getAll([
    'filter'  => 'country{ct}jamaica',
    'include' => 'subscription.package'
]);

var_dump($customers);

```

Features
--------

[](#features)

#### Feature namespace

[](#feature-namespace)

To work with features, include the following namespace:

```
use teamtools\Entities\Feature;
use teamtools\Exceptions\TTException;   // this will be needed for error-handling
```

#### Get feature attributes

[](#get-feature-attributes)

```
$attributes = Feature::getAttributes();
```

#### Create feature attribute

[](#create-feature-attribute)

```
use teamtools\Entities\Feature;
use teamtools\Entities\Attribute;

$data = [
    'name'         => 'status',
    'prettyName'   => 'Feature status',
    'type'         => 'number',
    'description'  => 'Status of feature',
    'required'     => true,
    'editable'     => true,
    'searchable'   => true,
    'default'      => false,
    'defaultValue' => ''
];

try {
    $attribute = new Attribute($data);
    Feature::saveAttribute($attribute);
} catch (TTException $ex) {
    echo $ex->getMessage();
}
```

#### Update feature attributes

[](#update-feature-attributes)

```
use teamtools\Entities\Feature;
use teamtools\Entities\Attribute;

$data = [
    'id'           => '5656c899bffebc47078b456e',
    'name'         => 'status',
    'prettyName'   => 'Feature status',
    'type'         => 'number',
    'description'  => 'Status of feature. 1 - active; 0 - inactive.',
    'required'     => true,
    'editable'     => true,
    'searchable'   => true,
    'default'      => false,
    'defaultValue' => ''
];

try {
    $attribute = new Attribute($data);
    Feature::saveAttribute($attribute);
} catch (TTException $ex) {
    echo $ex->getMessage();
}
```

#### Delete feature attribute

[](#delete-feature-attribute)

```
try {
    Feature::deleteAttribute('5656c899bffebc47078b456e');
} catch (TTException $ex) {
    echo $ex->getMessage();
}
```

#### Get feature by ID

[](#get-feature-by-id)

```
try {
    $feature = Feature::getByID('5655c5f6bffebc40078b459e');
} catch (TTException $ex) {
    echo $ex->getMessage();
}
```

#### Get feature by tag

[](#get-feature-by-tag)

```
try {
    $feature = Feature::getByTag('master');
} catch (TTException $ex) {
    echo $ex->getMessage();
}
```

#### Create feature

[](#create-feature)

```
$data = [
    'name'        => 'Feature B',
    'description' => 'Feature B',
    'uniqueKey'   => 'feat-B'
];

try {
    $feature = new Feature($data);
    $feature->save();
} catch (TTException $ex) {
    echo $ex->getMessage();
}
```

#### Update feature

[](#update-feature)

```
$feature              = Feature::getByID('5655c5f6bffebc40078b459e');
$feature->description = 'Feature B - extended trial period.';

try {
    $feature->save();
} catch (TTException $ex) {
    echo $ex->getMessage();
}
```

#### Delete feature

[](#delete-feature)

```
try {
    $feature = Feature::getByID('5655d765bffebc3f078b4595');
    $feature->delete();
} catch (TTException $ex) {
    echo $ex->getMessage();
}
```

#### Relation examples

[](#relation-examples)

##### Update feature dependencies

[](#update-feature-dependencies)

```
try {
    $feature                 = Feature::getByID('5655c5edbffebc40078b459c');
    $feature->dependency_ids = ['5655c5f6bffebc40078b459e'];
    $feature->save();
} catch (TTException $ex) {
    echo $ex->getMessage();
}
```

##### Remove feature dependencies

[](#remove-feature-dependencies)

```
try {
    $feature                 = Feature::getByID('5655c5edbffebc40078b459c');
    $feature->dependency_ids = [];
    $feature->save();
} catch (TTException $ex) {
    echo $ex->getMessage();
}
```

### Groups, Packages and Plans

[](#groups-packages-and-plans)

#### Groups, Packages and Plans namespaces:

[](#groups-packages-and-plans-namespaces)

To work with groups, packages or plans, include respective namespace:

```
use teamtools\Entities\Group;
use teamtools\Entities\Package;
use teamtools\Entities\Plan;
```

#### Step 1: Create Group

[](#step-1-create-group)

Groups have following parameters:

- name - a user-friendly label for the Group that’ll be seen by you in your dashboard, and possibly by your customers.
- default - should be set as true or false, depending if you want to set Group as default
- defaultPackageId - each Group should contain at least one Package. If Group is having more than one Package, you should determine, which Package is getting defaultPackageId.

Code example:

```
$data = [
    'name'    => 'Standard group',
    'default' => true   //if ommited and this is first group in the system, group will become default
];

$group = new Group($data);

try {
    var_dump($group->save());
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

Example with default package and assign as default group:

```
$data = [
    'name'           => 'Basic group',
    'defaultPackage' => '5733052dbffebc46088b456b',
    'default'        => true
];

$group = new Group($data);

try {
    var_dump($group->save());
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

Retrieve packages by group ID:

```
try {
    $group = Group::getByID('573301dbbffebc46088b4567');
    var_dump($group->getPackages());
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

#### Step 2: Create Packages

[](#step-2-create-packages)

Packages have following parameters:

- name - a user-friendly label for the package that’ll be seen by you in your dashboard, and possibly by your customers.
- description - additional description of Package for providing more information.
- default - Indicates if Package is default for the group.
- groupId - represents Package group.
- featureIds - represents Feature(s) you want to assign to Package.

Code example:

```
$data = [
    'name'    => 'Basic package',
    'groupId' => '573301dbbffebc46088b4567',
    'default' => 'true'     // assign this package as default in its group
];

$package = new Package($data);

try {
    var_dump($package->save());
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

Example creating package with features:

```
$data = [
    'name'       => 'Pro package',
    'featureIds' => [
        '573305cdbffebc46088b4571',
        '573305e5bffebc46088b4575'
    ],
    'groupId'    => '573301dbbffebc46088b4567'
];

$package = new Package($data);

try {
    var_dump($package->save());
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

Upon creation of Package, you will get packageId from teamtools. Each Package requires a unique ID. You’ll provide this value in API requests to subscribe a customer to one of your Packages.

> **Default Package**

> In case there is only one Package created in the Group, this Package will get defaultPackageId. If there are two or more Packages created in the Group, you'll need to decide which Package gets to be default.

#### Retrieve all packages

[](#retrieve-all-packages)

```
try {
    $packages = Package::getAll();

    var_dump($packages);
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

#### Step 3: Create Plan

[](#step-3-create-plan)

Plan includes following parameters:

- name - a user-friendly label for the Plan which will be inherited from Package name
- description - additional description of Plan for providing more information, which will be inherited from Package name
- trial - number of days available for trial, used in case Trial is offered by your service.
- initialFee - amount, used in case you want to charge specific fee for service setup.
- pricing - described below

Example creating unit plan:

```
$data = [
    'packageId' => '57330639bffebc46088b4579',
    'trial'     => '30',
    'currency'  => 'USD',
    'pricing'   => [
        'type' => 'unit',
        'interval' => [
            'type' => 'month',
            'amount' => 2
        ],
        'unit'   => 'enduser',
        'amount' =>  200    //amount in cents
    ]
];

$plan = new Plan($data);

try {
    var_dump($plan->save());
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

Example creating flat plan:

```
$data = [
    'name'      => 'Enterprise',
    'packageId' => '57330639bffebc46088b4579',
    'trial' => '30',
    'currency'  => 'USD',
    'pricing'   => [
        'type' => 'flat',
        'interval' => [
            'type'   => 'month',
            'amount' => 2
        ],
        'amount' =>  1500
    ]
];

```

Example creating tier plan:

```
$data = [
    'packageId' => '57330639bffebc46088b4579',
    'trial'     => '30',
    'currency'  => 'USD',
    'pricing'   => [
        'type' => 'tier',
        'interval' => [
            'type' => 'month',
            'amount' => 2
        ],
        'unit' => 'enduser',
        'levels' => [
            [
                'condition' => [
                    'min' => 1,
                    'max' => -1
                ],
                'expression' => [
                    [
                        'type'   => 'unit',
                        'unit'   => 'enduser',
                        'amount' => 120     //amount in cents
                    ]
                ]
            ]
        ]
    ]
];

$plan = new Plan($data);

try {
    var_dump($plan->save());
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

Get plan by ID:

```
try {
    $plan = Plan::getByID('5673eff3bffebc4e078b4569');
} catch (TTException $ex) {
    echo $ex->getMessage();
}
```

#### Start subscribing Customer to a Package

[](#start-subscribing-customer-to-a-package)

There are two ways to create customer subscription: via customer create / update request and through dedicated endpoint.

Create subscription using customer update request (returns `customer` in response):

```
try {
    $customer = Customer::getByID('5730838fbffebc290b8b4591');
    $customer->groupId = 'default';

    var_dump($customer->save());
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

Create subscription using dedicated endpoint (default group). Returns `subscription` in response:

```
try {
    $customer = Customer::getByID('5730838fbffebc290b8b4591');

    $subscriptionData = [
        'groupId' => 'default'
    ];

    var_dump($customer->subscribe($subscriptionData));
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

Create subscription using dedicated endpoint:

```
try {
    $customer = Customer::getByID('5730838fbffebc290b8b4591');

    $subscriptionData = [
        'groupId'     => '573301dbbffebc46088b4567',
        'packageId'   => '5733052dbffebc46088b456b',
        'manual'      => 'false',
        'stripeToken' => 'xxxx',
        'force'       => false
    ];

    var_dump($customer->subscribe($subscriptionData));
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

Retrieve customer's subscription

```
try {
    $customer = Customer::getByID('5730838fbffebc290b8b4591');
    var_dump($customer->getSubscription());
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

#### Unsubscribe customer from package

[](#unsubscribe-customer-from-package)

By calling following SDK function customer will be unsubscribed from current package. If subscription exists on payment gateway, it will also be cancelled. Return value: `subscription` object.

```
try {
    $customer = Customer::getByID('56c73ce5bffebc47078b4619');
    var_dump($customer->unsubscribe());
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

#### Add invoice item

[](#add-invoice-item)

Invoice item can be added and picked up by next invoice generation. If subscription exist on payment gateway, invoice item will be created on gateway. Otherwise it's created in TeamTools database.

```
use teamtools\Entities\Subscription;

$data = [
    'description' => 'This item will appear on next invoice',
    'currency'    => 'usd',
    'amount'      => 1800
];

try {
    $subscription = Subscription::getByID('56cc46f2bffebc5b078b4571');
    $subscription->addInvoiceItem($data);
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

Invoices
--------

[](#invoices)

#### Get invoice by ID

[](#get-invoice-by-id)

```
use teamtools\Entities\Invoice;

try {
    $invoice = Invoice::getByID('56cc581abffebc5b078b4575');

    var_dump($invoice);
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

#### Create invoice

[](#create-invoice)

```
use teamtools\Entities\Invoice;

$data = [
    'invoiceDate' => '2016-01-22',
    'dueDate'     => '2016-02-22',
    'customerId'  => '56c73ce5bffebc47078b4619',
    'items'       => [
        [
            'description' => 'Initial account setup',
            'amount'      => 1750
        ],
        [
            'description' => 'Application adjustments',
            'amount'      => 450000
        ]
    ]
];

$invoice = new Invoice($data);

try {
    var_dump($invoice->save());
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

#### Settle invoice

[](#settle-invoice)

Used to manually mark invoice as settled.

```
use teamtools\Entities\Invoice;

try{
    $invoice = Invoice::getByID('56cc581abffebc5b078b4575');
    $invoice->settle();
    var_dump($invoice->save());
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

#### Apply payment on invoice

[](#apply-payment-on-invoice)

Manually apply payment to invoice total. If applied amount is equal to invoice total, invoice will be marked as paid. If amount is larger than open invoice amount, invoice will be closed and remaining amount added to balance on subscription object.

```
use teamtools\Entities\Invoice;

try {
    $invoice = Invoice::getByID('56cc581abffebc5b078b4575');
    $invoice->applyPayment(['amount' => 350]);
    var_dump($invoice->save());
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

#### Get payments / refunds

[](#get-payments--refunds)

Retrieve refunds or payments for invoice:

```
try {
    $invoice = Invoice::getByID('57e3a348bffebc83318b457e');

    var_dump($invoice->getRefunds());
    var_dump($invoice->getPayments());
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

#### Bulk insert and update

[](#bulk-insert-and-update)

Customers and Endusers support bulk operations like inserting and updating multiple records in single request. For this operation a structure named "data" should be provided, which contains array of entities to be persisted. If array element contains element "id", entity with that specific ID will be updated. Otherwise, entity will be inserted. All validations are still valid, like when working with single entity.

Customers example:

```
use teamtools\Entities\Customer;

$customers = [
    [
        'id'      => '5704f67cbffebc47078b4574',
        'name'    => 'My Customer XXY',
        'email'   => 'customerCHANGE@email.com',
        'phone'   => '+1234123412',
        'country' => 'USA',
        'city'    => 'Chicago',
    ],
    [
        'name'    => 'My Customer YXY',
        'email'   => 'customer@email.com',
        'phone'   => '+1234123412',
        'country' => 'USA',
        'city'    => 'Chicago'
    ]
];

try {
    var_dump(Customer::saveAll($customers, false));
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

Endusers example:

```
use teamtools\Entities\EndUser;

$endusers = [
    [
        'firstName'  => 'Mary',
        'lastName'   => 'Jones',
        'email'      => 'customerCHANGE@email.com',
        'phone'      => '+1234123412',
        'country'    => 'USA',
        'city'       => 'Chicago',
        'customerId' => '5704f67cbffebc47078b4574'
    ],
    [
        'firstName' => 'Peter',
        'lastName'  => 'Johnson',
        'email'     => 'customer@email.com',
        'phone'     => '+1234123412',
        'country'   => 'USA',
        'city'      => 'Chicago',
        'customerId' => '5704f67cbffebc47078b4574'
    ],
    [
        'id'        => '57050433bffebc46078b457f',
        'firstName' => 'John',
        'lastName'  => 'Smith',
        'email'     => 'customer@email.com',
        'phone'     => '+1234123412',
        'country'   => 'USA',
        'city'      => 'Chicago',
        'customerId' => '5704f67cbffebc47078b4574'
    ]
];

try {
    var_dump(EndUser::saveAll($endusers, false));
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

### Retrieve webhook event

[](#retrieve-webhook-event)

```
try {
    $webEvent = WebEvent::getByID('57334232bffebc77088b4574');
    var_dump($webEvent);
} catch (TTException $ex) {
    echo $ex->getMessage();
}

```

### Webhook event format examples

[](#webhook-event-format-examples)

Customer name updated:

```
{
  "data": {
    "id": "5729eb7bbffebc48088b456e",
    "timestamp": "2016-05-04 12:30:51",
    "source": "UI",
    "memberId": "5729c6ebbffebc47088b458a",
    "url": null,
    "action": "updated",
    "data": {
      "type": "customer",
      "value": {
        "id": "5729e7c8bffebc47088b458b",
        "name": "ShiftPlanning 2",
        "email": "sp@shiftplanning.com",
        "country": "USA",
        "phone": "123",
        "city": "Belgrade",
        "joinDate": {
          "date": "2016-05-01 00:00:00.000000",
          "timezone_type": 3,
          "timezone": "UTC"
        },
        "updated_at": {
          "date": "2016-05-04 12:30:51.000000",
          "timezone_type": 3,
          "timezone": "UTC"
        },
        "created_at": {
          "date": "2016-05-04 12:15:04.000000",
          "timezone_type": 3,
          "timezone": "UTC"
        },
        "tags": [],
        "notes": []
      },
      "old": {
        "id": "5729e7c8bffebc47088b458b",
        "name": "ShiftPlanning",
        "email": "sp@shiftplanning.com",
        "country": "USA",
        "phone": "123",
        "city": "Belgrade",
        "joinDate": {
          "date": "2016-05-01 00:00:00.000000",
          "timezone_type": 3,
          "timezone": "UTC"
        },
        "updated_at": {
          "date": "2016-05-04 12:15:04.000000",
          "timezone_type": 3,
          "timezone": "UTC"
        },
        "created_at": {
          "date": "2016-05-04 12:15:04.000000",
          "timezone_type": 3,
          "timezone": "UTC"
        },
        "tags": [],
        "notes": []
      }
    },
    "status": "failed",
    "updated_at": {
      "date": "2016-05-04 12:30:51.000000",
      "timezone_type": 3,
      "timezone": "UTC"
    },
    "created_at": {
      "date": "2016-05-04 12:30:51.000000",
      "timezone_type": 3,
      "timezone": "UTC"
    }
  }
}

```

Group created:

```
{
  "data": {
    "id": "57332e6dbffebc78088b4573",
    "timestamp": "2016-05-11 13:06:53",
    "source": "API",
    "memberId": null,
    "url": null,
    "action": "created",
    "data": {
      "type": "group",
      "value": {
        "id": "57332e6dbffebc78088b4571",
        "default": true,
        "updated_at": {
          "date": "2016-05-11 13:06:53.000000",
          "timezone_type": 3,
          "timezone": "UTC"
        },
        "created_at": {
          "date": "2016-05-11 13:06:53.000000",
          "timezone_type": 3,
          "timezone": "UTC"
        },
        "tags": [],
        "defaultPackageId": null
      },
      "old": null
    },
    "status": "failed",
    "updated_at": {
      "date": "2016-05-11 13:06:53.000000",
      "timezone_type": 3,
      "timezone": "UTC"
    },
    "created_at": {
      "date": "2016-05-11 13:06:53.000000",
      "timezone_type": 3,
      "timezone": "UTC"
    }
  }
}

```

Package deleted:

```
{
  "data": {
    "id": "57334232bffebc77088b4574",
    "timestamp": "2016-05-11 14:31:14",
    "source": "API",
    "memberId": null,
    "url": null,
    "action": "deleted",
    "data": {
      "type": "package",
      "value": {
        "id": "5733052dbffebc46088b456b",
        "name": "Basic package",
        "default": false,
        "updated_at": {
          "date": "2016-05-11 10:10:53.000000",
          "timezone_type": 3,
          "timezone": "UTC"
        },
        "created_at": {
          "date": "2016-05-11 10:10:53.000000",
          "timezone_type": 3,
          "timezone": "UTC"
        },
        "groupId": "573301dbbffebc46088b4567",
        "deleted_at": "2016-05-11 14:31:14",
        "tags": [],
        "featureIds": []
      },
      "old": null
    },
    "status": "failed",
    "updated_at": {
      "date": "2016-05-11 14:31:14.000000",
      "timezone_type": 3,
      "timezone": "UTC"
    },
    "created_at": {
      "date": "2016-05-11 14:31:14.000000",
      "timezone_type": 3,
      "timezone": "UTC"
    }
  }
}

```

###  Health Score

34

—

LowBetter than 75% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity19

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity71

Established project with proven stability

 Bus Factor1

Top contributor holds 94.3% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~13 days

Recently: every ~19 days

Total

34

Last Release

3443d ago

PHP version history (3 changes)1.0.0PHP &gt;=5.5.0

1.1.17PHP &gt;=5.4.0

1.4.0PHP &gt;=5.6

### Community

Maintainers

![](https://www.gravatar.com/avatar/6741e6c1758ca2302d64fa825fe91d0836d5a9811bcddafe9044888893106af9?d=identicon)[sophokli](/maintainers/sophokli)

---

Top Contributors

[![miroslavjovanovic](https://avatars.githubusercontent.com/u/9320086?v=4)](https://github.com/miroslavjovanovic "miroslavjovanovic (82 commits)")[![minjamarcetic-tomtom](https://avatars.githubusercontent.com/u/158580313?v=4)](https://github.com/minjamarcetic-tomtom "minjamarcetic-tomtom (4 commits)")[![shipla](https://avatars.githubusercontent.com/u/8070402?v=4)](https://github.com/shipla "shipla (1 commits)")

---

Tags

sdkteamtools

### Embed Badge

![Health badge](/badges/teamtools-php-sdk/health.svg)

```
[![Health](https://phpackages.com/badges/teamtools-php-sdk/health.svg)](https://phpackages.com/packages/teamtools-php-sdk)
```

###  Alternatives

[aws/aws-sdk-php

AWS SDK for PHP - Use Amazon Web Services in your PHP project

6.3k543.5M2.6k](/packages/aws-aws-sdk-php)[facebook/php-business-sdk

PHP SDK for Facebook Business

91624.2M37](/packages/facebook-php-business-sdk)[tencentcloud/tencentcloud-sdk-php

TencentCloudApi php sdk

3741.3M46](/packages/tencentcloud-tencentcloud-sdk-php)[facebook/php-ads-sdk

PHP SDK for Facebook Business

9214.2M8](/packages/facebook-php-ads-sdk)[resend/resend-php

Resend PHP library.

617.2M43](/packages/resend-resend-php)[checkout/checkout-sdk-php

Checkout.com SDK for PHP

563.6M13](/packages/checkout-checkout-sdk-php)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
