Skip to content

Client libraries

The OpenAPI document is generated from the same code that serves the API, and the rhino-relay command line is generated from it. Point any OpenAPI 3.1 generator at it to get a library in your language. Everything a library needs beyond plain OpenAPI is in a few x- fields, described here, so a generated library and the CLI name and behave the same.

Each operation has one tag, its resource group, and an operationId of the form verb then resource (getCampaignReport). x-client gives the short names:

"x-client": { "group": "campaigns", "method": "report" }

Use group for the library’s namespace and method for the method: client.campaigns.report(id). The CLI uses the same names in kebab-case: rhino-relay campaigns report <id>. Each tag’s x-group and description give the namespace and its documentation.

x-idempotency says how a request may be retried after a timeout or a 5xx:

Value Meaning
key-required Send an Idempotency-Key (make one up per call); retry with the same key
key-optional Same, when you send a key; without one, don’t retry automatically
safe Repeating the request changes nothing further (reads, updates, deletes, state changes)
unsafe Never retry automatically. Only POST /keys: the new secret is returned once and never stored for replay

429 and 503 responses carry Retry-After. A replayed response carries Idempotent-Replayed: true. See Idempotency.

Lists carry x-pagination, so a generator can make them iterable:

"x-pagination": { "type": "cursor", "limitParam": "limit", "cursorParam": "cursor", "itemsField": "data", "nextCursorField": "nextCursor" }

Follow nextCursor until it’s null. See Pagination.

Imports, exports, campaigns and setup take a while. The GET operations that show their progress carry x-waiters, in the shape of AWS SDK waiters: poll every delaySeconds, up to maxAttempts times, until a response field matches an acceptor.

"x-waiters": {
"ready": {
"description": "The export is written and downloadUrl is set",
"delaySeconds": 5,
"maxAttempts": 720,
"acceptors": [
{ "path": "state", "expected": "ready", "state": "success" },
{ "path": "state", "expected": "failed", "state": "failure" }
]
}
}

The requests that start the work (POST /exports, the import calls, /schedule, /resume and /setup/verify) carry a standard OpenAPI response link to the GET, with the new resource’s id, so a library can offer “create and wait”. In the CLI that’s --wait: rhino-relay exports create --data '{"kind":"contacts"}' --wait ready.

OperationWaiterSucceeds whenStops early whenPolls every
campaigns.getcompleted: Every stage has gone out. A pause or cancel ends the wait, since it needs you to actstate = completedstate = paused, state = cancelled30 seconds
imports.getdryRunReady: The dry run is ready to review and commit (or the import went further)state = dry_run_ready, state = committing, state = completedstate = failed, state = cancelled5 seconds
imports.getcompleted: The import is committedstate = completedstate = failed, state = cancelled10 seconds
exports.getready: The export is written and downloadUrl is setstate = readystate = failed5 seconds
health.gethealthy: Every setup and sending check passes (DNS can take a while to spread)ok = true—30 seconds

Every object and enum in a request or response is a named schema, so libraries get the same readable type names. Unions have a type field and a discriminator, so each kind gets its own type: segment conditions (tag, field, score, clicked, opened, created and nested group) and stage plans (preset and custom). Contacts, segments, campaigns and settings send their version as an ETag, which If-Match takes back.

servers lists every host: the home Region (marked x-region), other Regions (a {region} variable) and your custom domain. The only security scheme is the API key, a standard bearer token, so every generated library works with it as it is.

SigV4 isn’t a security scheme, because OpenAPI has none for it and generators would try to send it as a fixed header. x-sigv4 at the top of the document describes it instead: your Region’s SigV4 endpoint and the signing service. To use it from a library, point the library at that endpoint and sign each request with the AWS SDK’s signer in its request hook, as in Authentication.

Errors are application/problem+json with a code from a fixed list (x-error-codes at the top of the document), so a library can raise one error type per code. See Errors.