Docs
Dashboard
View as Markdown
On this page
  1. http
  2. kv
  3. log
  4. json
  5. crypto
  6. money
  7. time and url

Host API

Every function a plugin can call: http, kv, log, json, crypto, money, time, url and the ctx table.

Hooks are called as plugin.<hook>(ctx, input). ctx is the same for every kind:

Field
ctx.store { id, name, handle, currency }
ctx.plugin { id, name, version }
ctx.settings Values for the settings in the manifest, secrets decrypted (only inside the run)
ctx.test true in the test runner

JSON null members of input are absent (they read as nil), like most Lua JSON libraries.

http

local res, err = http.fetch({
  url = "https://api.example.com/v1/payments",
  method = "POST",                      -- GET by default
  headers = { authorization = "Bearer " .. ctx.settings.api_key },
  body = { amount = 2499 },             -- a table is sent as JSON; a string as is
})
if not res then error("network: " .. err) end
if not res.ok then error("HTTP " .. res.status .. ": " .. res.body) end
local data = res.json()                 -- res.status, res.headers, res.body, res.ok
  • Only hosts in permissions.http (api.example.com, or *.example.com for subdomains), only https.
  • Names that resolve to private, loopback, link-local or metadata addresses are refused, and the connection goes to the address that was checked.
  • 5 s timeout, 64 KB request body, 256 KB response, redirects returned (not followed), set-cookie dropped.
  • http.fetch returns nil, message instead of raising, so you decide what a failure means.
  • Calls are made from the hook’s main thread; calling it inside a coroutine raises.

kv

A private store per plugin (needs "kv": true): up to 1,000 keys of 16 KB.

kv.set("invoice:" .. id, json.encode({ amount = 2499 }), 86400)  -- optional TTL in seconds
local raw = kv.get("invoice:" .. id)                             -- string or nil
local n = kv.incr("issued", 2)                                    -- atomic counter
kv.delete("invoice:" .. id)
local keys = kv.list("invoice:", 50)                              -- by prefix

log

log.debug, log.info, log.warn, log.error and print take any values (tables are logged as JSON). Up to 200 lines of 2,000 characters per run, shown with the run in the workbench.

json

json.encode(value), json.decode(text), json.null, and json.array(t) to encode a table as [] even when it is empty. Object keys are sorted, so the same table always encodes to the same bytes (handy for signatures).

crypto

Function
crypto.hmac(alg, key, data, enc) alg: sha1, sha256, sha384, sha512, md5; enc: hex (default), base64, base64url
crypto.hash(alg, data, enc), crypto.sha256(data, enc) Digests
crypto.equal(a, b) Constant-time comparison: use it for every signature check
crypto.random_hex(bytes) Cryptographically random, up to 256 bytes
crypto.uuid() A random UUID
crypto.base64_encode/decode, crypto.base64url_encode, crypto.hex_encode/decode Encodings

money

Amounts are integers in minor units, everywhere. These helpers never use floats for an amount:

money.format(2499, "USD")        --> "$24.99"
money.to_major(2499, "USD")      --> "24.99"   (a string, for provider APIs that want decimals)
money.from_major("24.99", "USD") --> 2499      (refuses "24.999")
money.percent(1999, 250)         --> 50        (basis points, rounded half up)
money.split(100, 3)              --> {34, 33, 33}
money.exponent("JPY")            --> 0

time and url

time.now() (ms), time.unix() (seconds), time.iso(ms); url.encode, url.decode, url.query(table) and url.parse_query(text).

Was this page helpful?