Sendwithus PHP Client

Overview

sendwithus_php

Sendwithus PHP Client

Status

Build Status

Requirements

curl library must be installed and enabled in php.ini

Install it via Composer

Add it to your composer.json

{
    "repositories": [
        {
            "type": "vcs",
            "url": "https://github.com/sendwithus/sendwithus_php"
        }
    ],
    "require": {
        "sendwithus/api": "dev-master"
    }
}

Then install it with

composer install

Getting started

// Yii Users
Yii::$classMap = array(
    'sendwithus\\API' => dirname($_SERVER['DOCUMENT_ROOT']) . '/path/to/sendwithus/lib/API.php'
);

// composer users
use sendwithus\API;

require_once 'vendor/autoload.php';


$API_KEY = 'THIS_IS_A_TEST_API_KEY';
$options = array(
    'DEBUG' => true,
    'API_DEBUG_HANDLER' => function ($message, $priority_level) {
        // possible priority levels - http://php.net/manual/en/function.syslog.php
        error_log("[SendWithUs][$priority_level] " . $message);
    }
);

$api = new API($API_KEY, $options);

Emails

Get emails

$response = $api->emails();

Get specific template

$response = $api->get_template($template_id,     //string id of template
                               $version_id       //optional string version id of template
);

Create emails

Create new email

We validate all HTML content

$response = $api->create_email('Email Name',               // string email name
    'Email Subject',                                       // string subject line of email
    '<html><head></head><body>Valid HTML<body></html>',    // string of HTML code for email
    'Optional text content')                               // optional string of text for email

Create new email template version

We validate all HTML content

$response = $api->create_new_template_version(
    'Email Name',                                          // string email version name
    'Email Subject',                                       // string subject of email
	'tem_JAksjdjwJXUVwnemljflksEJks',                      // string id of email used
    '<html><head></head><body>Valid HTML<body></html>',    // string block of HTML code used for email
    'Optional text content')                               // optional string of text used for email

Update email version

We validate all HTML content

$response = $api->update_template_version(
    'Email Name',                                          // string email version name
    'Email Subject',                                       // string subject of email
	'tem_JAkCjdjwJXUVwnemljflksEJks',                      // string id of email being updated
	'ver_iuweJskj4Jwkj2ndclk4jJDken',                      // string version of email being updated
    '<html><head></head><body>Valid HTML<body></html>',    // string block of HTML code used for email
    'Optional text content')                               // optional string of text used for email

Send emails

NOTE - If a customer does not exist by the specified email (recipient address), the send call will create a customer.

// Send function header
send(
    $email_id,      // string, id of email to send (template id)
    $recipient,     // associative array, ("address" => "[email protected]", "name" => "Clark") to send to
    $args           // (optional) array, (array) additional parameters - (see below)
)

// Send function options
'template_data'  // array of variables to merge into the template.
'sender'         // array ("address", "name", "reply_to") of sender.
'cc'             // array of ("address", "name") for carbon copy.
'bcc'            // array of ("address", "name") for blind carbon copy.
'inline'         // string, path to file to include inline
                 // or an associative array with "id" containing filename
                 // and "data" containing base64 encoded file content
'files'          // array, each element represents either a string path to file to attach
                 // or an associative array with "id" containing filename
                 // and "data" containing base64 encoded file content
'tags'           // array of strings to tag email send with.
'esp_account'    // string of ESP ID to manually select ESP
'headers'        // associative array of header name and value

Send Examples

Send request with REQUIRED parameters only

$response = $api->send('email_id',
    array('address' => '[email protected]')
);

Send request with REQUIRED and OPTIONAL parameters

$response = $api->send('email_id',
    array(
        'name' => 'Matt',
        'address' => '[email protected]'),
    array(
    	'template_data' => array('name' => 'Jimmy the snake'),
    	'sender' => array(
            'name' => 'Company',
            'address' => '[email protected]',
            'reply_to' => '[email protected]'
        ),
        'esp_account' => 'esp_EMpi5eo59cG4cCWd7AdW7J'
    )
);

Send an email with multiple CC/BCC recipients

