From da6ee36fed887f952a85ad65265eae63f6401b9d Mon Sep 17 00:00:00 2001
From: Sean Johnson <pirogoeth@users.noreply.github.com>
Date: Mon, 20 Feb 2017 13:57:54 -0600
Subject: [PATCH] Implement suppressions API (#258) (#264)

* Implement suppressions API (#258)

* Fix annotation issues and use alternate pagination method
---
 src/Mailgun/Api/Suppressions.php              |  73 ++++++++++
 src/Mailgun/Api/Suppressions/Bounce.php       | 111 ++++++++++++++++
 src/Mailgun/Api/Suppressions/Complaint.php    | 110 +++++++++++++++
 src/Mailgun/Api/Suppressions/Unsubscribe.php  | 111 ++++++++++++++++
 src/Mailgun/Mailgun.php                       |   8 ++
 .../Api/Suppressions/BaseResponse.php         |  69 ++++++++++
 .../Suppressions/Bounce/CreateResponse.php    |  19 +++
 .../Suppressions/Bounce/DeleteResponse.php    |  19 +++
 .../Api/Suppressions/Bounce/IndexResponse.php |  62 +++++++++
 .../Api/Suppressions/Bounce/ShowResponse.php  | 125 ++++++++++++++++++
 .../Suppressions/Complaint/CreateResponse.php |  19 +++
 .../Suppressions/Complaint/DeleteResponse.php |  19 +++
 .../Suppressions/Complaint/IndexResponse.php  |  62 +++++++++
 .../Suppressions/Complaint/ShowResponse.php   |  77 +++++++++++
 .../Unsubscribe/CreateResponse.php            |  19 +++
 .../Unsubscribe/DeleteResponse.php            |  19 +++
 .../Unsubscribe/IndexResponse.php             |  62 +++++++++
 .../Suppressions/Unsubscribe/ShowResponse.php | 101 ++++++++++++++
 18 files changed, 1085 insertions(+)
 create mode 100644 src/Mailgun/Api/Suppressions.php
 create mode 100644 src/Mailgun/Api/Suppressions/Bounce.php
 create mode 100644 src/Mailgun/Api/Suppressions/Complaint.php
 create mode 100644 src/Mailgun/Api/Suppressions/Unsubscribe.php
 create mode 100644 src/Mailgun/Resource/Api/Suppressions/BaseResponse.php
 create mode 100644 src/Mailgun/Resource/Api/Suppressions/Bounce/CreateResponse.php
 create mode 100644 src/Mailgun/Resource/Api/Suppressions/Bounce/DeleteResponse.php
 create mode 100644 src/Mailgun/Resource/Api/Suppressions/Bounce/IndexResponse.php
 create mode 100644 src/Mailgun/Resource/Api/Suppressions/Bounce/ShowResponse.php
 create mode 100644 src/Mailgun/Resource/Api/Suppressions/Complaint/CreateResponse.php
 create mode 100644 src/Mailgun/Resource/Api/Suppressions/Complaint/DeleteResponse.php
 create mode 100644 src/Mailgun/Resource/Api/Suppressions/Complaint/IndexResponse.php
 create mode 100644 src/Mailgun/Resource/Api/Suppressions/Complaint/ShowResponse.php
 create mode 100644 src/Mailgun/Resource/Api/Suppressions/Unsubscribe/CreateResponse.php
 create mode 100644 src/Mailgun/Resource/Api/Suppressions/Unsubscribe/DeleteResponse.php
 create mode 100644 src/Mailgun/Resource/Api/Suppressions/Unsubscribe/IndexResponse.php
 create mode 100644 src/Mailgun/Resource/Api/Suppressions/Unsubscribe/ShowResponse.php

diff --git a/src/Mailgun/Api/Suppressions.php b/src/Mailgun/Api/Suppressions.php
new file mode 100644
index 0000000..8ed73eb
--- /dev/null
+++ b/src/Mailgun/Api/Suppressions.php
@@ -0,0 +1,73 @@
+<?php
+
+/*
+ * Copyright (C) 2013-2016 Mailgun
+ *
+ * This software may be modified and distributed under the terms
+ * of the MIT license. See the LICENSE file for details.
+ */
+
+namespace Mailgun\Api;
+
+use Http\Client\HttpClient;
+use Mailgun\Deserializer\ResponseDeserializer;
+use Mailgun\RequestBuilder;
+
+/**
+ * @see https://documentation.mailgun.com/api-suppressions.html
+ *
+ * @author Sean Johnson <sean@mailgun.com>
+ */
+class Suppressions
+{
+    /**
+     * @var HttpClient
+     */
+    private $httpClient;
+
+    /**
+     * @var RequestBuilder
+     */
+    private $requestBuilder;
+
+    /**
+     * @var ResponseDeserializer
+     */
+    private $deserializer;
+
+    /**
+     * @param HttpClient           $httpClient
+     * @param RequestBuilder       $requestBuilder
+     * @param ResponseDeserializer $deserializer
+     */
+    public function __construct(HttpClient $httpClient, RequestBuilder $requestBuilder, ResponseDeserializer $deserializer)
+    {
+        $this->httpClient = $httpClient;
+        $this->requestBuilder = $requestBuilder;
+        $this->deserializer = $deserializer;
+    }
+
+    /**
+     * @return Suppressions\Bounce
+     */
+    public function bounces()
+    {
+        return new Suppressions\Bounce($this->httpClient, $this->requestBuilder, $this->deserializer);
+    }
+
+    /**
+     * @return Suppressions\Complaint
+     */
+    public function complaints()
+    {
+        return new Suppressions\Complaint($this->httpClient, $this->requestBuilder, $this->deserializer);
+    }
+
+    /**
+     * @return Suppressions\Unsubscribe
+     */
+    public function unsubscribes()
+    {
+        return new Suppressions\Unsubscribe($this->httpClient, $this->requestBuilder, $this->deserializer);
+    }
+}
diff --git a/src/Mailgun/Api/Suppressions/Bounce.php b/src/Mailgun/Api/Suppressions/Bounce.php
new file mode 100644
index 0000000..1185720
--- /dev/null
+++ b/src/Mailgun/Api/Suppressions/Bounce.php
@@ -0,0 +1,111 @@
+<?php
+
+/*
+ * Copyright (C) 2013-2016 Mailgun
+ *
+ * This software may be modified and distributed under the terms
+ * of the MIT license. See the LICENSE file for details.
+ */
+
+namespace Mailgun\Api;
+
+use Mailgun\Assert;
+use Mailgun\Resource\Api\Suppressions\Bounce\CreateResponse;
+use Mailgun\Resource\Api\Suppressions\Bounce\DeleteResponse;
+use Mailgun\Resource\Api\Suppressions\Bounce\IndexResponse;
+use Mailgun\Resource\Api\Suppressions\Bounce\ShowResponse;
+
+/**
+ * @see https://documentation.mailgun.com/api-suppressions.html#bounces
+ *
+ * @author Sean Johnson <sean@mailgun.com>
+ */
+class Bounce extends HttpApi
+{
+    use Pagination;
+
+    /**
+     * @param string $domain Domain to list bounces for
+     * @param int    $limit  optional
+     *
+     * @return IndexResponse
+     */
+    public function index($domain, $limit = 100)
+    {
+        Assert::stringNotEmpty($domain);
+        Assert::range($limit, 1, 10000, '"Limit" parameter must be between 1 and 10000');
+
+        $params = [
+            'limit' => $limit,
+        ];
+
+        $response = $this->httpGet(sprintf('/v3/%s/bounces', $domain), $params);
+
+        return $this->safeDeserialize($response, IndexResponse::class);
+    }
+
+    /**
+     * @param string $domain  Domain to show bounce from
+     * @param string $address Bounce address to show
+     *
+     * @return ShowResponse
+     */
+    public function show($domain, $address)
+    {
+        Assert::stringNotEmpty($domain);
+        Assert::stringNotEmpty($address);
+
+        $response = $this->httpGet(sprintf('/v3/%s/bounces/%s', $domain, $address));
+
+        return $this->safeDeserialize($response, ShowResponse::class);
+    }
+
+    /**
+     * @param string $domain  Domain to create a bounce for
+     * @param string $address Address to create a bounce for
+     * @param array  $params  optional
+     *
+     * @return CreateResponse
+     */
+    public function create($domain, $address, array $params = [])
+    {
+        Assert::stringNotEmpty($domain);
+        Assert::stringNotEmpty($address);
+
+        $params['address'] = $address;
+
+        $response = $this->httpPost(sprintf('/v3/%s/bounces', $domain), $params);
+
+        return $this->safeDeserialize($response, CreateResponse::class);
+    }
+
+    /**
+     * @param string $domain  Domain to delete a bounce for
+     * @param string $address Bounce address to delete
+     *
+     * @return DeleteResponse
+     */
+    public function delete($domain, $address)
+    {
+        Assert::stringNotEmpty($domain);
+        Assert::stringNotEmpty($address);
+
+        $response = $this->httpDelete(sprintf('/v3/%s/bounces/%s', $domain, $address));
+
+        return $this->safeDeserialize($response, DeleteResponse::class);
+    }
+
+    /**
+     * @param string $domain Domain to delete all bounces for
+     *
+     * @return DeleteResponse
+     */
+    public function deleteAll($domain)
+    {
+        Assert::stringNotEmpty($domain);
+
+        $response = $this->httpDelete(sprintf('/v3/%s/bounces', $domain));
+
+        return $this->safeDeserialize($response, DeleteResponse::class);
+    }
+}
diff --git a/src/Mailgun/Api/Suppressions/Complaint.php b/src/Mailgun/Api/Suppressions/Complaint.php
new file mode 100644
index 0000000..847a931
--- /dev/null
+++ b/src/Mailgun/Api/Suppressions/Complaint.php
@@ -0,0 +1,110 @@
+<?php
+
+/*
+ * Copyright (C) 2013-2016 Mailgun
+ *
+ * This software may be modified and distributed under the terms
+ * of the MIT license. See the LICENSE file for details.
+ */
+
+namespace Mailgun\Api;
+
+use Mailgun\Assert;
+use Mailgun\Resource\Api\Suppressions\Complaint\CreateResponse;
+use Mailgun\Resource\Api\Suppressions\Complaint\DeleteResponse;
+use Mailgun\Resource\Api\Suppressions\Complaint\IndexResponse;
+use Mailgun\Resource\Api\Suppressions\Complaint\ShowResponse;
+
+/**
+ * @see https://documentation.mailgun.com/api-suppressions.html#complaints
+ *
+ * @author Sean Johnson <sean@mailgun.com>
+ */
+class Complaint extends HttpApi
+{
+    use Pagination;
+
+    /**
+     * @param string $domain Domain to get complaints for
+     * @param int    $limit  optional
+     *
+     * @return IndexResponse
+     */
+    public function index($domain, $limit = 100)
+    {
+        Assert::stringNotEmpty($domain);
+        Assert::range($limit, 1, 10000, 'Limit parameter must be between 1 and 10000');
+
+        $params = [
+            'limit' => $limit,
+        ];
+
+        $response = $this->httpGet(sprintf('/v3/%s/complaints', $domain), $params);
+
+        return $this->safeDeserialize($response, IndexResponse::class);
+    }
+
+    /**
+     * @param string $domain  Domain to show complaint for
+     * @param string $address Complaint address
+     *
+     * @return ShowResponse
+     */
+    public function show($domain, $address)
+    {
+        Assert::stringNotEmpty($domain);
+        Assert::stringNotEmpty($address);
+        $response = $this->httpGet(sprintf('/v3/%s/complaints/%s', $domain, $address));
+
+        return $this->safeDeserialize($response, ShowResponse::class);
+    }
+
+    /**
+     * @param string $domain  Domain to create complaint for
+     * @param string $address Complaint address
+     * @param array  $params  optional
+     *
+     * @return CreateResponse
+     */
+    public function create($domain, $address, $code = null, $error = null, $createdAt = null)
+    {
+        Assert::stringNotEmpty($domain);
+        Assert::stringNotEmpty($address);
+
+        $params['address'] = $address;
+
+        $response = $this->httpPost(sprintf('/v3/%s/complaints', $domain), $params);
+
+        return $this->safeDeserialize($response, CreateResponse::class);
+    }
+
+    /**
+     * @param string $domain  Domain to delete complaint for
+     * @param string $address Complaint address
+     *
+     * @return DeleteResponse
+     */
+    public function delete($domain, $address)
+    {
+        Assert::stringNotEmpty($domain);
+        Assert::stringNotEmpty($address);
+
+        $response = $this->httpDelete(sprintf('/v3/%s/complaints/%s', $domain, $address));
+
+        return $this->safeDeserialize($response, DeleteResponse::class);
+    }
+
+    /**
+     * @param string $domain Domain to delete all bounces for
+     *
+     * @return DeleteResponse
+     */
+    public function deleteAll($domain)
+    {
+        Assert::stringNotEmpty($domain);
+
+        $response = $this->httpDelete(sprintf('/v3/%s/complaints', $domain));
+
+        return $this->safeDeserialize($response, DeleteResponse::class);
+    }
+}
diff --git a/src/Mailgun/Api/Suppressions/Unsubscribe.php b/src/Mailgun/Api/Suppressions/Unsubscribe.php
new file mode 100644
index 0000000..3b9c170
--- /dev/null
+++ b/src/Mailgun/Api/Suppressions/Unsubscribe.php
@@ -0,0 +1,111 @@
+<?php
+
+/*
+ * Copyright (C) 2013-2016 Mailgun
+ *
+ * This software may be modified and distributed under the terms
+ * of the MIT license. See the LICENSE file for details.
+ */
+
+namespace Mailgun\Api;
+
+use Mailgun\Assert;
+use Mailgun\Resource\Api\Suppressions\Unsubscribe\CreateResponse;
+use Mailgun\Resource\Api\Suppressions\Unsubscribe\DeleteResponse;
+use Mailgun\Resource\Api\Suppressions\Unsubscribe\IndexResponse;
+use Mailgun\Resource\Api\Suppressions\Unsubscribe\ShowResponse;
+
+/**
+ * @see https://documentation.mailgun.com/api-suppressions.html#unsubscribes
+ *
+ * @author Sean Johnson <sean@mailgun.com>
+ */
+class Unsubscribe extends HttpApi
+{
+    use Pagination;
+
+    /**
+     * @param string $domain Domain to get unsubscribes for
+     * @param int    $limit  optional
+     *
+     * @return IndexResponse
+     */
+    public function index($domain, $limit = 100)
+    {
+        Assert::stringNotEmpty($domain);
+        Assert::range($limit, 1, 10000, 'Limit parameter must be between 1 and 10000');
+
+        $params = [
+            'limit' => $limit,
+        ];
+
+        $response = $this->httpGet(sprintf('/v3/%s/unsubscribes', $domain), $params);
+
+        return $this->safeDeserialize($response, IndexResponse::class);
+    }
+
+    /**
+     * @param string $domain  Domain to show unsubscribe for
+     * @param string $address Unsubscribe address
+     *
+     * @return ShowResponse
+     */
+    public function show($domain, $address)
+    {
+        Assert::stringNotEmpty($domain);
+        Assert::stringNotEmpty($address);
+
+        $response = $this->httpGet(sprintf('/v3/%s/unsubscribes/%s', $domain, $address));
+
+        return $this->safeDeserialize($response, ShowResponse::class);
+    }
+
+    /**
+     * @param string $domain  Domain to create unsubscribe for
+     * @param string $address Unsubscribe address
+     * @param array  $params  optional
+     *
+     * @return CreateResponse
+     */
+    public function create($domain, $address, array $params = [])
+    {
+        Assert::stringNotEmpty($domain);
+        Assert::stringNotEmpty($address);
+
+        $params['address'] = $address;
+
+        $response = $this->httpPost(sprintf('/v3/%s/unsubscribes', $domain), $params);
+
+        return $this->safeDeserialize($response, CreateResponse::class);
+    }
+
+    /**
+     * @param string $domain  Domain to delete unsubscribe for
+     * @param string $address Unsubscribe address
+     *
+     * @return DeleteResponse
+     */
+    public function delete($domain, $address)
+    {
+        Assert::stringNotEmpty($domain);
+        Assert::stringNotEmpty($address);
+
+        $response = $this->httpDelete(sprintf('/v3/%s/unsubscribes/%s', $domain, $address));
+
+        return $this->safeDeserialize($response, DeleteResponse::class);
+    }
+
+    /**
+     * @param string $domain Domain to delete all unsubscribes for
+     *
+     * @return DeleteResponse
+     */
+    public function deleteAll($domain)
+    {
+        Assert::stringNotEmpty($domain);
+
+        $response = $this->httpDelete(sprintf('/v3/%s/unsubscribes', $domain));
+
+        return $this->safeDeserialize($response, DeleteResponse::class);
+    }
+}
diff --git a/src/Mailgun/Mailgun.php b/src/Mailgun/Mailgun.php
index 433fa9a..67c2440 100644
--- a/src/Mailgun/Mailgun.php
+++ b/src/Mailgun/Mailgun.php
@@ -300,4 +300,12 @@ class Mailgun
     {
         return new Api\Message($this->httpClient, $this->requestBuilder, $this->deserializer);
     }
+
+    /**
+     * @return Api\Suppressions
+     */
+    public function suppressions()
+    {
+        return new Api\Suppressions($this->httpClient, $this->requestBuilder, $this->deserializer);
+    }
 }
diff --git a/src/Mailgun/Resource/Api/Suppressions/BaseResponse.php b/src/Mailgun/Resource/Api/Suppressions/BaseResponse.php
new file mode 100644
index 0000000..cede881
--- /dev/null
+++ b/src/Mailgun/Resource/Api/Suppressions/BaseResponse.php
@@ -0,0 +1,69 @@
+<?php
+
+/*
+ * Copyright (C) 2013-2016 Mailgun
+ *
+ * This software may be modified and distributed under the terms
+ * of the MIT license. See the LICENSE file for details.
+ */
+
+namespace Mailgun\Resource\Api\Suppressions;
+
+use Mailgun\Resource\ApiResponse;
+
+/**
+ * Serves only as an abstract base for suppressions API code.
+ *
+ * @author Sean Johnson <sean@mailgun.com>
+ */
+abstract class BaseResponse implements ApiResponse
+{
+    /**
+     * @var string
+     */
+    private $address;
+
+    /**
+     * @var string
+     */
+    private $message;
+
+    /**
+     * @param string $address
+     * @param string $message
+     */
+    private function __construct($address, $message)
+    {
+        $this->address = $address;
+        $this->message = $message;
+    }
+
+    /**
+     * @param array $data
+     *
+     * @return BaseResponse
+     */
+    public static function create(array $data)
+    {
+        $address = isset($data['address']) ? $data['address'] : '';
+        $message = isset($data['message']) ? $data['message'] : '';
+
+        return new static($address, $message);
+    }
+
+    /**
+     * @return string
+     */
+    public function getAddress()
+    {
+        return $this->address;
+    }
+
+    /**
+     * @return string
+     */
+    public function getMessage()
+    {
+        return $this->message;
+    }
+}
diff --git a/src/Mailgun/Resource/Api/Suppressions/Bounce/CreateResponse.php b/src/Mailgun/Resource/Api/Suppressions/Bounce/CreateResponse.php
new file mode 100644
index 0000000..d921c3d
--- /dev/null
+++ b/src/Mailgun/Resource/Api/Suppressions/Bounce/CreateResponse.php
@@ -0,0 +1,19 @@
+<?php
+
+/*
+ * Copyright (C) 2013-2016 Mailgun
+ *
+ * This software may be modified and distributed under the terms
+ * of the MIT license. See the LICENSE file for details.
+ */
+
+namespace Mailgun\Resource\Api\Suppressions\Bounce;
+
+use Mailgun\Resource\Api\Suppressions\BaseResponse;
+
+/**
+ * @author Sean Johnson <sean@mailgun.com>
+ */
+final class CreateResponse extends BaseResponse
+{
+}
diff --git a/src/Mailgun/Resource/Api/Suppressions/Bounce/DeleteResponse.php b/src/Mailgun/Resource/Api/Suppressions/Bounce/DeleteResponse.php
new file mode 100644
index 0000000..85fa2a4
--- /dev/null
+++ b/src/Mailgun/Resource/Api/Suppressions/Bounce/DeleteResponse.php
@@ -0,0 +1,19 @@
+<?php
+
+/*
+ * Copyright (C) 2013-2016 Mailgun
+ *
+ * This software may be modified and distributed under the terms
+ * of the MIT license. See the LICENSE file for details.
+ */
+
+namespace Mailgun\Resource\Api\Suppression\Bounce;
+
+use Mailgun\Resource\Api\Suppressions\BaseResponse;
+
+/**
+ * @author Sean Johnson <sean@mailgun.com>
+ */
+final class DeleteResponse extends BaseResponse
+{
+}
diff --git a/src/Mailgun/Resource/Api/Suppressions/Bounce/IndexResponse.php b/src/Mailgun/Resource/Api/Suppressions/Bounce/IndexResponse.php
new file mode 100644
index 0000000..2c8470b
--- /dev/null
+++ b/src/Mailgun/Resource/Api/Suppressions/Bounce/IndexResponse.php
@@ -0,0 +1,62 @@
+<?php
+
+/*
+ * Copyright (C) 2013-2016 Mailgun
+ *
+ * This software may be modified and distributed under the terms
+ * of the MIT license. See the LICENSE file for details.
+ */
+
+namespace Mailgun\Resource\Api\Suppressions\Bounce;
+
+use Mailgun\Resource\ApiResponse;
+use Mailgun\Resource\Api\PaginationResponse;
+use Mailgun\Resource\Api\PagingProvider;
+
+/**
+ * @author Sean Johnson <sean@mailgun.com>
+ */
+final class IndexResponse implements ApiResponse, PagingProvider
+{
+    use PaginationResponse;
+
+    /**
+     * @var Bounce[]
+     */
+    private $items;
+
+    /**
+     * @param Bounce[] $items
+     * @param array    $paging
+     */
+    private function __construct(array $items, array $paging)
+    {
+        $this->items = $items;
+        $this->paging = $paging;
+    }
+
+    /**
+     * @param array $data
+     *
+     * @return IndexResponse
+     */
+    public static function create(array $data)
+    {
+        $bounces = [];
+        if (isset($data['items'])) {
+            foreach ($data['items'] as $item) {
+                $bounces[] = Bounce::create($item);
+            }
+        }
+
+        return new self($bounces, $data['paging']);
+    }
+
+    /**
+     * @return Bounce[]
+     */
+    public function getItems()
+    {
+        return $this->items;
+    }
+}
diff --git a/src/Mailgun/Resource/Api/Suppressions/Bounce/ShowResponse.php b/src/Mailgun/Resource/Api/Suppressions/Bounce/ShowResponse.php
new file mode 100644
index 0000000..3e08e65
--- /dev/null
+++ b/src/Mailgun/Resource/Api/Suppressions/Bounce/ShowResponse.php
@@ -0,0 +1,125 @@
+<?php
+
+/*
+ * Copyright (C) 2013-2016 Mailgun
+ *
+ * This software may be modified and distributed under the terms
+ * of the MIT license. See the LICENSE file for details.
+ */
+
+namespace Mailgun\Resource\Api\Suppressions\Bounce;
+
+use Mailgun\Resource\ApiResponse;
+
+/**
+ * @author Sean Johnson <sean@mailgun.com>
+ */
+final class ShowResponse implements ApiResponse
+{
+    /**
+     * @var string
+     */
+    private $address;
+
+    /**
+     * @var string
+     */
+    private $code;
+
+    /**
+     * @var string
+     */
+    private $error;
+
+    /**
+     * @var \DateTime
+     */
+    private $createdAt;
+
+    /**
+     * @param string $address
+     */
+    private function __construct($address)
+    {
+        $this->address = $address;
+        $this->createdAt = new \DateTime();
+    }
+
+    /**
+     * @param array $data
+     *
+     * @return ShowResponse
+     */
+    public static function create(array $data)
+    {
+        $bounce = new self($data['address']);
+
+        if (isset($data['code'])) {
+            $this->setCode($data['code']);
+        }
+        if (isset($data['error'])) {
+            $this->setError($data['error']);
+        }
+        if (isset($data['created_at'])) {
+            $this->setCreatedAt(new \DateTime($data['created_at']));
+        }
+
+        return $bounce;
+    }
+
+    /**
+     * @return string
+     */
+    public function getAddress()
+    {
+        return $this->address;
+    }
+
+    /**
+     * @return string
+     */
+    public function getCode()
+    {
+        return $this->code;
+    }
+
+    /**
+     * @param string $code
+     */
+    private function setCode($code)
+    {
+        $this->code = $code;
+    }
+
+    /**
+     * @return string
+     */
+    public function getError()
+    {
+        return $this->error;
+    }
+
+    /**
+     * @param string $error
+     */
+    private function setError($error)
+    {
+        $this->error = $error;
+    }
+
+    /**
+     * @return \DateTime
+     */
+    public function getCreatedAt()
+    {
+        return $this->createdAt;
+    }
+
+    /**
+     * @param \DateTime $createdAt
+     */
+    private function setCreatedAt(\DateTime $createdAt)
+    {
+        $this->createdAt = $createdAt;
+    }
+}
diff --git a/src/Mailgun/Resource/Api/Suppressions/Complaint/CreateResponse.php b/src/Mailgun/Resource/Api/Suppressions/Complaint/CreateResponse.php
new file mode 100644
index 0000000..d685626
--- /dev/null
+++ b/src/Mailgun/Resource/Api/Suppressions/Complaint/CreateResponse.php
@@ -0,0 +1,19 @@
+<?php
+
+/*
+ * Copyright (C) 2013-2016 Mailgun
+ *
+ * This software may be modified and distributed under the terms
+ * of the MIT license. See the LICENSE file for details.
+ */
+
+namespace Mailgun\Resource\Api\Suppressions\Complaint;
+
+use Mailgun\Resource\Api\Suppressions\BaseResponse;
+
+/**
+ * @author Sean Johnson <sean@mailgun.com>
+ */
+final class CreateResponse extends BaseResponse
+{
+}
diff --git a/src/Mailgun/Resource/Api/Suppressions/Complaint/DeleteResponse.php b/src/Mailgun/Resource/Api/Suppressions/Complaint/DeleteResponse.php
new file mode 100644
index 0000000..0834df3
--- /dev/null
+++ b/src/Mailgun/Resource/Api/Suppressions/Complaint/DeleteResponse.php
@@ -0,0 +1,19 @@
+<?php
+
+/*
+ * Copyright (C) 2013-2016 Mailgun
+ *
+ * This software may be modified and distributed under the terms
+ * of the MIT license. See the LICENSE file for details.
+ */
+
+namespace Mailgun\Resource\Api\Suppressions\Complaint;
+
+use Mailgun\Resource\Api\Suppressions\BaseResponse;
+
+/**
+ * @author Sean Johnson <sean@mailgun.com>
+ */
+final class DeleteResponse extends BaseResponse
+{
+}
diff --git a/src/Mailgun/Resource/Api/Suppressions/Complaint/IndexResponse.php b/src/Mailgun/Resource/Api/Suppressions/Complaint/IndexResponse.php
new file mode 100644
index 0000000..4afe1ef
--- /dev/null
+++ b/src/Mailgun/Resource/Api/Suppressions/Complaint/IndexResponse.php
@@ -0,0 +1,62 @@
+<?php
+
+/*
+ * Copyright (C) 2013-2016 Mailgun
+ *
+ * This software may be modified and distributed under the terms
+ * of the MIT license. See the LICENSE file for details.
+ */
+
+namespace Mailgun\Resource\Api\Suppressions\Complaint;
+
+use Mailgun\Resource\ApiResponse;
+use Mailgun\Resource\Api\PaginationResponse;
+use Mailgun\Resource\Api\PagingProvider;
+
+/**
+ * @author Sean Johnson <sean@mailgun.com>
+ */
+final class IndexResponse implements ApiResponse, PagingProvider
+{
+    use PaginationResponse;
+
+    /**
+     * @var Complaint[]
+     */
+    private $items;
+
+    /**
+     * @param Complaint[] $items
+     * @param array       $paging
+     */
+    private function __construct(array $items, array $paging)
+    {
+        $this->items = $items;
+        $this->paging = $paging;
+    }
+
+    /**
+     * @param array $data
+     *
+     * @return IndexResponse
+     */
+    public static function create(array $data)
+    {
+        $complaints = [];
+        if (isset($data['items'])) {
+            foreach ($data['items'] as $item) {
+                $complaints[] = Complaint::create($item);
+            }
+        }
+
+        return new self($complaints, $data['paging']);
+    }
+
+    /**
+     * @return Complaint[]
+     */
+    public function getItems()
+    {
+        return $this->items;
+    }
+}
diff --git a/src/Mailgun/Resource/Api/Suppressions/Complaint/ShowResponse.php b/src/Mailgun/Resource/Api/Suppressions/Complaint/ShowResponse.php
new file mode 100644
index 0000000..37a7b5c
--- /dev/null
+++ b/src/Mailgun/Resource/Api/Suppressions/Complaint/ShowResponse.php
@@ -0,0 +1,77 @@
+<?php
+
+/*
+ * Copyright (C) 2013-2016 Mailgun
+ *
+ * This software may be modified and distributed under the terms
+ * of the MIT license. See the LICENSE file for details.
+ */
+
+namespace Mailgun\Resource\Api\Suppressions\Complaint;
+
+use Mailgun\Resource\ApiResponse;
+
+/**
+ * @author Sean Johnson <sean@mailgun.com>
+ */
+final class ShowResponse implements ApiResponse
+{
+    /**
+     * @var string
+     */
+    private $address;
+
+    /**
+     * @var \DateTime
+     */
+    private $createdAt;
+
+    /**
+     * @param string $address
+     */
+    private function __construct($address)
+    {
+        $this->address = $address;
+        $this->createdAt = new \DateTime();
+    }
+
+    /**
+     * @param array $data
+     *
+     * @return ShowResponse
+     */
+    public static function create(array $data)
+    {
+        $bounce = new self($data['address']);
+
+        if (isset($data['created_at'])) {
+            $this->setCreatedAt(new \DateTime($data['created_at']));
+        }
+
+        return $bounce;
+    }
+
+    /**
+     * @return string
+     */
+    public function getAddress()
+    {
+        return $this->address;
+    }
+
+    /**
+     * @return \DateTime
+     */
+    public function getCreatedAt()
+    {
+        return $this->createdAt;
+    }
+
+    /**
+     * @param \DateTime $createdAt
+     */
+    private function setCreatedAt(\DateTime $createdAt)
+    {
+        $this->createdAt = $createdAt;
+    }
+}
diff --git a/src/Mailgun/Resource/Api/Suppressions/Unsubscribe/CreateResponse.php b/src/Mailgun/Resource/Api/Suppressions/Unsubscribe/CreateResponse.php
new file mode 100644
index 0000000..04e63d0
--- /dev/null
+++ b/src/Mailgun/Resource/Api/Suppressions/Unsubscribe/CreateResponse.php
@@ -0,0 +1,19 @@
+<?php
+
+/*
+ * Copyright (C) 2013-2016 Mailgun
+ *
+ * This software may be modified and distributed under the terms
+ * of the MIT license. See the LICENSE file for details.
+ */
+
+namespace Mailgun\Resource\Api\Suppressions\Unsubscribe;
+
+use Mailgun\Resource\Api\Suppressions\BaseResponse;
+
+/**
+ * @author Sean Johnson <sean@mailgun.com>
+ */
+final class CreateResponse extends BaseResponse
+{
+}
diff --git a/src/Mailgun/Resource/Api/Suppressions/Unsubscribe/DeleteResponse.php b/src/Mailgun/Resource/Api/Suppressions/Unsubscribe/DeleteResponse.php
new file mode 100644
index 0000000..401de2b
--- /dev/null
+++ b/src/Mailgun/Resource/Api/Suppressions/Unsubscribe/DeleteResponse.php
@@ -0,0 +1,19 @@
+<?php
+
+/*
+ * Copyright (C) 2013-2016 Mailgun
+ *
+ * This software may be modified and distributed under the terms
+ * of the MIT license. See the LICENSE file for details.
+ */
+
+namespace Mailgun\Resource\Api\Suppressions\Unsubscribe;
+
+use Mailgun\Resource\Api\Suppressions\BaseResponse;
+
+/**
+ * @author Sean Johnson <sean@mailgun.com>
+ */
+final class DeleteResponse extends BaseResponse
+{
+}
diff --git a/src/Mailgun/Resource/Api/Suppressions/Unsubscribe/IndexResponse.php b/src/Mailgun/Resource/Api/Suppressions/Unsubscribe/IndexResponse.php
new file mode 100644
index 0000000..bd8d5c1
--- /dev/null
+++ b/src/Mailgun/Resource/Api/Suppressions/Unsubscribe/IndexResponse.php
@@ -0,0 +1,62 @@
+<?php
+
+/*
+ * Copyright (C) 2013-2016 Mailgun
+ *
+ * This software may be modified and distributed under the terms
+ * of the MIT license. See the LICENSE file for details.
+ */
+
+namespace Mailgun\Resource\Api\Suppressions\Unsubscribe;
+
+use Mailgun\Resource\ApiResponse;
+use Mailgun\Resource\Api\PaginationResponse;
+use Mailgun\Resource\Api\PagingProvider;
+
+/**
+ * @author Sean Johnson <sean@mailgun.com>
+ */
+final class IndexResponse implements ApiResponse, PagingProvider
+{
+    use PaginationResponse;
+
+    /**
+     * @var Unsubscribe[]
+     */
+    private $items;
+
+    /**
+     * @param Unsubscribe[] $items
+     * @param array         $paging
+     */
+    private function __construct(array $items, array $paging)
+    {
+        $this->items = $items;
+        $this->paging = $paging;
+    }
+
+    /**
+     * @param array $data
+     *
+     * @return IndexResponse
+     */
+    public static function create(array $data)
+    {
+        $unsubscribes = [];
+        if (isset($data['items'])) {
+            foreach ($data['items'] as $item) {
+                $unsubscribes[] = Unsubscribes::create($item);
+            }
+        }
+
+        return new self($unsubscribes, $data['paging']);
+    }
+
+    /**
+     * @return Unsubscribe[]
+     */
+    public function getItems()
+    {
+        return $this->items;
+    }
+}
diff --git a/src/Mailgun/Resource/Api/Suppressions/Unsubscribe/ShowResponse.php b/src/Mailgun/Resource/Api/Suppressions/Unsubscribe/ShowResponse.php
new file mode 100644
index 0000000..4d29a19
--- /dev/null
+++ b/src/Mailgun/Resource/Api/Suppressions/Unsubscribe/ShowResponse.php
@@ -0,0 +1,101 @@
+<?php
+
+/*
+ * Copyright (C) 2013-2016 Mailgun
+ *
+ * This software may be modified and distributed under the terms
+ * of the MIT license. See the LICENSE file for details.
+ */
+
+namespace Mailgun\Resource\Api\Suppressions\Unsubscribe;
+
+use Mailgun\Resource\ApiResponse;
+
+/**
+ * @author Sean Johnson <sean@mailgun.com>
+ */
+final class ShowResponse implements ApiResponse
+{
+    /**
+     * @var string
+     */
+    private $address;
+
+    /**
+     * @var string
+     */
+    private $tag;
+
+    /**
+     * @var \DateTime
+     */
+    private $createdAt;
+
+    /**
+     * @param string $address
+     */
+    private function __construct($address)
+    {
+        $this->address = $address;
+        $this->createdAt = new \DateTime();
+    }
+
+    /**
+     * @param array $data
+     *
+     * @return ShowResponse
+     */
+    public static function create(array $data)
+    {
+        $unsubscribe = new self($data['address']);
+
+        if (isset($data['tag'])) {
+            $this->setTag($data['tag']);
+        }
+        if (isset($data['created_at'])) {
+            $this->setCreatedAt(new \DateTime($data['created_at']));
+        }
+
+        return $unsubscribe;
+    }
+
+    /**
+     * @return string
+     */
+    public function getAddress()
+    {
+        return $this->address;
+    }
+
+    /**
+     * @return string
+     */
+    public function getTag()
+    {
+        return $this->tag;
+    }
+
+    /**
+     * @param string $tag
+     */
+    private function setTag($tag)
+    {
+        $this->tag = $tag;
+    }
+
+    /**
+     * @return \DateTime
+     */
+    public function getCreatedAt()
+    {
+        return $this->createdAt;
+    }
+
+    /**
+     * @param \DateTime $createdAt
+     */
+    private function setCreatedAt(\DateTime $createdAt)
+    {
+        $this->createdAt = $createdAt;
+    }
+}