How to call our APIs

Time and monetary values

Our APIs use consistent formats for representing values of certain data types.

Time

Use RFC 3339 for time values. We store and return times in UTC timezone.

We will accept times in any time zone, though, as required by RFC 3339; you do need to specify the offset properly. We will convert any incoming time values to UTC for you.

Example: 1990-12-31T23:59:60Z.

Shop timezone has no effect on API

Each online shop is assigned to a particular time zone that is used to determine date boundaries for analytics and promo purposes. However, this timezone has no effect on parsing of API requests or formatting of API responses.

Date

Some values like birthdays and statistical days are pure dates, represented as YYYY-MM-DD strings. These are generally interpreted as corresponding to day boundaries in the shop time zone.

Birthdays may lack a year, in which case it is encoded as 0000 (0000-MM-DD).

Monetary

In API responses, monetary values are encoded as decimal strings with exactly 6 digits of precision, e.g. "42.990000".

On input, we accept two representations:

  • same format as responses — a decimal string representation of the value (you can use any precision you like);
  • an integer representing the value multiplied by 1_000_000 (e.g. $1 = 1000000, $0.01 = 10000).

Note that we do not accept straight floating-point values. We strongly recommend against using floating-point numbers to deal with monetary values.

Internally, we use fixed-point decimal values with 6 digits of precision when storing and processing monetary values. (Another way to explain it is that we store monetary values as 64-bit integers, premultiplied by 1_000_000.)

ValueEncodingAlternative acceptable inputs
$1"1.000000"1000000, "1.00", "1"
$0.05"0.050000"50000, "0.05"
$0.0001"0.000100"100, "0.0001"

Monetary with Currency

Some monetary values include currency. We encode these as a 2-element [amount, "currency"] array.

ValueEncodingAlternative acceptable inputs
$1["1.000000", "USD"][1000000, "USD"] or ["1.00", "USD"] or ["1", "USD"]
0.05 EUR["0.050000", "EUR"][50000, "EUR"] or ["0.05", "EUR"]

Permyriads

Percentages are specified as integer permyriads, aka 1/100s of a percent. (In other words, percentages are represented by decimal fixed-point numbers with 2 digits of precision, encoded as integers.)

ValueEncoding
0%0
1%100
50%5000
100%10000

Bubbleflake

These are internal Bubblehouse identifiers assigned to all objects it deals with. These identifiers use a format similar to Snowflake; we're calling it Bubbleflake.

In the API, they are represented by 16-character hex strings (e.g. "197a332e1f02002e"). You should treat these as opaque strings. (You are allowed to parse them into unsigned 64-bit integers if you'd like, e.g. for efficiency reasons on your side. But be sure to format these into 16-character lowercase hex strings with leading zeros before passing them back to Bubblehouse.)

Within a given shop, Bubbleflakes are unique and monotonically increasing, i.e. later objects get larger Bubbleflake values. (The values are increasing whether you treat them as strings or as integers, because the strings have a fixed length.)

Optional properties

Response properties marked as optional may be either omitted or set to null by Bubblehouse. You need to support both cases.

Dealing with nulls

This is worth repeating: in most cases we're omitting optional values with missing values, but we may opt to return nulls at any point. Depending on your backend stack, you might have to deal with that.

(We use Go on the server, and Go clients should have no problem dealing with nulls. Ditto for Swift clients using optionals. JavaScript clients should do == null checks with two-equals comparison operator. TypeScript clients might need to handle typing carefully.)

Previous
Rate limits