Kepla API

Batches

Batches allow you to run a series of requests in parallel. They're a great way to reduce latency between your integration and Kepla. There are two batches endpoints, one for all API endpoints which is synchronous and one for collections of records, which is asynchronous. We use batches in the client to implement all the bulk editing functionality.

Batches Overview

{
  "method": "GET",
String

The HTTP method required by the endpoint (GET, POST, PUT, DELETE)

  "url": "/activities",
String

The endpoint path to send to. This should be the URL in the docs, for example /activities not /v1/activities. Include any query parameters in this string.

  "body": {
  "body": { ... }
Object

(Optional) The JSON body to send with the request.

  }
}
{
  "response": {
  "response": { ... }
Object

The JSON response from the API

    "items": {
    "items": { ... }
Object
    }
  },
  "status": 200
Integer

The HTTP status code of the response

}

Create a Batch

Open in API Explorer
POST /batches

Send a set of requests to the API at once. These requests will be run in parallel, and their results returned in the response.

Example Request

Format:
curl --request POST \
  --url https://api.kepla.com/v1/batches \
  --header 'accept: application/json' \
  --header 'authorization: Bearer YOUR API KEY HERE' \
  --header 'content-type: application/json' \
  --data '{"requests":[{"method":"GET","url":"/activities","body":{}}]}'
require 'uri'
require 'net/http'

url = URI("https://api.kepla.com/v1/batches")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Post.new(url)
request["accept"] = 'application/json'
request["authorization"] = 'Bearer YOUR API KEY HERE'
request["content-type"] = 'application/json'
request.body = "{\"requests\":[{\"method\":\"GET\",\"url\":\"/activities\",\"body\":{}}]}"

response = http.request(request)
puts response.read_body
var http = require("https");

var options = {
  "method": "POST",
  "hostname": "api.kepla.com",
  "port": null,
  "path": "/v1/batches",
  "headers": {
    "accept": "application/json",
    "authorization": "Bearer YOUR API KEY HERE",
    "content-type": "application/json"
  }
};

var req = http.request(options, function (res) {
  var chunks = [];

  res.on("data", function (chunk) {
    chunks.push(chunk);
  });

  res.on("end", function () {
    var body = Buffer.concat(chunks);
    console.log(body.toString());
  });
});

req.write(JSON.stringify({ requests: [ { method: 'GET', url: '/activities', body: {} } ] }));
req.end();
import http.client

conn = http.client.HTTPSConnection("api.kepla.com")

payload = "{\"requests\":[{\"method\":\"GET\",\"url\":\"/activities\",\"body\":{}}]}"

headers = {
    'accept': "application/json",
    'authorization': "Bearer YOUR API KEY HERE",
    'content-type': "application/json"
    }

