API versionv2 next

API v2 is not live yet: it launches in early 2027, and until then these pages are its spec. Switch to v1 (live)

Requests

A request names the object it acts on in its URL, and says what to do with it in its method and its body, a JSON object.

Environments

Host Environment
api.gjold.com Production, where payers pay for real.
api.gjold.dev The test environment, for developing integrations, where no money moves.

The two are not connected: an account, a key, or an ID on one means nothing on the other. Only we create accounts in the test environment: write to us and say what you need one for.

URLs

Every object has a URI, which names its shop, the database it is in, and its ID there:

{shopid}:{db}:{id}

A request's URL is https://api.gjold.com/v2/, then as much of a URI as the request needs, then the action, if the request has one. Without an action, the method says what the request does, as a DELETE deletes the object:

https://api.gjold.com/v2/{shopid}:{db}/{action}
https://api.gjold.com/v2/{shopid}:{db}:{id}/{action}
https://api.gjold.com/v2/{shopid}:{db}:{id}

A URL that fits no request is answered 404 Not Found, and a known URL with the wrong method 405 Method Not Allowed.

IDs

Database Its IDs
pay Payment links. A link's ID is the "id" that Create payment link answers with: 12 to 48 letters and digits.
trn Transactions, which a paid link or a charge of a subscriber creates. A transaction's ID is its "id" in seq's changes, or in the answer to Charge subscriber.
sub Subscribers. A subscriber's ID is its "id" in seq's changes.
seq The changes themselves, by number: see Seq.

Your shop ID is in the dashboard. Shop, transaction, and subscriber IDs are positive integers, written in decimal without leading zeros, and never reused. A shop's transactions are numbered from 1 in the order they were created, and so are its subscribers. Store an ID as a 64-bit integer, or as a string.

Request bodies

A POST request has a body: one JSON object, encoded as UTF-8, of at most 32 KiB. We don't read Content-Type, but send application/json, which is what it is. A request without fields to send, such as a void, sends {}.

The body must be valid JSON. If it isn't, the request fails with 400 invalid json in {where}: {why}, where {where} is the path of the field at fault, as in items[1].total, or json root object for the body as a whole. See Errors.

  • Unknown fields are ignored, so that a request written for a later version of the API, or with a field that you misspelled, still goes through. Check your spelling against the field tables.
  • Types are as each field table gives them. A field of another type is an error, and so is null: leave the field out instead.
  • Strings may contain any Unicode text, which we clean up before we store it: each white space character, such as a tab or a newline, becomes a space, other control characters are removed, and spaces at the ends are trimmed. A string that is empty after that is the same as no string at all.
  • Integers are JSON numbers without a fraction or an exponent, so 2, not 2.0 or "2".
  • Amounts are strings, as "99.95 DKK", never JSON numbers. See Amounts.

Responses

A request that succeeds is answered with 200 OK and a JSON object, which is {} for the requests that only act, such as a capture. Its Content-Type is application/json. A request that fails is answered with another status and a line of text. See Errors.

Every response has these headers:

HTTP header Why
Cache-Control: no-store No answer is to be cached, by you or anything in between.
Strict-Transport-Security: max-age=63072000 Browsers and clients that honour it use HTTPS only, for two years.
X-Content-Type-Options: nosniff The Content-Type is what it says.

Compatibility

The API's version is in its URL, /v2/. Within a version, we may add to the API, but not change or take away:

  • We may add requests, optional request fields, response fields, and new values of fields that list their values, such as a change's "type", a transaction's "act", a card's "brand", or a transaction's "services". Write your client to skip what it doesn't know.
  • We may add error messages, and reword them, but for the ones to branch on: a 402's first word, transient or permanent, and a 409's whole message, as Errors lists them. Branch on the status, and on those.
  • We don't remove or rename a field, change its type or meaning, or make an optional field required.

A change that breaks these rules goes in a new version, with its own URL, beside the old one.