$response = $api->send('email_id',
    array(
        'name' => 'Matt',
        'address' => '[email protected]'
    ),
    array(
        'template_data' => array('name' => 'Jimmy the snake'),
        'sender' => array(
            'name' => 'Company',
            'address' => '[email protected]',
            'reply_to' => '[email protected]'
        ),
        'cc' => array(
            array(
                'name' => 'CC Name',
                'address' => '[email protected]'
            ),
            array(
                'name' => 'CC 2 Name',
                'address' => '[email protected]'
            )
        ),
        'bcc' => array(
            array(
                'name' => 'BCC Name',
                'address' => '[email protected]'
            )
        )
    )
);

Send an email with a dynamic tag

$response = $api->send('email_id',
    array(
        'name' => 'Matt',
        'address' => '[email protected]'),
    array(
        'tags' => array('Production', 'Client1')
    )
);

Send specific version of an email

$response = $api->send('email_id',
    array(
        'name' => 'Matt',
        'address' => '[email protected]'),
    array(
        'version_name' => 'My Version'
    )
);

Send email with an inline image attachment

$response = $api->send('email_id',
    array(
        'name' => 'Matt',
        'address' => '[email protected]'),
    array(
        'inline' => 'filename.jpg'
    )
);

Send email with an inline encoded image attachment

$response = $api->send('email_id',
    array(
        'name' => 'Matt',
        'address' => '[email protected]'),
    array(
        'inline' => array(
            'id' => 'photo.jpg',
            'data' => base64_encode(file_get_contents('filename.jpg'))
        )
    )
);

Send email with attachments

$response = $api->send('email_id',
    array(
        'name' => 'Matt',
        'address' => '[email protected]'),
    array(
        'files' => array(
            'filename.txt',
            'filename.pdf',
            array(
                'id' => 'photo.jpg',
                'data' => base64_encode(file_get_contents('filename.jpg'))
            )
        )
    )
);

Render templates

// Render function header
render(
    $email_id,      // string, id of email to send (template id)
    $args           // (optional) array, (array) additional parameters - (see below)
)

// Send function options
'template_data'  // Array of variables to merge into the template.
'version_id'     // Version ID obtained from /templates/(:template_id)/versions
'version_name'   // Version name that you want rendered (provide either a version_name or a version_id, not both)
'locale'         // Template locale to render
'strict'         // Render in strict mode (fails on missing template data)

Example:

$response = $api->render('email_id',
    array('address' => '[email protected]'),
    array(
        'template_data' => array(
            'name' => 'Bobby Boucher'
        )
    )
);

Get a Specific Email's Log

get_log(
    $log_id          // id of log to retrieve
)

Example

$response = api->get_log('log_d4R7hV4d0r')

Response

(
    [email_id] => tem_1jeid84bg
    [recipient_name] =>
    [message] => Mandrill: Message has been successfully delivered to the receiving server.
    [id] => log_d4R7hV4d0r
    [object] => log
    [created] => 1409287597
    [email_name] => test
    [recipient_address] => [email protected]
    [status] => sent
    [email_version] => Original Version
)

Resend a Specific Email from Log

resend(
    $log_id          // id of log to resend
)

Example

$response = api->resend('log_d4R7hV4d0r')

Response

(
    [status] => OK
    [receipt_id] => 130be975-dc07-4071-9333-58530e5df052-i03a5q
    [email] => stdClass Object
        (
            [locale] => en-US
            [version_name] => Test Template
            [name] => test
        )

    [success] => 1
)

Drip Unsubscribe

// Unsubscribe email address from active drips
drip_unsubscribe(
    $email_address,      // the email to unsubscribe from active drips
)

Drip Unsubscribe Example

$response = $api->drip_unsubscribe('[email protected]');

Drips 2.0

List Drip Campaigns

List all drip campaigns for the current profile

Example

$response = $api->list_drip_campaigns();

Response

Array
(
    [0] => stdClass Object
        (
            [drip_steps] => Array
                (
                    [0] => stdClass Object
                        (
                            [id] => dcs_1234abcd1234
                            [object] => drip_step
                            [delay_seconds] => 0
                            [email_id] => tem_1234abcd1234
                        )

                )

            [name] => Drip Campaign
            [enabled] => 1
            [id] => dc_1234abcd1234
            [trigger_email_id] => tem_1234abcd1234
            [object] => drip_campaign
        )
)

Start on Drip Campaign

Starts a customer on the first step of a specified drip campaign

