Connect by JBRH Open Connect

A developer calling the public API

A machine caller presents an integration key rather than a session cookie. The key is issued inside one workspace, carries an explicit scope set, and is stored only as a digest — the plaintext is shown once at issue and never again. Every request is filtered to that workspace, and a key cannot widen its own scope or reach the operator's surface.

Status
Available What this means
Audience
developer
Last verified
Product version
6.3.2

Why a key exists at all#

The application's own interface is authenticated by session cookie: a browser, a Google sign-in, a person. A server has none of those. The integration key is the deliberate, narrow answer to that — a credential for a service, bound to one workspace and one list of scopes.

  • Keys are prefixed so one is recognisable in a log or a configuration file at a glance.
  • Only a digest is stored, the same treatment a session token gets. A lost key is replaced, never recovered.
  • Scopes are additive and explicit, and there is no all-scope. A capability added later is not silently inherited by an existing key.
  • A key cannot widen its own scope, and nothing on the machine surface grants the operator's API.

One call, stage by stage#

  1. Trigger — your service needs to read or change something in one Connect workspace.
  2. External event — an HTTPS request arrives carrying the key.
  3. Authentication and workspace resolution — the key is matched by digest, checked as enabled, and resolved to exactly one workspace. The workspace is entered before any setting or row is read.
  4. Request — the route and the body are validated against the published description; a scope the key does not hold is refused here rather than deeper in.
  5. Canonical record — a writing call creates the same row the application would, through the service that owns it.
  6. Reasoning — only where the endpoint's job includes it. A plain read asks no model anything.
  7. Knowledge, memory and rules — the workspace's own data, filtered by the allowlist, the ORM kernel and row-level security independently.
  8. Autonomy and approval — an action that would need a human yes becomes a held item; the response says so rather than reporting a send.
  9. Action through a provider — where the call ends in an outbound message, the same send boundary a person uses is what runs.
  10. Result — a documented response shape, or a documented error shape. Success is never inferred from the absence of an error.
  11. Relationship, timeline and memory — anything created lands on the person and the timeline as it would from a screen.
  12. Audit, usage and Needs You — the action is attributed to the key, metered against the workspace, and queued for a person where it needs one.
GET /api/... HTTP/1.1
Host: connectbyjbrh.com
Authorization: Bearer cbj_<the key issued to you>
Accept: application/json

Errors, retries and duplicates#

Read the error shape rather than the status code alone: a refusal carries which rule refused, and that is what tells you whether to fix the request, ask a person, or wait. The exact bodies are documented on API error shapes; the rules below are the ones that hold across all of them.

  1. A 4xx is an answer. Retrying it unchanged produces the same answer and wastes your allowance.
  2. A 429 means slow down, not stop. Back off and retry the same request later; the limits are published on their own page rather than guessed at from observed behaviour.
  3. A 5xx or a dropped connection is genuinely uncertain. If the call could have created something, use the idempotency mechanism rather than re-posting blind.
  4. A held action is a success, not a failure. The request was accepted and the workspace's own rules decided a person should release it.

The duplicate risk is real and worth designing for. Re-sending on a maybe is how a customer receives the same message twice, which is why the send boundary reports an uncertain result as uncertain rather than guessing either way.

Before you build against it#

  1. Read the published description of the API rather than inferring shapes from responses.

    Result It is written to OpenAPI 3.1.0, so a client can be generated instead of hand-rolled.

  2. Issue a key with only the scopes your integration needs.

    Result A narrow key limits the blast radius of a leak and makes the audit trail readable.

  3. Decide how you will handle a held action before you write the happy path.

    Result An integration that treats held as failed will retry, and retrying an approval request is how a queue fills with duplicates.

  4. Test against a workspace you are willing to write to.

    Result Machine callers act on real records; there is no dry-run flag that makes a write pretend.

Questions#

Can one key serve several workspaces?

No. The binding to one workspace is on the key, not in the request, so there is no parameter that could point it elsewhere. Operating several workspaces means issuing a key in each — which also keeps the audit trail readable.

What happens if a key leaks?

Disable it. Because only a digest is stored, there is nothing to recover and nothing to rotate in place: issue a replacement, deploy it, then disable the old one. The audit trail attributes past actions to the key, so you can see what it did while it was valid.

Does the API let me do things the application will not?

No, and that is the design. The same domain services run underneath, so autonomy, suppression, do-not-contact and allowance limits apply identically. An endpoint that could step around them would make a workspace's own rules advisory.