conn.request("POST", "/v1/batches", payload, headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
<?php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://api.kepla.com/v1/batches",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "{\"requests\":[{\"method\":\"GET\",\"url\":\"/activities\",\"body\":{}}]}",
  CURLOPT_HTTPHEADER => array(
    "accept: application/json",
    "authorization: Bearer YOUR API KEY HERE",
    "content-type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io/ioutil"
)

func main() {

	url := "https://api.kepla.com/v1/batches"

	payload := strings.NewReader("{\"requests\":[{\"method\":\"GET\",\"url\":\"/activities\",\"body\":{}}]}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("accept", "application/json")
	req.Header.Add("authorization", "Bearer YOUR API KEY HERE")
	req.Header.Add("content-type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}

Request Body

Name Type Required Description Example
payload Object Required
{
  requests: [
Array

An array or object of requests. If you send an object, the response will be returned under the same object key.

    {
    { ... }
Object

Default

      "method": "GET",
String

The HTTP method required by the endpoint (GET, POST, PUT, DELETE)

      "url": "/activities",
String

The endpoint path to send to. This should be the URL in the docs, for example /activities not /v1/activities. Include any query parameters in this string.

      "body": {
      "body": { ... }
Object

(Optional) The JSON body to send with the request.

      }
    }
  ]
}

Responses

200 Success

An array or object (same format as you sent) of all the JSON responses and status codes.

Batches Response
{
  "response": {
  "response": { ... }
Object

The JSON response from the API

    "items": {
    "items": { ... }
Object
    }
  },
  "status": 200
Integer

The HTTP status code of the response

}

Create a Collection Batch

Open in API Explorer
POST /collection-batches

Run a series of requests on an entire collection of records, transactions, activities or tasks (pretty much anything that has pagination). These requests are run sequentially and can reliably assume that a previous request has been completed. They are run in the background by the API, and can take a little while to complete depending on the size of the batch.

Example Request

Format:
curl --request POST \
  --url https://api.kepla.com/v1/collection-batches \
  --header 'accept: application/json' \
  --header 'authorization: Bearer YOUR API KEY HERE' \
  --header 'content-type: application/json' \
  --data '{"requests":[[{"method":"GET","url":"/activities","body":{}}]],"collection":{"method":"GET","url":"/types/3cfdd22a-8f80-4f5a-b22d-0f06a39dbebf/records","params":{},"body":{}}}'
require 'uri'
require 'net/http'

url = URI("https://api.kepla.com/v1/collection-batches")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Post.new(url)
request["accept"] = 'application/json'
request["authorization"] = 'Bearer YOUR API KEY HERE'
request["content-type"] = 'application/json'
request.body = "{\"requests\":[[{\"method\":\"GET\",\"url\":\"/activities\",\"body\":{}}]],\"collection\":{\"method\":\"GET\",\"url\":\"/types/3cfdd22a-8f80-4f5a-b22d-0f06a39dbebf/records\",\"params\":{},\"body\":{}}}"

response = http.request(request)
puts response.read_body
var http = require("https");

var options = {
  "method": "POST",
  "hostname": "api.kepla.com",
  "port": null,
  "path": "/v1/collection-batches",
  "headers": {
    "accept": "application/json",
    "authorization": "Bearer YOUR API KEY HERE",
    "content-type": "application/json"
  }
};

var req = http.request(options, function (res) {
  var chunks = [];

  res.on("data", function (chunk) {
    chunks.push(chunk);
  });

  res.on("end", function () {
    var body = Buffer.concat(chunks);
    console.log(body.toString());
  });
});

req.write(JSON.stringify({ requests: [ [ { method: 'GET', url: '/activities', body: {} } ] ],
  collection: 
   { method: 'GET',
     url: '/types/3cfdd22a-8f80-4f5a-b22d-0f06a39dbebf/records',
     params: {},
     body: {} } }));
req.end();
import http.client

conn = http.client.HTTPSConnection("api.kepla.com")

payload = "{\"requests\":[[{\"method\":\"GET\",\"url\":\"/activities\",\"body\":{}}]],\"collection\":{\"method\":\"GET\",\"url\":\"/types/3cfdd22a-8f80-4f5a-b22d-0f06a39dbebf/records\",\"params\":{},\"body\":{}}}"

headers = {
    'accept': "application/json",
    'authorization': "Bearer YOUR API KEY HERE",
    'content-type': "application/json"
    }

conn.request("POST", "/v1/collection-batches", payload, headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
<?php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://api.kepla.com/v1/collection-batches",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "{\"requests\":[[{\"method\":\"GET\",\"url\":\"/activities\",\"body\":{}}]],\"collection\":{\"method\":\"GET\",\"url\":\"/types/3cfdd22a-8f80-4f5a-b22d-0f06a39dbebf/records\",\"params\":{},\"body\":{}}}",
  CURLOPT_HTTPHEADER => array(
    "accept: application/json",
    "authorization: Bearer YOUR API KEY HERE",
    "content-type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io/ioutil"
)

func main() {

	url := "https://api.kepla.com/v1/collection-batches"

	payload := strings.NewReader("{\"requests\":[[{\"method\":\"GET\",\"url\":\"/activities\",\"body\":{}}]],\"collection\":{\"method\":\"GET\",\"url\":\"/types/3cfdd22a-8f80-4f5a-b22d-0f06a39dbebf/records\",\"params\":{},\"body\":{}}}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("accept", "application/json")
	req.Header.Add("authorization", "Bearer YOUR API KEY HERE")
	req.Header.Add("content-type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}

Request Body

Name Type Required Description Example
payload Object Required
{
  requests: [
Array

An array of requests to run on each item in the collection. You may include the string :id anywhere in the url or body of these requests. It will be replaced with the ID of the current object in the collection (for instance the current record ID to add an activity).

    {
    { ... }
Object

List

      "items": {
      "items": { ... }
Object
        "method": "GET",
String

The HTTP method required by the endpoint (GET, POST, PUT, DELETE)

        "url": "/activities",
String

The endpoint path to send to. This should be the URL in the docs, for example /activities not /v1/activities. Include any query parameters in this string.

        "body": {
        "body": { ... }
Object

(Optional) The JSON body to send with the request.

        }
      }
    }
  ]
  "collection": {
  "collection": { ... }
Object
    "method": "GET",
String

The method to request the collectio with. This would be GET unless you've used a POST method on a search endpoint.

    "url": "/types/3cfdd22a-8f80-4f5a-b22d-0f06a39dbebf/records",
String

The endpoint of the collection to loop through excluding the base URL or version.

    "params": {
    "params": { ... }
Object

An object of query parameters to send with the collection.

    },
    "body": {
    "body": { ... }
Object

The body to send with the collection (search endpoints only).

    }
  }
}

Responses

200 Success

This endpoint returns an operation object, it's the only time you get one using the public/documented API. You can request status updates on the operation by polling /operations/:operation where :operation is the ID returned in this response. That endpoint will show you if the batch has finished.

Batches Operation
{
  "type": "batches.processCollection",
String

System. The type of background operation being run.

  "data": {
  "data": { ... }
Object

A direct copy of the data sent to the API.

    "collection": {
    "collection": { ... }
Object
      "body": {
      "body": { ... }
Object
      },
      "method": "GET",
String
      "params": {
      "params": { ... }
Object
      },
      "url": "/types/3cfdd22a-8f80-4f5a-b22d-0f06a39dbebf/records"
String
    },
    requests: [
Array
      {
      { ... }
Object

Requests

        "body": {
        "body": { ... }
Object
        },
        "method": "GET",
String
        "url": "/activities"
String
      }
    ]
    "token": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhY2NvdW50IjoiNzczZmMwNTgtNzk5OC00OTA4LTkzNjAtZWY3MmMwOTc5MmQxIiwiaWF0IjoxNDcwNDY0MDIzfQ.u5vPY_2IOGh4XIQ5JAmlnDGra4xOQhVFEsGtfnXngiA"
String
  },
  "userId": "api",
String

Your user ID, which will generally be "api".

  "accountId": "04fe9a97-a579-43c5-bb1a-58ed29bf0a6a",
String (Uuid)

Account ID you're accessing.

  "createdAt": null,
String (Date-time)

Timestamp for when the operation started

  "id": "04fe9a97-a579-43c5-bb1a-58ed29bf0a6a"
String (Uuid)

An operation ID to query for updates on the progress of the batch. You can do a GET request to /operations/:operation to retrieve this.

}