start_on_drip_campaign(
    $recipient_address, // string, email address being added to drip campaign
    $drip_campaign_id,  // string, drip campaign being added to
    $data               // array, (optional) email data being added to drip campaign
    $args               // array, (optional) additional options being sent with email (tags, cc's, etc)
);

// Args options
'sender'      // array ("address", "name", "reply_to") of sender.
'cc'          // array of ("address", "name") for carbon copy.
'bcc'         // array of ("address", "name") for blind carbon copy.
'tags'        // array of strings to tag email send with.
'esp_account' // string of ESP ID to manually select ESP

Example

$template_data = array(
    'name' => 'Jean-Luc',
    'rank' => 'Captain'
);

$args = array(
    'tags' => array('all', 'the', 'tags'),
    'cc' => array('address' => '[email protected]')
);
$response = $api->start_on_drip_campaign('[email protected]', 'dc_1234abcd1234', $template_data, $args);

Response

stdClass Object
(
    [success] => 1
    [drip_campaign] => stdClass Object
        (
            [id] => dc_1234abcd1234
            [name] => Drip Campaign
        )

    [message] => Recipient successfully added to drip campaign.
    [status] => OK
    [recipient_address] => [email protected]
)

Remove from Drip Campaign

Deactivates all pending emails for a customer on a specified drip campaign

$response = $api->remove_from_drip_campaign(
    $recipient_address, // string, email address being removed from drip campaign
    $drip_campaign_id   // string, drip campaign being removed from
);

Example

$response = $api->remove_from_drip_campaign('[email protected]', 'dc_1234abcd1234');

Response

stdClass Object
(
    [success] => 1
    [drip_campaign] => stdClass Object
        (
            [id] => dc_1234abcd1234
            [name] => Drip Campaign
        )

    [message] => Recipient successfully removed from drip campaign.
    [status] => OK
    [recipient_address] => [email protected]
)

List Drip Campaign Details

Show all the steps and other information in a specified campaign

$response = $api->drip_campaign_details(
    $drip_campaign_id   // string, drip campaign to list details from
);

Example

$response = $api->drip_campaign_details('dc_1234abcd1234');

Response

stdClass Object
(
    [drip_steps] => Array
        (
            [0] => stdClass Object
                (
                    [id] => dcs_1234abcd1234
                    [object] => drip_step
                    [delay_seconds] => 0
                    [email_id] => tem_1234abcd1234
                )

        )

    [name] => Drip Campaign
    [enabled] => 1
    [id] => dc_1234abcd1234
    [trigger_email_id] => tem_1234abcd1234
    [object] => drip_campaign
)

Customers API

Create Customer

create_customer(
    $email,             // string, email of customer
    $data,              // array, optional, data for customer
    $args               // array, optional, optional parameters:

    // The additional optional parameters are as follows:
    //      'locale' - Default is null. String to specify a locale for this customer.
)

Example

$response = $api->create_customer('[email protected]',
    array('name' => 'Sendwithus')
);

Update Customer

update_customer(
    $email,             // string, email of customer
    $data,              // array, optional, data for customer
)

Example

$response = $api->update_customer('[email protected]',
    array('name' => 'Sendwithus.com')
);

Delete Customer

delete_customer(
    $email,             // string, email of customer
)

Example

$response = $api->delete_customer('[email protected]');

List Customer Logs

List all customer logs

Example

$response = api->get_customer_logs("[email protected]");

print_r($response);

/*
(
    [success] => 1
    [logs] => Array
        (
        [email_name] => Name of email
        [message] => Message body
        [recipient_name] => Recipient name
        [email_version] => Name of email version
        [object] => log
        [email_id] => ID of email
        [created] => Time stamp
        [recipient_address] => Email address of recipient
        [status] => Status of email
        [id] => ID of log
        )
    [status] => OK
)
*/

Batch API

Batch requests together to be run all at once.

Usage

Create a batch_api object by calling start_batch().

Do any request you would do normally with the API but on the batch_api object.

Execute all commands at once by calling execute() on the object.

Example

$batch_api = api->start_batch();
for($i = 0; $i < 10; $i++) {
    $result = $batch_api->create_customer('[email protected]',
        array('name' => 'Sendwithus'));
    // $result->success == true && $result->status == 'Batched'
}
$result = $batch_api->execute();

// $result will be an array of responses for each command executed.

Canceling Batch Request

