openapi: 3.0.0
# Added by API Auto Mocking Plugin
servers:
  - description: Sakari Production
    url: https://api.sakari.io
info:
  description: |
    # Introduction
    
    Welcome to the documentation for the Sakari Messaging REST API. 
    
    Sakari provides an advanced platform to drive large scale customized SMS communication
    
    REST is a web-service protocol that lends itself to rapid development by using everyday HTTP and JSON technology.
    
    To find out more about our product offering, please visit [https://sakari.io](https://sakari.io).
    
    # Quickstart
    
    For your convenience we have created a quickstart guide to get you up and running in 5 minutes. 
    
    [https://sakari.io/blog/sakari-api-quickstart](https://sakari.io/blog/sakari-api-quickstart)
    
    # PostMan Collection
    
    We've created a simple set of examples using [PostMan](https://www.getpostman.com/) Simply click below to import these. You will need to setup three environment variables in PostMan - AccountId, ClientId and ClientSecret. Check out our PostMan blog post for more information
    
    [![Run in Postman](https://run.pstmn.io/button.svg)](https://app.getpostman.com/run-collection/d616e273edc916a7a6eb)
    
    # Finding your client id, client secret and account id
    
    To authenticate against the API's you will need three key pieces of data
     - client id
     - client secret
     - account id
    
    To retrieve these, simply login into [https://hub.sakari.io](https://hub.sakari.io) and click on the "cog" in the top right corner. In the popup dialog at the bottom you should see your API credentials and account id. If these are not visible you will need to click on "Request Credentials"
    
    # Versioning

    With any breaking changes we will introduce a new version of the API. The latest version is v1.
    
    The API uses an open schema model, which means server may add extra properties to responses. Likewise, the server will ignore any extra query parameters and request body properties. When you write clients, you need to ignore additional properties in responses to ensure they do not break.
    
    # Testing

    There are numerous tools available for testing the API's. We will include examples using curl and the client SDKs that we have created. If you would like to see an SDK in a language not currently available, please let us know.
    
    # Throttling / Limits
    
    Our API's have been specifically designed to support bulk messaging in a single API call. We therefore impose limits on the frequency of calling the APIs to prevent abuse or runaway processes. If you feel you need a higher limit, please contact us. If you hit the limit you will get a 429 error code returned from our servers

    # Errors

    The API uses standard HTTP status codes to indicate the success or failure of the API call. The body of the response will be JSON in the following format:

    ```
    {
      "success": false,
      "error": {
        "code": "CONT-001",
        "message": "Invalid mobile number"
      }
    }
    ```
    
    # Pagination
    
    For performance, most GET calls return a subset of data. This data is paginated for easy access. Most APIs which return collections of data will return a pagination object as such:
    
    ```
    {
      "pagination": {
        "offset": 0,
        "limit": 10
        "totalCount": 21
      }  
    }
    ```
    
    When making calls to the API, you can adjust the slice of data returned using query parameters such as:
    
    `` https://api.sakari.io/v1/accounts/123/contacts?offset=20&limit=25 ``
    
    This will return 25 contacts with an offset of 20.
    
  version: "1.0.1"
  title: Sakari
  termsOfService: 'https://sakari.io/terms-service.html'
  contact:
    email: support@sakari.io
  # x-logo: 
    # url: 'https://sakari.io/assets/images/sakari_logo.svg'
tags:
  - name: authentication
    description: |
      Sakari uses OAuth2 for authentication. After you have created an account at [https://hub.sakari.io](https://hub.sakari.io), you can retrieve your client id and secret from the 'Account Details' screen (click on the 'cog' icon in the top right corner and scroll down to API Credentials)
      
      Using your client id and secret, you can exchange these for a JWT ([JSON Web Token](https://en.wikipedia.org/wiki/JSON_Web_Token))
      
      The JWT should then be used when accessing any of the core API's. It should be passed in the `Authorization` header.
      
      For example:
      
      ``Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImt....``
    
  - name: contacts
    description: Create, modify or delete contacts
    # externalDocs:
      # description: Find out more
      # url: 'https://sakari.io'
  - name: messages
    description: Send or track messages to one contact, a group of contacts or your entire address book 
  - name: templates
    description: Define reusable message or web templates
  - name: campaigns
    description: Define reusable message campaigns with a predefined contact list/filter, template and schedule
  - name: conversations
    description: Conversations group your message history with each contact into one thread
  - name: tools
    description: Tools to assist with sending and receiving messages, such as file sharing, translation, etc.
  - name: webhooks
    description: Webhooks allow your own system to be automatically notified upon certin events, such as a new message received from one of your contacts or a status change notification for your messages

paths:
  /oauth2/token:
    post:
      tags:
      - authentication
      summary: Get token for accessing APIs
      operationId: auth.token
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TokenRequest'
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TokenResponse'
      x-code-samples:
        - lang: CURL
          source: |
            curl -X POST \
              https://api.sakari.io/oauth2/token \
              -H 'Content-Type: application/json' \
              -d '{
              "grant_type": "client_credentials",
              "client_id": "12345678-1234-1234-1234-123456789012",
              "client_secret": "87654321-4321-4321-4321-098765432121"
            }'
        - lang: JavaScript
          source: |
            var settings = {
              "async": true,
              "crossDomain": true,
              "url": "https://api.sakari.io/oauth2/token",
              "method": "POST",
              "headers": {
                "Content-Type": "application/json"
              },
              "processData": false,
              "data": "{\n\t\"grant_type\": \"client_credentials\",\n\t\"client_id\": \"12345678-1234-1234-1234-123456789012\",\n\t\"client_secret\": \"87654321-4321-4321-4321-098765432121\"\n}"
            }
            
            $.ajax(settings).done(function (response) {
              console.log(response);
            });
        - lang: PHP
          source: |
            <?php

              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/oauth2/token');
              $request->setMethod(HTTP_METH_POST);
              
              $request->setHeaders(array(
                'Content-Type' => 'application/json'
              ));
              
              $request->setBody('{
                "grant_type": "client_credentials",
                "client_id": "12345678-1234-1234-123456789012",
                "client_secret": "87654321-4321-4321-898765432121"
              }');
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }

  /v1/accounts/{accountId}/contacts:
    get:
      tags:
      - contacts
      summary: Fetch contacts
      operationId: contacts.fetchAll
      parameters:
      - $ref: '#/components/parameters/accountId'
      - $ref: '#/components/parameters/offset'
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/firstNameFilter'
      - $ref: '#/components/parameters/lastNameFilter'
      - $ref: '#/components/parameters/mobileFilter'
      - $ref: '#/components/parameters/emailFilter'
      - $ref: '#/components/parameters/tagsFilter'
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ContactsResponse'
        4XX:
          description: invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        5XX:
          description: invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - sakari_auth: []
      x-code-samples:
        - lang: CURL
          source: |
            curl -X GET \
              https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/contacts \
              -H 'Authorization: Bearer {{TOKEN}}'
        - lang: JavaScript
          source: |
            var request = require("request");
            var options = { method: 'GET',
              url: 'https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/contacts',
              headers: 
               { Authorization: 'Bearer {{TOKEN}}' } };
            
            request(options, function (error, response, body) {
              if (error) throw new Error(error);
            
              console.log(body);
            });

        - lang: PHP
          source: |
            <?php
              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/contacts');
              $request->setMethod(HTTP_METH_GET);
              
              $request->setHeaders(array(
                'Authorization' => 'Bearer {{TOKEN}}'
              ));
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }
      
    post:
      tags:
      - contacts
      summary: Create contact
      operationId: contacts.create
      parameters:
      - $ref: '#/components/parameters/accountId'
      - name: mergeStrategy
        in: query
        description: Determines how existing contacts with matching mobile numbers are treated
        required: false
        schema:
          type: string
          # TODO add enum descriptions
          enum:
          - append
          - core
          - remove
      requestBody:
        content:
          application/json:
            schema: 
              $ref: '#/components/schemas/ContactRequest'
          text/csv:
            #description: Bulk upload using CSV file
            schema:
              type: string
              example: >
                country,firstName,lastName,email,mobile,jobTitle,Address,City,State,ZipCode
                US,Joe,Bloggs,joebloggs@sakari.co,123-456-7890,mover,123 Text Street,San Francisco,CA,12345
      responses:
        201:
          description: successful operation
          content:
            application/json:
              schema: 
                oneOf:
                  - $ref: '#/components/schemas/ContactsResponse'
                  - $ref: '#/components/schemas/ContactUploadResponse'
      security:
      - sakari_auth: []
      x-code-samples:
        - lang: CURL
          source: |
            curl -X POST \
              https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/contacts \
              -H 'Content-Type: application/json' \
              -d '{
              "firstName": "Chris",
              "lastName": "Thomson",
              "mobile": {
                "number": "+1234567890",
                "country": "US"
              }
            }'
        - lang: JavaScript
          source: |
            var request = require("request");
            var options = { method: 'POST',
              url: 'https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/contacts',
              headers: {
                 Authorization: 'Bearer {{TOKEN}}',
                 'Content-Type': 'application/json' },
              body: 
               { firstName: 'Chris',
                 lastName: 'Thomson',
                 mobile: { number: '+1234567890', country: 'US' } },
              json: true };
            
            request(options, function (error, response, body) {
              if (error) throw new Error(error);
            
              console.log(body);
            });

        - lang: PHP
          source: |
            <?php
              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/contacts');
              $request->setMethod(HTTP_METH_POST);
              
              $request->setHeaders(array(
                'Content-Type' => 'application/json'
              ));
              
              $request->setBody('{
                "firstName": "Chris",
                "lastName": "Thomson",
                "mobile": {
                  "number": "+1234567890",
                  "country": "US"
                }
              }');
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }
      
  /v1/accounts/{accountId}/contacts/{contactId}:
    get:
      tags:
      - contacts
      summary: Fetch contact by ID
      operationId: contacts.fetch
      parameters:
      - $ref: '#/components/parameters/accountId'
      - name: contactId
        in: path
        description: ID of contact to return
        required: true
        schema:
          type: string
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema: 
                $ref: '#/components/schemas/ContactResponse'
      security:
      - sakari_auth: []
      x-code-samples:
        - lang: CURL
          source: |
            curl -X GET \
              https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/contacts/{{CONTACT_ID}} \
              -H 'Authorization: Bearer {{TOKEN}}'
        - lang: JavaScript
          source: |
            var request = require("request");
            var options = { method: 'GET',
              url: 'https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/contacts/{{CONTACT_ID}}',
              headers: 
               { Authorization: 'Bearer {{TOKEN}}' } };
            
            request(options, function (error, response, body) {
              if (error) throw new Error(error);
            
              console.log(body);
            });

        - lang: PHP
          source: |
            <?php
              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/contacts/{{CONTACT_ID}}');
              $request->setMethod(HTTP_METH_GET);
              
              $request->setHeaders(array(
                'Authorization' => 'Bearer {{TOKEN}}'
              ));
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }
    put:
      tags:
      - contacts
      summary: Updates a contact
      operationId: contacts.update
      parameters:
      - $ref: '#/components/parameters/accountId'
      - name: contactId
        in: path
        description: ID of contact
        required: true
        schema:
          type: string
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema: 
                $ref: '#/components/schemas/ContactResponse'
      security:
      - sakari_auth: []
      x-code-samples:
        - lang: CURL
          source: |
            curl -X PUT \
              https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/contacts/{{CONTACT_ID}} \
              -H 'Authorization: Bearer {{TOKEN}}'' \
              -H 'Content-Type: application/json' \
              -d '{
              "firstName": "Bob",
              "lastName": "Thomson",
              "mobile": {
                "number": "+1234567890",
                "country": "US"
              }
            }'
        - lang: JavaScript
          source: |
            var request = require("request");
            var options = { method: 'PUT',
              url: 'https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/contacts/{{CONTACT_ID}}',
              headers: 
               { 'Authorization': 'Bearer {{TOKEN}}',
                 'Content-Type': 'application/json' },
              body: 
               { firstName: 'Bob',
                 lastName: 'Thomson',
                 mobile: { number: '+1234567890', country: 'US' } },
              json: true };
            
            request(options, function (error, response, body) {
              if (error) throw new Error(error);
            
              console.log(body);
            });

        - lang: PHP
          source: |
            <?php
              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/contacts/{{CONTACT_ID}}');
              $request->setMethod(HTTP_METH_PUT);
              
              $request->setHeaders(array(
                'Authorization' => 'Bearer {{TOKEN}}',
                'Content-Type' => 'application/json'
              ));
              
              $request->setBody('{
                "firstName": "Bob",
                "lastName": "Thomson",
                "mobile": {
                  "number": "+1234567890",
                  "country": "US"
                }
              }');
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }
    delete:
      tags:
      - contacts
      summary: Deletes a contact
      operationId: contacts.remove
      parameters:
      - $ref: '#/components/parameters/accountId'
      - name: contactId
        in: path
        description: Contact id to delete
        required: true
        schema:
          type: string
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema: 
                type: object
                properties:
                  success:
                    type: boolean
      security:
      - sakari_auth: []
      x-code-samples:
        - lang: CURL
          source: |
            curl -X DELETE \
              https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/contacts/{{CONTACT_ID}} \
              -H 'Authorization: Bearer {{TOKEN}}' \
              -H 'Content-Type: application/json' \
            }'
        - lang: JavaScript
          source: |
            var request = require("request");
            var options = { method: 'DELETE',
              url: 'https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/contacts/{{CONTACT_ID}}',
              headers: 
               { 'Authorization': 'Bearer {{TOKEN}}',
                 'Content-Type': 'application/json' } };
            
            request(options, function (error, response, body) {
              if (error) throw new Error(error);
            
              console.log(body);
            });

        - lang: PHP
          source: |
            <?php
              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/contacts/{{CONTACT_ID}}');
              $request->setMethod(HTTP_METH_DELETE);
              
              $request->setHeaders(array(
                'Authorization' => 'Bearer {{TOKEN}}',
                'Content-Type' => 'application/json'
              ));
              
              $request->setBody('{
                "firstName": "Chris",
                "lastName": "Thomson",
                "mobile": {
                  "number": "+1234567890",
                  "country": "US"
                }
              }');
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }
        
        
  /v1/accounts/{accountId}/messages:
    get:
      tags:
      - messages
      summary: Fetch messages
      operationId: messages.fetchAll
      parameters:
      - $ref: '#/components/parameters/accountId'
      - $ref: '#/components/parameters/offset'
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/contactIdFilter'
      - $ref: '#/components/parameters/conversationIdFilter'
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema: 
                $ref: '#/components/schemas/MessagesResponse'
      security:
      - sakari_auth: []
      x-code-samples:
        - lang: CURL
          source: |
            curl -X GET \
              https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/messages \
              -H 'Authorization: Bearer {{TOKEN}}'
        - lang: JavaScript
          source: |
            var settings = {
              "async": true,
              "crossDomain": true,
              "url": "https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/messages",
              "method": "GET",
              "headers": {
                "Authorization": "Bearer {{TOKEN}}"
              }
            }
            
            $.ajax(settings).done(function (response) {
              console.log(response);
            });
        - lang: PHP
          source: |
            <?php
              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/messages');
              $request->setMethod(HTTP_METH_GET);
              
              $request->setHeaders(array(
                'Authorization' => 'Bearer {{TOKEN}}'
              ));
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }
    post:
      tags:
      - messages
      summary: Send Messages
      operationId: messages.send
      parameters:
      - $ref: '#/components/parameters/accountId'
      requestBody:
        content:
          application/json:
            schema: 
              $ref: '#/components/schemas/SendMessagesRequest'
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema: 
                $ref: '#/components/schemas/SendMessagesResponse'
      security:
      - sakari_auth: []
      x-code-samples:
        - lang: CURL
          source: |
            curl -X POST \
              https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/messages \
              -H 'Accept: application/json' \
              -H 'Authorization: Bearer {{TOKEN}}' \
              -H 'Content-Type: application/json' \
              -d '{
              "contacts": [{
                "mobile": {
                  "number": "+1234567890",
                  "country": "US"
                }
              }],
              "template": "Congratulations! You just sent your first message"
            } '
        - lang: JavaScript
          source: |
            var request = require("request");
            var options = { method: 'POST',
              url: 'https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/messages',
              headers: 
               { 'Authorization': 'Bearer {{TOKEN}}',
                 Accept: 'application/json',
                 'Content-Type': 'application/json' },
              body: 
               { contacts: [ { mobile: { number: '+1234567890', country: 'US' } } ],
                 template: 'Congratulations! You just sent your first message' },
              json: true };
            
            request(options, function (error, response, body) {
              if (error) throw new Error(error);
            
              console.log(body);
            });

        - lang: PHP
          source: |
            <?php
              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/messages');
              $request->setMethod(HTTP_METH_POST);
              
              $request->setHeaders(array(
                'Authorization' => 'Bearer {{TOKEN}}',
                'Accept' => 'application/json',
                'Content-Type' => 'application/json'
              ));
              
              $request->setBody('{
                "contacts": [{
                  "mobile": {
                    "number": "+1234567890",
                    "country": "US"
                  }
                }],
                "template": "Congratulations! You just sent your first message"
              } ');
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }
    
  /v1/accounts/{accountId}/messages/{messageId}:
    get:
      tags:
      - messages
      summary: Fetch message by id
      description: Returns a single messag
      operationId: messages.fetch
      parameters:
      - $ref: '#/components/parameters/accountId'
      - name: messageId
        in: path
        description: ID of message to return
        required: true
        schema:
          type: string
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema: 
                $ref: '#/components/schemas/MessageResponse'
      security:
      - sakari_auth: []
      x-code-samples:
        - lang: CURL
          source: |
            curl -X GET \
              https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/messages/{{MESSAGE_ID}} \
              -H 'Authorization: Bearer {{TOKEN}}'
        - lang: JavaScript
          source: |
            var request = require("request");
            var options = { method: 'GET',
              url: 'https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/messages/{{MESSAGE_ID}}',
              headers: 
               { 'Authorization': 'Bearer {{TOKEN}}' } };
            
            request(options, function (error, response, body) {
              if (error) throw new Error(error);
            
              console.log(body);
            });

        - lang: PHP
          source: |
            <?php
              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/messages/{{MESSAGE_ID}}');
              $request->setMethod(HTTP_METH_GET);
              
              $request->setHeaders(array(
                'Authorization' => 'Bearer {{TOKEN}}'
              ));
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }
  
  
  
  /v1/accounts/{accountId}/templates:
    get:
      tags:
      - templates
      summary: Fetch templates
      operationId: templates.fetchAll
      parameters:
      - $ref: '#/components/parameters/accountId'
      - $ref: '#/components/parameters/offset'
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/nameFilter'
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TemplatesResponse'
        4XX:
          description: invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        5XX:
          description: invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - sakari_auth: []
      x-code-samples:
        - lang: CURL
          source: |
            curl -X GET \
              https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/templates \
              -H 'Authorization: Bearer {{TOKEN}}'
        - lang: JavaScript
          source: |
            var request = require("request");
            var options = { method: 'GET',
              url: 'https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/templates',
              headers: 
               { 'Authorization': 'Bearer {{TOKEN}}' } };
            
            request(options, function (error, response, body) {
              if (error) throw new Error(error);
            
              console.log(body);
            });

        - lang: PHP
          source: |
            <?php
              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/templates');
              $request->setMethod(HTTP_METH_GET);
              
              $request->setHeaders(array(
                'Authorization' => 'Bearer {{TOKEN}}'
              ));
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }
      
    post:
      tags:
      - templates
      summary: Create template
      operationId: templates.create
      parameters:
      - $ref: '#/components/parameters/accountId'
      requestBody:
        content:
          application/json:
            schema: 
              $ref: '#/components/schemas/TemplateRequest'
      responses:
        201:
          description: successful operation
          content:
            application/json:
              schema: 
                $ref: '#/components/schemas/TemplatesResponse'
      security:
      - sakari_auth: []
      x-code-samples:
        - lang: CURL
          source: |
            curl -X POST \
              https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/templates \
              -H 'Authorization: Bearer {{TOKEN}}' \
              -H 'Content-Type: application/json' \
              -d '{
              "name": "Test Template",
              "template": "Hi {{ firstName }}, Welcome to Sakari!",
              "type": "SMS"
            }'
        - lang: JavaScript
          source: |
            var request = require("request");
            var options = { method: 'POST',
              url: 'https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/templates',
              headers: 
               { 'Content-Type': 'application/json' },
              body: 
               { name: 'Test Template',
                 template: 'Hi {{ firstName }}, Welcome to Sakari!',
                 type: 'SMS' },
              json: true };
            
            request(options, function (error, response, body) {
              if (error) throw new Error(error);
            
              console.log(body);
            });

        - lang: PHP
          source: |
            <?php
              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/templates');
              $request->setMethod(HTTP_METH_POST);
              
              $request->setHeaders(array(
                'Authorization' => 'Bearer {{TOKEN}}',
                'Content-Type' => 'application/json'
              ));
              
              $request->setBody('{
                "name": "Test Template",
                "template": "Hi {{ firstName }}, Welcome to Sakari!",
                "type": "SMS"
              }');
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }
      
  /v1/accounts/{accountId}/templates/{templateId}:
    get:
      tags:
      - templates
      summary: Fetch template by ID
      operationId: templates.fetch
      parameters:
      - $ref: '#/components/parameters/accountId'
      - name: templateId
        in: path
        description: ID of template to return
        required: true
        schema:
          type: string
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema: 
                $ref: '#/components/schemas/TemplateResponse'
      security:
      - sakari_auth: []
      x-code-samples:
        - lang: CURL
          source: |
            curl -X GET \
              https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/templates/{{TEMPLATE_ID}} \
              -H 'Authorization: Bearer {{TOKEN}}'
        - lang: JavaScript
          source: |
            var request = require("request");
            var options = { method: 'GET',
              url: 'https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/templates/{{TEMPLATE_ID}}',
              headers: 
               { Authorization: 'Bearer {{TOKEN}}' } };
            
            request(options, function (error, response, body) {
              if (error) throw new Error(error);
            
              console.log(body);
            });

        - lang: PHP
          source: |
            <?php
              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/templates/{{TEMPLATE_ID}}');
              $request->setMethod(HTTP_METH_GET);
              
              $request->setHeaders(array(
                'Authorization' => 'Bearer {{TOKEN}}'
              ));
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }
    put:
      tags:
      - templates
      summary: Updates a template
      operationId: templates.update
      parameters:
      - $ref: '#/components/parameters/accountId'
      - name: templateId
        in: path
        description: ID of template
        required: true
        schema:
          type: string
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema: 
                $ref: '#/components/schemas/TemplateResponse'
      security:
      - sakari_auth: []
      x-code-samples:
        - lang: CURL
          source: |
            curl -X PUT \
              https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/templates/{{TEMPLATE_ID}} \
              -H 'Authorization: Bearer {{TOKEN}}' \
              -H 'Content-Type: application/json' \
              -d '{
              "name": "Test Template",
              "template": "Hi {{ firstName }}, Welcome to Sakari!",
              "type": "SMS"
            }'
        - lang: JavaScript
          source: |
            var request = require("request");

            var options = { method: 'PUT',
              url: 'https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/templates/{{TEMPLATE_ID}}',
              headers: 
               { Authorization: 'Bearer {{TOKEN}}',
                 'Content-Type': 'application/json' },
              body: 
               { name: 'Test Template',
                 template: 'Hi {{ firstName }}, Welcome to Sakari!',
                 type: 'SMS' },
              json: true };
            
            request(options, function (error, response, body) {
              if (error) throw new Error(error);
            
              console.log(body);
            });

        - lang: PHP
          source: |
            <?php
              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/templates/{{TEMPLATE_ID}}');
              $request->setMethod(HTTP_METH_PUT);
              
              $request->setHeaders(array(
                'Authorization' => 'Bearer {{TOKEN}}',
                'Content-Type' => 'application/json'
              ));
              
              $request->setBody('{
                "name": "Test Template",
                "template": "Hi {{ firstName }}, Welcome to Sakari!",
                "type": "SMS"
              }');
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }
    delete:
      tags:
      - templates
      summary: Deletes a template
      operationId: templates.remove
      parameters:
      - $ref: '#/components/parameters/accountId'
      - name: templateId
        in: path
        description: Template id to delete
        required: true
        schema:
          type: string
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema: 
                type: object
                properties:
                  success:
                    type: boolean
      security:
      - sakari_auth: []
      x-code-samples:
        - lang: CURL
          source: |
            curl -X DELETE \
              https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/templates/{{TEMPLATE_ID}} \
              -H 'Authorization: Bearer {{TOKEN}}'
        - lang: JavaScript
          source: |
            var request = require("request");

            var options = { method: 'DELETE',
              url: 'https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/templates/{{TEMPLATE_ID}}',
              headers: 
               { Authorization: 'Bearer {{TOKEN}}' } };
            
            request(options, function (error, response, body) {
              if (error) throw new Error(error);
            
              console.log(body);
            });

        - lang: PHP
          source: |
            <?php
              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/templates/{{TEMPLATE_ID}}');
              $request->setMethod(HTTP_METH_DELETE);
              
              $request->setHeaders(array(
                'Authorization' => 'Bearer {{TOKEN}}'
              ));
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }
        
        
  /v1/accounts/{accountId}/campaigns:
    get:
      tags:
      - campaigns
      summary: Fetch campaigns
      operationId: campaigns.fetchAll
      parameters:
      - $ref: '#/components/parameters/accountId'
      - $ref: '#/components/parameters/offset'
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/nameFilter'
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CampaignsResponse'
        4XX:
          description: invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        5XX:
          description: invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - sakari_auth: []
      x-code-samples:
        - lang: CURL
          source: |
            curl -X GET \
              https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/campaigns \
              -H 'Authorization: Bearer {{TOKEN}}'
        - lang: JavaScript
          source: |
            var request = require("request");
            var options = { method: 'GET',
              url: 'https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/campaigns',
              headers: 
               { Authorization: 'Bearer {{TOKEN}}' } };
            
            request(options, function (error, response, body) {
              if (error) throw new Error(error);
            
              console.log(body);
            });

        - lang: PHP
          source: |
            <?php
              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/campaigns');
              $request->setMethod(HTTP_METH_GET);
              
              $request->setHeaders(array(
                'Authorization' => 'Bearer {{TOKEN}}'
              ));
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }
      
    post:
      tags:
      - campaigns
      summary: Create campaign
      operationId: campaigns.create
      parameters:
      - $ref: '#/components/parameters/accountId'
      requestBody:
        content:
          application/json:
            schema: 
              $ref: '#/components/schemas/CampaignRequest'
      responses:
        201:
          description: successful operation
          content:
            application/json:
              schema: 
                $ref: '#/components/schemas/CampaignResponse'
      security:
      - sakari_auth: []
      x-code-samples:
        - lang: CURL
          source: |
            curl -X POST \
              https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/campaigns \
              -H 'Authorization: Bearer {{TOKEN}}' \
              -H 'Content-Type: application/json' \
              -d '{
              "name": "Marketing Campaign",
              "trigger": {
                "code":"M"
              },
              "template":"Hi {{{contact.firstName}}}",
              "reporting":{"when":"NoReport"}
            }'
        - lang: JavaScript
          source: |
            var request = require("request");
            var options = { method: 'POST',
              url: 'https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/campaigns',
              headers: 
               { Authorization: 'Bearer {{TOKEN}}',
                 'Content-Type': 'application/json' },
              body: 
               { name: 'Marketing Campaign',
                 trigger: { code: 'M' },
                 template: 'Hi {{{contact.firstName}}}',
                 reporting: { when: 'NoReport' } },
              json: true };
            
            request(options, function (error, response, body) {
              if (error) throw new Error(error);
            
              console.log(body);
            });

        - lang: PHP
          source: |
            <?php
              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/campaigns');
              $request->setMethod(HTTP_METH_POST);
              
              $request->setHeaders(array(
                'Authorization' => 'Bearer {{TOKEN}}',
                'Content-Type' => 'application/json'
              ));
              
              $request->setBody('{
                "name": "Marketing Campaign",
                "trigger": {
                  "code":"M"
                },
                "template":"Hi {{{contact.firstName}}}",
                "reporting":{"when":"NoReport"}
              }');
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }
      
  /v1/accounts/{accountId}/campaigns/{campaignId}:
    get:
      tags:
      - campaigns
      summary: Fetch campaign by ID
      operationId: campaigns.fetch
      parameters:
      - $ref: '#/components/parameters/accountId'
      - name: campaignId
        in: path
        description: ID of campaign to return
        required: true
        schema:
          type: string
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema: 
                $ref: '#/components/schemas/CampaignResponse'
      security:
      - sakari_auth: []
      x-code-samples:
        - lang: CURL
          source: |
            curl -X GET \
              https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/campaigns/{{CAMPAIGN_ID}} \
              -H 'Authorization: Bearer {{TOKEN}}'
        - lang: JavaScript
          source: |
            var request = require("request");
            var options = { method: 'GET',
              url: 'https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/campaigns/{{CAMPAIGN_ID}}',
              headers: 
               { Authorization: 'Bearer {{TOKEN}}' } };
            
            request(options, function (error, response, body) {
              if (error) throw new Error(error);
            
              console.log(body);
            });

        - lang: PHP
          source: |
            <?php
              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/campaigns/{{CAMPAIGN_ID}}');
              $request->setMethod(HTTP_METH_GET);
              
              $request->setHeaders(array(
                'Authorization' => 'Bearer {{TOKEN}}'
              ));
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }
    put:
      tags:
      - campaigns
      summary: Updates a campaign
      operationId: campaigns.update
      parameters:
      - $ref: '#/components/parameters/accountId'
      - name: campaignId
        in: path
        description: ID of campaign
        required: true
        schema:
          type: string
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema: 
                $ref: '#/components/schemas/CampaignResponse'
      security:
      - sakari_auth: []
      x-code-samples:
        - lang: CURL
          source: |
            curl -X POST \
              https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/campaigns/{{CAMPAIGN_ID}} \
              -H 'Authorization: Bearer {{TOKEN}}' \
              -H 'Content-Type: application/json' \
              -d '{
              "name": "Marketing Campaign",
              "trigger": {
                "code":"M"
              },
              "template":"Hi {{{contact.firstName}}}",
              "reporting":{"when":"NoReport"}
            }'
        - lang: JavaScript
          source: |
            var request = require("request");
            var options = { method: 'POST',
              url: 'https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/campaigns/{{CAMPAIGN_ID}}',
              headers: 
               { Authorization: 'Bearer {{TOKEN}}',
                 'Content-Type': 'application/json' },
              body: 
               { name: 'Marketing Campaign',
                 trigger: { code: 'M' },
                 template: 'Hi {{{contact.firstName}}}',
                 reporting: { when: 'NoReport' } },
              json: true };
            
            request(options, function (error, response, body) {
              if (error) throw new Error(error);
            
              console.log(body);
            });

        - lang: PHP
          source: |
            <?php
              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/campaigns/{{CAMPAIGN_ID}}');
              $request->setMethod(HTTP_METH_POST);
              
              $request->setHeaders(array(
                'Authorization' => 'Bearer {{TOKEN}}',
                'Content-Type' => 'application/json'
              ));
              
              $request->setBody('{
                "name": "Marketing Campaign",
                "trigger": {
                  "code":"M"
                },
                "template":"Hi {{{contact.firstName}}}",
                "reporting":{"when":"NoReport"}
              }');
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }
    delete:
      tags:
      - campaigns
      summary: Deletes a campaign
      operationId: campaigns.remove
      parameters:
      - $ref: '#/components/parameters/accountId'
      - name: campaignId
        in: path
        description: Campaign id to delete
        required: true
        schema:
          type: string
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema: 
                type: object
                properties:
                  success:
                    type: boolean
      security:
      - sakari_auth: []
      x-code-samples:
        - lang: CURL
          source: |
            curl -X DELETE \
              https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/campaigns/{{CAMPAIGN_ID}} \
              -H 'Authorization: Bearer {{TOKEN}}'
        - lang: JavaScript
          source: |
            var request = require("request");
            var options = { method: 'DELETE',
              url: 'https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/campaigns/{{CAMPAIGN_ID}}',
              headers: 
               { Authorization: 'Bearer {{TOKEN}}' } };
            
            request(options, function (error, response, body) {
              if (error) throw new Error(error);
            
              console.log(body);
            });

        - lang: PHP
          source: |
            <?php
              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/campaigns/{{CAMPAIGN_ID}}');
              $request->setMethod(HTTP_METH_DELETE);
              
              $request->setHeaders(array(
                'Authorization' => 'Bearer {{TOKEN}}'
              ));
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }
        
    
  /v1/accounts/{accountId}/conversations:
    get:
      tags:
      - conversations
      summary: Fetch conversations
      operationId: conversations.fetchAll
      parameters:
      - $ref: '#/components/parameters/accountId'
      - $ref: '#/components/parameters/offset'
      - $ref: '#/components/parameters/limit'
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConversationsResponse'
        4XX:
          description: invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        5XX:
          description: invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - sakari_auth: []
      x-code-samples:
        - lang: CURL
          source: |
            curl -X GET \
              https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/conversations \
              -H 'Authorization: Bearer {{TOKEN}}'
        - lang: JavaScript
          source: |
            var request = require("request");
            var options = { method: 'GET',
              url: 'https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/conversations',
              headers: 
               { Authorization: 'Bearer {{TOKEN}}' } };
            
            request(options, function (error, response, body) {
              if (error) throw new Error(error);
            
              console.log(body);
            });

        - lang: PHP
          source: |
            <?php
              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/conversations');
              $request->setMethod(HTTP_METH_GET);
              
              $request->setHeaders(array(
                'Authorization' => 'Bearer {{TOKEN}}'
              ));
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }
      
      
  /v1/accounts/{accountId}/conversations/{conversationId}:
    get:
      tags:
      - conversations
      summary: Fetch conversation by ID
      operationId: conversations.fetch
      parameters:
      - $ref: '#/components/parameters/accountId'
      - name: conversationId
        in: path
        description: ID of template to return
        required: true
        schema:
          type: string
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema: 
                $ref: '#/components/schemas/ConversationResponse'
      security:
      - sakari_auth: []
      x-code-samples:
        - lang: CURL
          source: |
            curl -X GET \
              https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/conversations/{{CONVERSATION_ID}} \
              -H 'Authorization: Bearer {{TOKEN}}'
        - lang: JavaScript
          source: |
            var request = require("request");
            var options = { method: 'GET',
              url: 'https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/conversations/{{CONVERSATION_ID}}',
              headers: 
               { Authorization: 'Bearer {{TOKEN}}' } };
            
            request(options, function (error, response, body) {
              if (error) throw new Error(error);
            
              console.log(body);
            });

        - lang: PHP
          source: |
            <?php
              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/conversations/{{CONVERSATION_ID}}');
              $request->setMethod(HTTP_METH_GET);
              
              $request->setHeaders(array(
                'Authorization' => 'Bearer {{TOKEN}}'
              ));
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }
      
  /v1/accounts/{accountId}/conversations/{conversationId}/close:
    put:
      tags:
      - conversations
      summary: Closes a conversation
      operationId: conversations.close
      parameters:
      - $ref: '#/components/parameters/accountId'
      - name: conversationId
        in: path
        description: ID of conversation
        required: true
        schema:
          type: string
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema: 
                $ref: '#/components/schemas/ConversationResponse'
      security:
      - sakari_auth: []
      x-code-samples:
        - lang: CURL
          source: |
            curl -X GET \
              https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/conversations/{{CONVERSATION_ID}}/close \
              -H 'Authorization: Bearer {{TOKEN}}'
        - lang: JavaScript
          source: |
            var request = require("request");
            var options = { method: 'GET',
              url: 'https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/conversations/{{CONVERSATION_ID}}/close',
              headers: 
               { Authorization: 'Bearer {{TOKEN}}' } };
            
            request(options, function (error, response, body) {
              if (error) throw new Error(error);
            
              console.log(body);
            });

        - lang: PHP
          source: |
            <?php
              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/conversations/{{CONVERSATION_ID}}/close');
              $request->setMethod(HTTP_METH_PUT);
              
              $request->setHeaders(array(
                'Authorization' => 'Bearer {{TOKEN}}',
                'Content-Type' => 'application/json'
              ));
              
              $request->setBody('{
                "name": "Test Template",
                "template": "Hi {{ firstName }}, Welcome to Sakari!",
                "type": "SMS"
              }');
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }
        

  /v1/tools/sharefile:
    post:
      tags:
      - tools
      summary: Share file - use to host a file and generate a short link to be used directly in a message or as a link to media for a MMS
      operationId: tools.shareFile
      requestBody:
        required: true
        content:
          application/octet-stream:
            schema:
              type: string
              format: binary
          multipart/form-data:
            schema:
              type: object
              properties:
                media:  
                  type: string
                  format: binary
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ShareFileResponse'
        4XX:
          description: invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        5XX:
          description: invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - sakari_auth: []
      
      
      
         
  /v1/accounts/{accountId}/webhooks:
    get:
      tags:
      - webhooks
      summary: Fetch active webhooks
      description: When messages are acknowledge by carriers, a notification is sent to the specified URL
      operationId: webhooks.fetchAll
      parameters:
      - $ref: '#/components/parameters/accountId'
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema: 
                $ref: '#/components/schemas/WebhooksResponse'
      security:
      - sakari_auth: []
      x-code-samples:
        - lang: CURL
          source: |
            curl -X GET \
              https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/webhooks \
              -H 'Authorization: Bearer {{TOKEN}}' \
              -d '{
              "url": "https://requestbin.io"
            }'
        - lang: JavaScript
          source: |
            var settings = {
              "async": true,
              "crossDomain": true,
              "url": "https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/webhooks",
              "method": "GET",
              "headers": {
                "Authorization": "Bearer {{TOKEN}}"
              },
              "data": "{\n\t\"url\": \"https://requestbin.io\"\n}"
            }
            
            $.ajax(settings).done(function (response) {
              console.log(response);
            });
        - lang: PHP
          source: |
            <?php
              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/webhooks');
              $request->setMethod(HTTP_METH_GET);
              
              $request->setHeaders(array(
                'Authorization' => 'Bearer {{TOKEN}}'
              ));
              
              $request->setBody('{
                "url": "https://requestbin.io"
              }');
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }
    post:
      tags:
      - webhooks
      summary: Subscribe to message events
      description: When messages are acknowledge by carriers, a notification is sent to the specified URL
      operationId: webhooks.subscribe
      parameters:
      - $ref: '#/components/parameters/accountId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                url: # Callback URL
                  type: string
                  format: uri
                  example: https://myserver.com/send/callback/here
                eventTypes:
                  type: array
                  items: 
                    type: string
                    enum: ['contact-created','contact-updated','contact-removed','message-received','message-sent','message-status','conversation-started','contact-opt-out','contact-opt-in','list-opt-out','list-opt-in']
              required:
                - callbackUrl
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema: 
                $ref: '#/components/schemas/WebhookResponse'
      security:
      - sakari_auth: []
      x-code-samples:
        - lang: CURL
          source: |
            curl -X POST \
              https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/webhooks \
              -H 'Authorization: Bearer {{TOKEN}}' \
              -H 'Content-Type: application/json' \
              -d '{
              "url": "https://requestbin.io",
              "eventTypes": ["message-received"]
            }'
        - lang: JavaScript
          source: |
            var request = require("request");
            var options = { method: 'POST',
              url: 'https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/webhooks',
              headers: 
               { Authorization: 'Bearer {{TOKEN}}',
                 'Content-Type': 'application/json' },
              body: { url: 'https://requestbin.io', eventTypes: [ 'message-received' ] },
              json: true };
            
            request(options, function (error, response, body) {
              if (error) throw new Error(error);
            
              console.log(body);
            });

        - lang: PHP
          source: |
            <?php
              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/webhooks');
              $request->setMethod(HTTP_METH_POST);
              
              $request->setHeaders(array(
                'Authorization' => 'Bearer {{TOKEN}}',
                'Content-Type' => 'application/json'
              ));
              
              $request->setBody('{
                "url": "https://requestbin.io",
                "eventTypes": ["message-received"]
              }');
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }
                
  /v1/accounts/{accountId}/webhooks/{url}:
    delete:
      tags:
      - webhooks
      summary: Unsubscribe to message events
      description: Delete subscription for receiving notifications
      operationId: webhooks.unsubscribe
      parameters:
      - $ref: '#/components/parameters/accountId'
      - name: url
        in: path
        description: Account to apply operations to
        required: true
        schema: 
          type: string
      responses:
        204:
          description: successful operation
      security:
      - sakari_auth: []
      x-code-samples:
        - lang: CURL
          source: |
            curl -X DELETE \
              https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/webhooks/{{URL_ENCODED CALLBACK_URL}} \
              -H 'Authorization: Bearer {{TOKEN}}'
        - lang: JavaScript
          source: |
            var request = require("request");
            var options = { method: 'DELETE',
              url: 'https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/webhooks/{{URL_ENCODED CALLBACK_URL}}',
              headers: 
               { Authorization: 'Bearer {{TOKEN}}' };
            
            request(options, function (error, response, body) {
              if (error) throw new Error(error);
            
              console.log(body);
            });

        - lang: PHP
          source: |
            <?php
              $request = new HttpRequest();
              $request->setUrl('https://api.sakari.io/v1/accounts/{{ACCOUNT_ID}}/webhooks/{{URL_ENCODED CALLBACK_URL}}');
              $request->setMethod(HTTP_METH_DELETE);
              
              $request->setHeaders(array(
                'Authorization' => 'Bearer {{TOKEN}}'
              ));
              
              try {
                $response = $request->send();
              
                echo $response->getBody();
              } catch (HttpException $ex) {
                echo $ex;
              }
          
      callbacks:
        event: # Event name
          '{$request.body#/callbackUrl}': # The callback URL, Refers to the passed URL
            post:
              requestBody: # Contents of the callback message
                required: true
                content:
                  application/json:
                    schema:
                      $ref: '#/components/schemas/Event'
              responses: # Expected responses to the callback message
                '200':
                  description: Your server returns this code if it accepts the callback

      
externalDocs:
  description: Find out more about Sakari
  url: 'https://sakari.io'
  
components:
  
  parameters:
    accountId:
      name: accountId
      in: path
      description: Account to apply operations to
      required: true
      schema: 
        type: string
        
    offset:
      name: offset
      in: query
      description: Results to skip when paginating through a result set
      required: false
      schema: 
        type: integer
        format: int64
        minimum: 0
    limit:
      name: limit
      in: query
      description: Maximum number of results to return
      required: false
      schema: 
        type: integer
        format: int64
        minimum: 1
        maximum: 100
    
    contactIdFilter:
      name: contactId
      in: query
      description: ID of contact
      required: false
      schema:
        type: string
    firstNameFilter:
      name: firstName
      in: query
      description: Filter by first name or part of
      required: false
      schema: 
        type: string
    lastNameFilter:
      name: lastName
      in: query
      description: Filter by last name or part of
      required: false
      schema:
        type: string
    nameFilter:
      name: name
      in: query
      description: Filter by name or part of
      required: false
      schema:
        type: string
    mobileFilter:
      name: mobile
      in: query
      description: Filter by mobile or part of
      required: false
      schema:
        type: string
    emailFilter:
      name: email
      in: query
      description: Filter by email or part of
      required: false
      schema:
        type: string
    tagsFilter:
      name: tags
      in: query
      description: Filter by tag(s)
      required: false
      schema:
        type: string
    
    conversationIdFilter:
      name: conversationId
      in: query
      description: ID of conversation
      required: false
      schema:
        type: string
        
    firstName:
      name: firstName
      in: query
      description: First name of contact
      required: false
      schema: 
        type: string
    lastName:
      name: lastName
      in: query
      description: Last name of contact
      required: false
      schema:
        type: string
    mobile:
      name: mobile
      in: query
      description: Mobile of contact
      required: false
      schema:
        type: string
    email:
      name: email
      in: query
      description: Email of contact
      required: false
      schema:
        type: string
    tags:
      name: tags
      in: query
      description: Tag of contact
      required: false
      schema:
        type: string
        
    # eventType:
    #   type: string
    #   example: message
    #   enum:
    #   - account
    #   - message
    
  schemas:
    TokenRequest:
      type: object
      properties:
        grant_type: 
          type: string
          example: client_credentials
        client_id:
          type: string
          example: 00000000-0000-0000-0000-00000000000
        client_secret:
          type: string
          example: 00000000-0000-0000-0000-00000000000
  
    TokenResponse:
      type: object
      properties:
        access_token:
          type: string
        token_type:
          type: string
      
    AccountId:
      type: string
        
    EventType:
      type: string
      example: message
      enum:
      - account
      - messageStatus
      - messageIncoming

    Updated:
      type: object
      properties:
        at:
          type: string
          format: date-time
        by:
          type: object
          properties:
            id:
              type: string
            firstName: 
              type: string
              example: 'Joe'
            lastName: 
              type: string
              example: 'Bloggs'
          
    Error:
      type: object
      properties:
        code:
          type: string
          example: 'CONT-010'
        description:
          type: string
          example: 'Contact has requested no further communication'
          
    PhoneNumber:
      type: object
      properties:
        country:
          type: string
        number: 
          type: string
        active:
          type: boolean
           
    ContactIdentifiers:
      type: object
      properties:
        id:
          type: string
        email:
          type: string
          example: chris@sakari.io
        firstName:
          type: string
          example: Chris
        lastName:
          type: string
          example: Bloggs
        mobile:
          type: object
          properties:
            country:
              type: string
            number:
              type: string
              example: 123-456-7890
         
    ContactRequest:
      allOf:     # Combines the BasicErrorModel and the inline model
        - $ref: '#/components/schemas/ContactIdentifiers'
        - type: object
          properties:
            tags:
              type: array
              items:
                $ref: '#/components/schemas/Tag'
            attributes:
              type: object
        
    Contact:
      allOf:     # Combines the BasicErrorModel and the inline model
        - $ref: '#/components/schemas/ContactRequest'
        - type: object
          properties:
            valid:
              type: boolean
            error: 
              $ref: '#/components/schemas/Error'
            created:
              $ref: '#/components/schemas/Updated'
            updated:
              $ref: '#/components/schemas/Updated'
        
    Tag:
      type: object
      properties:
        tag:
          type: string
        visible:
          type: boolean
         
    ErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          default: false
          example: false
        error:
          type: object
          properties:
            code:
              type: string
              example: 'CONV-001'
            message: 
              type: string
              example: 'Invalid conversation id'
    
    PaginatedResponse:
      type: object
      properties:
        success:
          type: boolean
        pagination:
          type: object
          properties:
            totalCount:
              type: integer
            limit: 
              type: integer
            offset:
              type: integer
        error:
          type: object
          properties:
            code:
              type: string
            message: 
              type: string
              
    ContactsResponse:
      allOf:     # Combines the BasicErrorModel and the inline model
        - $ref: '#/components/schemas/PaginatedResponse'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/Contact'
            
    ContactResponse:
      type: object
      properties: 
        success: 
          type: boolean
          default: true
        data:
          $ref: '#/components/schemas/Contact'
           
    ContactUploadResponse:
      type: object
      properties:
        success: 
          type: boolean
          default: true
        data:
          type: object
          properties:
            contacts:
              type: array
              items: 
                $ref: '#/components/schemas/Contact'
              description: 'Uploaded contacts'
            errors:
              type: array
              items: 
                $ref: '#/components/schemas/Contact'
              description: 'Contacts that failed validation'
            #filters:
            #  type: '#/components/schemas/ContactFilter'
            submitted:
              type: integer #TODO review
            inserted:
              type: integer #TODO review
            updated:
              type: integer #TODO review
            success:
              type: integer #TODO review
  
    SendMessagesRequest:
      type: object
      properties:
        #TODO consider using 'oneOf'
        conversations:
          type: array
          description: List of conversation ids to send messages to
          items: 
            type: string
        contacts:
          type: array
          items:
            $ref: '#/components/schemas/ContactRequest'
        filters:
          type: object
          properties:
            tags:
              type: array
              items: 
                type: string
            attributes:
              type: array
              items: 
                type: object
        phoneNumberFilter: 
          type: object
          properties:
            group: 
              type: object
              properties:
                id: 
                  type: string
        template:
          type: string
        type:
          type: string
          enum:
          - SMS
          - MMS
        media:
          type: array
          description: List of media objects to attach to message
          items: 
            type: object
            properties:
              url:
                type: string
        conversationStrategy:
          type: string
          # TODO enum
      
    SendMessagesResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            messages:
              type: array
              items:
                $ref: '#/components/schemas/Message'
            jobId:
              type: string
            requested:
              type: integer
            valid:
              type: integer
            invalid:
              type: array
              items:
                $ref: '#/components/schemas/Contact'
            estimatedPrice:
              type: number
              format: double
      
    Message:
      type: object
      properties:
        id:
          type: string
        contact:
          $ref: '#/components/schemas/ContactIdentifiers'
        conversation:
          type: object
          properties:
            id:
              type: string
        message:
          type: string
        template:
          type: string
        outgoing:
          type: boolean
        phoneNumber: 
          type: string
          example: '+1234567890'
        price:
          type: number
        segments:
          type: number
        read: 
          type: boolean
        status:
          type: string
          #TODO enum
        media:
          type: array
          description: List of media objects attached to message
          items: 
            type: object
            properties:
              url:
                type: string
              type:
                type: string
              filename:
                type: string
        error:
          $ref: '#/components/schemas/Error'
        created:
          $ref: '#/components/schemas/Updated'
        updated:
          $ref: '#/components/schemas/Updated'
        
    MessagesResponse:
      allOf:     # Combines the BasicErrorModel and the inline model
        - $ref: '#/components/schemas/PaginatedResponse'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/Message'
           
    MessageResponse:
      type: object
      properties:
        success:
          type: boolean
        data:
          $ref: '#/components/schemas/Message'
          
    TemplateRequest:
      type: object
      properties:
        name:
          type: string
        type:
          type: string
          example: SMS
          enum:
          - SMS
          - Web
        template:
          type: string
          example: Hi {{{firstName}}}. Grab 20% off today only at ABC Shoes
         
    Template:
      allOf:     # Combines the BasicErrorModel and the inline model
        - $ref: '#/components/schemas/TemplateRequest'
        - type: object
          properties:
            id:
              type: string

    TemplatesResponse:
      allOf:     # Combines the BasicErrorModel and the inline model
        - $ref: '#/components/schemas/PaginatedResponse'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/Template'
           
    TemplateResponse:
      type: object
      properties:
        success:
          type: boolean
        data:
          $ref: '#/components/schemas/Template'
          
    Conversation:
      type: object
      properties:
        id:
          type: string
        contact:
          $ref: '#/components/schemas/ContactIdentifiers'
        closed:
          type: boolean
        lastMessage:
          $ref: '#/components/schemas/Message'
        phoneNumber:
          $ref: '#/components/schemas/PhoneNumber'
        unread: 
          type: array
          items:
            type: string
        created:
          $ref: '#/components/schemas/Updated'
        updated:
          $ref: '#/components/schemas/Updated'
        
    ConversationsResponse:
      allOf:     # Combines the BasicErrorModel and the inline model
        - $ref: '#/components/schemas/PaginatedResponse'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/Conversation'
           
    ConversationResponse:
      type: object
      properties:
        success:
          type: boolean
        data:
          $ref: '#/components/schemas/Conversation'
          
    CampaignRequest:
      type: object
      properties:
        trigger:
          type: object
          properties:
            code:
              type: string
              description: >
                Campaign type specifies how it sources contacts and what event triggers its execution 
                Sort order
                  * `M` - Manual
                  * `S` - Scheduled
                  * `FU` - File Upload
              enum:
              - M
              - S
              - FU
        filters: 
          type: object
          properties: 
            contacts:
              type: array
              items:
                type: string
            tags:
              type: array
              items: 
                type: string
            attributes:
              type: array
              items: 
                type: string
        template:
          type: string
        
    AttributeFilter:
      type: object
      properties:
        name:
          type: string
        comparator:
          type: string
          enum:
          - '='
          - '<'
          - '<='
          - '>'
          - '>='
          - '!='
        value:
          type: string
          
    AccountEvent:
      type: object
      properties:
          type:
            $ref: '#/components/schemas/EventType'
          accountId:
            $ref: '#/components/schemas/AccountId'
            
    Campaign:
      type: object
      properties:
        id:
          type: string
          
    CampaignsResponse:
      allOf:     # Combines the BasicErrorModel and the inline model
        - $ref: '#/components/schemas/PaginatedResponse'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/Campaign'
           
    CampaignResponse:
      type: object
      properties:
        success:
          type: boolean
        data:
          $ref: '#/components/schemas/Campaign'
          
    ShareFileResponse:
      type: object
      properties:
        success:
          type: boolean
        data: 
          type: object
          properties:
            link:
              type: string
            expires:
              type: string
              format: date-time
          
          
    Webhook:
      type: object
      properties:
        url:
          type: string
        eventTypes: 
          type: array
          items:
            type: string
            enum:
            - message-received
            - message-status
            - message-sent
            - conversation-closed
            - contact-created
            - contact-updated
            - contact-removed
            
    WebhooksResponse:
      allOf:     # Combines the BasicErrorModel and the inline model
        - $ref: '#/components/schemas/PaginatedResponse'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/Webhook'
           
    WebhookResponse:
      type: object
      properties:
        success:
          type: boolean
        data:
          $ref: '#/components/schemas/Webhook'
          
            
    Event:
      type: object
      properties:
        eventId:
          type: string
        type:
          $ref: '#/components/schemas/EventType'
        accountId:
          $ref: '#/components/schemas/AccountId'
        data:
          oneOf:
            - $ref: '#/components/schemas/AccountEventPayload'
            - $ref: '#/components/schemas/MessageEventPayload'
            
    AccountEventPayload:
      type: object
      properties:
        balance:
          type: number
          format: double
         
    MessageEventPayload:
      type: object
      properties:
        contact:
          $ref: '#/components/schemas/ContactIdentifiers'
        message:
          type: string
        status:
          type: string
        error:
          type: string
         
  requestBodies:
    Contact:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ContactRequest'
      description: Pet object that needs to be added to the store
      required: true
    Contacts:
      content:
        application/json:
          schema:
            type: array
            items:
              $ref: '#/components/schemas/ContactRequest'
      description: List of contacts
      required: true
      
  securitySchemes:
    sakari_auth:
      type: oauth2
      flows:
        clientCredentials:
          tokenUrl: '/oauth2/token'
          scopes:
            'messages:send': Send messages