Authentication
OAuth 2.0 user sign-in with PKCE, the audience and scopes, what a caller can see, and choosing a tenant.
A person signs in with their Relynk account, and the app calls the API with that person's access token.
Every call except the docs and the OpenAPI document needs that token. There are no API keys.
The sign-in
Relynk uses OAuth 2.0 authorization code with PKCE, the standard "Sign in with…" flow. The app sends the person to Relynk's sign-in page, gets a code back, and exchanges the code for an access token. PKCE (Proof Key for Code Exchange) protects that exchange, so apps that run in a browser or on a phone need no secret.
| Setting | Value |
|---|---|
| Authorization endpoint | https://auth.relynk.io/authorize |
| Token endpoint | https://auth.relynk.io/oauth/token |
| Audience | https://ai.relynk.io/builder |
| Scopes | openid offline_access |
| Client ID | ask your Relynk contact for it |
- Audience. Send
audience=https://ai.relynk.io/builderon the authorization request. It names the API the token is for. Without it, sign-in succeeds but the token is not accepted and every call answers 401. - Scopes.
openididentifies the person;offline_accessgives a refresh token, so the app can stay signed in without asking again. - Client ID and redirect URL. Relynk issues the client ID and registers the app's redirect URL (where Relynk sends the person back after sign-in). Ask your Relynk contact for both.
- No passwords. An app never asks for a Relynk password. The person types it only on Relynk's own sign-in page.
The authorization request to https://auth.relynk.io/authorize carries these query parameters:
| Parameter | Value |
|---|---|
response_type | code |
client_id | The client ID from Relynk |
redirect_uri | The redirect URL Relynk registered for the app |
scope | openid offline_access |
audience | https://ai.relynk.io/builder |
code_challenge | The PKCE challenge, with code_challenge_method=S256 |
state | A random value the app checks when the person returns |
Platforms with an OAuth connector do all of this for you. In Lovable, follow Build an app with Lovable.
Calling the API
Send the access token as a bearer token:
GET https://ai.relynk.io/builder/v1/me
authorization: Bearer <access token>- Refresh the token with the refresh token before it expires. When a call answers 401, sign the person in again.
- Keep tokens out of URLs, logs and source code.
- A browser can call the API directly only from web addresses Relynk has allowed. Otherwise call it from the app's own backend, with the person's token.
What a caller can see
A call sees exactly what the signed-in person may see in Relynk: the same tenants, the same buildings, nothing more. A person with access to two buildings sees those two buildings and their rooms, sensors and meters only. The API cannot read anything that person cannot.
If the app is shared, as with a shared Lovable connection, everyone using it sees what the person who connected can see. Connect with an account that has only the access the app should show.
Choosing a tenant
A tenant is one organisation in Relynk, such as a property company. Most people belong to one; some belong to several.
GET /me lists the tenants the person can read:
{
"userId": "6f1c…",
"tenants": [
{ "id": "8a1f…", "name": "Example Property AS" },
{ "id": "41b0…", "name": "Another Property AS" }
]
}- One tenant: leave
tenantIdout; calls read that tenant. - Several tenants: let the person choose, and add
?tenantId=<id>to every call. Without it the call fails with 400: "The caller belongs to 2 tenants: pass tenantId (GET /me lists them)". - A tenant the person cannot read: 403, "No access to tenant …".
- No tenant at all: 403, "The caller has no access to any tenant".