Skip to main content

Introduction

The Ditto HTTP API follows a RESTful pattern and is organized into several resources. API Resources typically map to the key elements of the Ditto Data Model. Applications may contain one or more Collections of Documents or TimeSeries of Events. JSON is used as the default representation for individual resources, and will be indicated by the Content-Type HTTP Header. Resources which are best represented by a sequence or stream of items are represented by JSONlines, that is new line delimited JSON. This will be indicated by the MIME type application/json-l. UTF-8 encoding is used and required unless otherwise indicated. Binary data should be Base64 encoded. Where alternative representations are desired, the API Client may use the Accept HTTP Header to indicate this in the Request.

Introduction

For simple examples for using the HTTP API for document storage, see the corresponding sections in the Concepts section for querying, writing, and remove. Ditto Big Peer also provides HTTP APIs for querying timeseries data. See the timeseries section for more information.

Endpoint

The Ditto HTTP API provides a programmatic interface for interactions with Ditto-powered Apps which expose an HTTP Server Interface. A primary use case for the HTTP API is external systems which integrate with cloud.ditto.live.

The canonical root URL for the HTTP API can be found in your app's page on the Ditto Portal. The standard port 443 is used.

curl https://{app_id}.cloud.ditto.live/api/v3

Generating a Client ID

An X-DITTO-CLIENT-ID is required whenever issuing POST requests to the HTTP API. You should generate one for each client, as this ID represents a client in the Ditto mesh.

info

Generate this ID once and cache it for the duration of each client.

Client IDs are used to resolve conflicts as part of the CRDT. Generating a new ID for each request will cause performance issues, because each client represents a new device in the ditto mesh.

>>> import base64>>> site_id = 5>>> epoch = 0>>> site_id_bytes = site_id.to_bytes(8,'big')>>> epoch_bytes = epoch.to_bytes(8, 'big')>>> actor_id_bytes = site_id_bytes + epoch_bytes>>> actor_id_bytesb'\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00'>>> base64.b64encode(actor_id_bytes)b'AAAAAAAAAAUAAAAAAAAAAA=='

Authorization

Access to the Ditto HTTP API is mediated by an Authorization: Bearer HTTP Header. There are two ways to authorize access: via a JWT (JSON Web Token) or a static API Key.

API Key

Long-lived API tokens are great for server-side hydration, which are not owned by a particular user. These API keys can be obtained and managed through the portal in the "API Key" section.

api_key_top.png

You can give each API key its own read and write permissions, scoped to particular collections or document ids.

info

Currently, you can only specify a permission query on the _id field of a document. Mutable properties are currently not supported. We are working on adding this feature.

api_key.png

Once you have your API Key, you can use it as part of the Authorization: Bearer HTTP header in subsequent HTTP requests.

curl --location --request POST 'https://{YOUR_APP_ID}.cloud.ditto.live/api/v3/store/write' \--header 'X-DITTO-CLIENT-ID: AAAAAAAAAAAAAAAAAAAABQ==' \--header 'Authorization: Bearer {YOUR_API_KEY}' \--header 'Content-Type: application/json' \--data-raw '{    "commands": [{      "method": "upsert",      "collection": "people",      "value": {        "name": "Susan", "age": 31      }    }]  }'

Security

The API key is formed by three parts: randomly generated prefix, fixed prefix and randomly generated suffix. The value is generated through cryptographically secure PRNG. The suffix is hashed using scrypt before being stored in database along with the prefix. The unhashed API key will only be shown once in the portal and will be inaccessible after creation.

Apart from that, an approximate of the timestamp when the API key is last used is tracked and is available in the portal.

JWT (JSON Web Token)

There are specific cases where a broad, long-lived HTTP API key is not the right authorization mechanism. For user-scoped credentials, you can use a JWT retrieved from Online With Authentication to secure your HTTP endpoint. To retrieve a JWT for a particular user, send a POST request to the Big Peer with the given provider and the user's token.

  1. First, set your application to enable Authentication using OnlineWithAuthentication. This involves deploying an authentication server on a publicly-accessible URL by following the tutorial.
  2. Send a POST request to the /_ditto/auth/login endpoint. This is the same endpoint used to authorize small peers access, used by the OnlineWithAuthentication identity.
curl --location \    --request POST '{YOUR_APP_ID}.cloud.ditto.live/_ditto/auth/login' \    --data-raw 'appId={YOUR_APP_ID}&provider={YOUR_PROVIDER}&token={USER_TOKEN}&siteId=1'
  1. The following payload will be returned. Extract the accessToken value. You can use the accessExpiry value in your application code to handle the expiration date and refresh of the token.
{    "result": "success",    "userId": "...",    "identityB64": "..."    "accessToken": "MY_ACCESS_TOKEN"    "accessExpiry": "YYYY-MM-DDT00:00:00.0000000Z",    "refreshToken": null,    "refreshExpiry": null,    "audiences": [        "sync"    ],    "clientInfo": null}
  1. Once you have this token, you can use it as part of the Authorization: Bearer HTTP header in subsequent requests (as seen in the previous section).

Errors

Ditto HTTP API errors are indicated with an HTTP Status Code and with a JSON response body containing an object with a single "error" key. This Error object contains the following fields:

  • error.code - The HTTP Status Code for
  • error.message - A short description of the error
  • error.data - An optional object which contains further elaboration about the error

Transactions

A successful response to POST or DELETE requests will include a Transaction ID, which can be used on subsequent GET requests. This type of insertion is non-blocking and so is very performant.

Each HTTP API write request represents a distinct transaction which may be one or many operations (e.g., upsert or remove). Because Ditto is also a distributed system, Transaction IDs are used to represent the order in which transactions should be applied. Each write request returns its associated Transaction ID.

GET requests can optionally specify a Transaction ID in an HTTP HEADER called X-DITTO-TXN-ID. This header will instruct the server to wait until the given transaction is applied before executing the query. The newly inserted events may still be replicating through the Ditto mesh between the time of the write and the time of the find request. If you don't supply this header, the default behavior is to use the most recent version common to all Ditto nodes. If the Ditto node servicing the Request can't supply the version of the data requested, an error will be returned.

For example, you write data using the HTTP API and get back Transaction 17. If you want to ensure that the values included in Transaction included in our subsequent query, we would include the header X-DITTO-TXN-ID: 17 in the next request.

Note: the HTTP API will return an error when the requested DITTO-TXN-ID is not yet available on the server.

New and Improved Docs

Ditto has a new documentation site at https://docs.ditto.live. This legacy site is preserved for historical reference, but its content is not guaranteed to be up to date or accurate.