Sometimes it is necessary to cancel all the api requests that have been batched, but not yet sent. To do that, use cancel():

Example

$batch_api = api->start_batch();
for($i = 0; $i < 10; $i++) {
    $batch_api->create_customer('[email protected]',
        array('name' => 'Sendwithus'));
}
$result = $batch_api->cancel();
// $result->success == true && $result->status == 'Canceled'

Once you have canceled a batch, you can continue to use the batch to make more requests.

Tests

Running Unit Tests

Make sure to have phpunit installed (http://phpunit.de/) and run the following from the root directory

phpunit test

Troubleshooting

General Troubleshooting

  • Enable debug mode
  • Make sure you're using the latest PHP client
  • Make sure data/ca-certificate.pem is included. This file is required
  • Capture the response data and check your logs — often this will have the exact error

Enable Debug Mode

Debug mode prints out the underlying cURL information as well as the data payload that gets sent to Sendwithus. You will most likely find this information in your logs. To enable it, simply put "DEBUG" => true in the optional parameters when instantiating the API object. Use the debug mode to compare the data payload getting sent to sendwithus' API docs.

$API_KEY = 'THIS_IS_AN_EXAMPLE_API_KEY';
$options = array(
    'DEBUG' => true
);

$api = new API($API_KEY, $options);

Response Ranges

Sendwithus' API typically sends responses back in these ranges:

  • 2xx – Successful Request
  • 4xx – Failed Request (Client error)
  • 5xx – Failed Request (Server error)

If you're receiving an error in the 400 response range follow these steps:

  • Double check the data and ID's getting passed to Sendwithus
  • Ensure your API key is correct
  • Make sure there's no extraneous spaces in the id's getting passed

Note: Enable Debug mode to check the response code.

Comments
  • Ports BathAPI from Python client

    Ports BathAPI from Python client

    Hi,

    We needed to use you batch api from our client in php and realised that it wasn't implemented there. I could find that it is implemented in your python client so I did a shameless port from the python client to the php client :)

    I'm filling this pull request since maybe you find it useful to add it to your php client (and we would love that since then we won't need to extend your code in our codebase but just update from composer instead and thats it :) )

    Please let me know your thoughts and if there is some cleaning/fixing that needs to be done before be able to merge it!

    Cheers

    opened by pbu88 5
  • Composer changes

    Composer changes

    Hi

    I have made some changes to the lib!

    1. composer.json does not have hard coded version anymore, so it will be easy to update it.
    2. As your lib does not use PSR-0, classes could still be autoloaded with classmap property.
    3. require is not needed anymore.
    4. README updated.
    5. Error class is included in PHPUnit test.
    opened by r8or0pz 5
  • Why no Packagist listing?

    Why no Packagist listing?

    Why is this project not listed on Packagist? It has ample stable releases, but GitHub's throttling is making it difficult to download directly. Why not list it on Packagist to make it easier to install?

    opened by Crell 3
  • Add priority levels to log messages

    Add priority levels to log messages

    Client version

    v6.1.0

    Expected behaviour

    It would be an improvement to have priority levels to the log messages. This could be passed to the custom log handler.

    Actual behaviour

    Currently log messages do not have any type of priority.

    opened by bogdanhadadeasv 3
  • Remove Gmail Link

    Remove Gmail Link

    Description

    Removes Gmail Link from the README.

    Motivation and Context

    Adding a Gmail account is not supported.

    How Has This Been Tested?

    N/A

    Types of changes

    • [ ] Bug fix (non-breaking change which fixes an issue)
    • [ ] New feature (non-breaking change which adds functionality)
    • [ ] Breaking change (fix or feature that would cause existing functionality to change)

    Checklist:

    • [x] My code follows the code style of this project.
    • [ ] My change requires a change to the documentation.
    • [x] I have updated the documentation accordingly.
    • [ ] I have added tests to cover my changes.
    • [x] All new and existing tests passed.
    opened by phil-ma 3
  • Missing /templates API methods

    Missing /templates API methods

    To start with, maybe just the /templates endpoint itself, to get a list of available templates? This will enable, for example, admin functionality that gets a list of templates and sends emails to a selected template id.

    opened by nik-418 3
  • [Issue #77] Added priority levels to log handler

    [Issue #77] Added priority levels to log handler

    Added priority levels to log handler

    Description

    Similar to the way syslog does it, I've added priority levels to the log_message function. This will give the end user more flexibility when using the custom log handler. Also, the logs which catch exceptions have been bumped to 'error' level.

    Motivation and Context

    Resolves issue #77

    How Has This Been Tested?

    This has been tested manually using the custom log handler and outputting the priority level along the message.

    Types of changes

    • [X] New feature (non-breaking change which adds functionality)

    Checklist:

    • [X] My code follows the code style of this project.
    • [X] My change requires a change to the documentation.
    • [X] I have updated the documentation accordingly.
    • [X] All new and existing tests passed.
    opened by bogdanhadadeasv 2
  • Get a List all Logs

    Get a List all Logs

    Hi there,

    I'm playing around with the API log and it working great with the count and offset param. What about the other mentioned on the documentation:

    • created_gt: Return logs created strictly after the given UTC timestamp.
    • created_gte: Return logs created on or after the given UTC timestamp.
    • created_lt: Return logs created strictly before the given UTC timestamp.
    • created_lte: Return logs created on or before the given UTC timestamp.

    Is it possible to add these as optional parameters in the logs method method and define them as default with null.

    Bests regards from Berlin,

    Matthias

    opened by wikimatze 2
  • Documentation Fix

    Documentation Fix

    Correct: $response->success Incorrect: $response['success']

    The response that you return is an Object, not an Array.

    Am I the only person using this code!?!? I should get free SendWithUs for life....

    opened by adamcowley 2
  • Reduced the number of log function calls

    Reduced the number of log function calls

    Description

    Reduce the number of calls to log_message to one call per instance. Instead of making 3 separate calls to log a multi-line log message in the same place, I've concatenated the message and did only one call.

    Motivation and Context

    It was redundant to make a call for each log line. Improve upon the change for issue #77

    How Has This Been Tested?

    This was manually tested.

    Types of changes

    • [X] Improvement (non-breaking change which improves code quality)

    Checklist:

    • [X] My code follows the code style of this project.
    • [X] All new and existing tests passed.
    opened by bogdanhadadeasv 1
  • [Issue #74] Added custom log handler

    [Issue #74] Added custom log handler

    Description

    Updating the API class to allow for an extra option containing a custom log handler.

    Motivation and Context

    Resolves #74

    How Has This Been Tested?

    I've added a two unit tests that go through the 2 flows:

    • one using the default logging method (using error_log)
    • a second one that uses the custom log handler

    Types of changes

    • New feature (non-breaking change which adds functionality)

    Checklist:

    • [X] My code follows the code style of this project.
    • [X] I have updated the documentation accordingly.
    • [X] I have added tests to cover my changes.
    • [X] All new and existing tests passed.
    opened by bogdanhadadeasv 1
  • BatchAPI::execute has inconsistent return values

    BatchAPI::execute has inconsistent return values

    Client version

    v3.0.0

    Expected behaviour

    When execute is called, it should always return an array of responses (a single output type).

    $batch = $api->start_batch();
    $batch->send();
    $responses = $batch->execute();
    if (is_array($responses)) {
        echo "succeeded";
    } else {
        echo "failed";
    }
    

    should output succeeded in all cases

    Actual behaviour

    outputs failed if the batch was too large, or authentication failed, or any failure that's not specific to one of the emails in the batch.

    The reason for requesting a change is that the current behavior requires boilerplate whenever calling execute():

    if (!is_array($response)) {
       //do we actually want to behave differently for this case? If so, should it be an exception?
    } else {
       //we can iterate over the responses to see what succeded, and what failed
    }
    

    Simplest "fix" would be to change this line: https://github.com/sendwithus/sendwithus_php/blob/master/lib/API.php#L782 to return the single error as an array. That way, a consumer can always depend on getting back an array.

    opened by jlesueur 4
Releases(v6.4.0)
Owner
Sendwithus by Dyspatch
Sendwithus by Dyspatch
PHP JSON-RPC 2.0 Server/Client Implementation with Automatic Client Class Generation via SMD

PHP JSON-RPC 2.0 Server/Client Implementation with Automatic Client Class Generation via SMD

Sergey Bykov 63 Feb 14, 2022
OpenAI API Client is a component-oriented, extensible client library for the OpenAI API. It's designed to be faster and more memory efficient than traditional PHP libraries.

OpenAI API Client in PHP (community-maintained) This library is a component-oriented, extensible client library for the OpenAI API. It's designed to b

Mounir R'Quiba 6 Jun 14, 2023
⚡️ Web3 PHP is a supercharged PHP API client that allows you to interact with a generic Ethereum RPC.

Web3 PHP is a supercharged PHP API client that allows you to interact with a generic Ethereum RPC. This project is a work-in-progress. Code and docume

Web3 PHP 665 Dec 23, 2022
A simple PHP GitHub API client, Object Oriented, tested and documented.

PHP GitHub API A simple Object Oriented wrapper for GitHub API, written with PHP. Uses GitHub API v3 & supports GitHub API v4. The object API (v3) is

KNP Labs 2k Jan 7, 2023
A simple Object Oriented PHP Client for Termii SMS API

Termii Client A simple Object Oriented PHP Client for Termii SMS API. Uses Termii API. Requirements PHP >= 7.2 Guzzlehttp ~6|~7 Installation Via Compo

Ilesanmi Olawale Adedotun 5 Feb 24, 2022
Xendit REST API Client for PHP - Card, Virtual Account, Invoice, Disbursement, Recurring Payments, Payout, EWallet, Balance, Retail Outlets Services

Xendit REST API Client for PHP - Card, Virtual Account, Invoice, Disbursement, Recurring Payments, Payout, EWallet, Balance, Retail Outlets Services

Xendit 96 Jan 6, 2023
PHP client for Kafka

A library to allow people to communicate to Kafka using plain PHP, compatible with Kafka v0.11+ (due to the way the protocol works).

Luís Cobucci 52 Dec 23, 2022
php 8 client for the lemon.markets api

lemon.markets php client This repository contains a php 8+ compatible client for the https://lemon.markets API. The documentation of the API can be fo

Daniel Freudenberger 4 Nov 17, 2022
PHP client for Microsoft Azure Face API.

Microsoft Azure Face API PHP client A PHP library that utilizes Azure Face REST API. Requirements PHP >= 7.4 Installation composer require darmen/php-

Darmen Amanbayev 6 Sep 14, 2022
Google PHP API Client Services

Google PHP API Client Services

Google APIs 1.1k Dec 22, 2022
AltiriaSmsPhpClient, the official PHP client of Altiria

Altiria, cliente SMS PHP Altiria SMS PHP es un cliente que simplifica al máximo la integración de nuestro API para PHP. Por el momento, esta librería

Altiria 3 Dec 22, 2022
PHP Client for the GoFlink API

GoFlink PHP API Client This project is an unofficial library to communicate with the GoFlink API from your PHP project. Documentation about the API is

Rico Hageman 4 Oct 3, 2022
A PHP client for the official Kizeo Forms API V3+. 📌

Kizeo Forms API V3+ - PHP This is a Swagger generated doc for Kizeo REST API 3. You can find additionnal documentation here : Online documentation. Th

siapepfrance 1 Oct 26, 2021
Client for the Tenant Security Proxy in PHP

Tenant Security Client PHP Library A PHP client for implementing CMK within a vendor's infrastructure. Makes requests through an IronCore Tenant Secur

IronCore Labs 1 Nov 19, 2021
Shopee Open API v2 Client build with php

Shopee PHP Client This is a Shopee PHP Client, currently supported for API V2 in ShopeeOpenPlatform Composer Install composer require haistar/shopee-p

ravimukti 17 Dec 27, 2022
The official Previewify.app PHP Client

Previewify for PHP This is the official Previewify client for PHP. Support us Like our work? You can support us by purchasing one of our products. Ins

Flowframe 6 Jan 19, 2022
Production-ready, stable Kafka client for PHP

PHP Kafka client - php-rdkafka PHP-rdkafka is a stable, production-ready, long term support, and fast Kafka client for PHP based on librdkafka. It sup

Arnaud Le Blanc 1.9k Dec 26, 2022
VideoColor PHP Search Client

This library is designed to find information about a movie and get the frame position using a screenshot from a video.

null 3 Oct 9, 2022
GitLab PHP API Client

GitLab PHP API Client We present a modern GitLab API v4 client for PHP. This is strongly based on php-github-api by KnpLabs. With this in mind, we now

 PHP GitLab API 868 Dec 30, 2022