Makini Link is a ready-made onboarding flow your customers use to connect their CMMS, EAM, ERP or fleet system to your product. You send them to one URL. Link walks them through choosing their system and entering their credentials, verifies those credentials against the system, creates the connection and sends them back to you with a code. You exchange the code for a token that reads and writes that customer's data.You write no credential forms, no per-vendor setup screens and no validation logic. Link carries your application's name and logo, so the experience feels like part of your product.What your customer sees#
1.
Consent. "Your app uses Makini to link your product", with your logo.
2.
Platform. A searchable list of the systems you offer. You choose which ones appear in Platforms in the dashboard.
3.
Connection details. A name for the connection and a contact email.
4.
Credentials. The exact fields their system needs. Link checks them against the system before anything is created, and says clearly what to fix if they are wrong. Customers whose system sits behind a firewall can connect it through a VPN on this step (see Connecting on-premise systems).
When they finish, Link sends them back to your redirect_uri.Upload your logo in Settings → Application. Link shows it on every step. To match your colors as well, use Settings → Whitelabel (a plan add-on).
Before you start#
Register your redirect URI in Settings → Application. Link compares redirect_uri against your registered URIs as an exact string, so https://app.example.com/makini/callback and https://app.example.com/makini/callback/ are different URIs. A redirect URI must use https (plain http is allowed for localhost and 127.0.0.1) and cannot contain a fragment.If each of your customers has their own subdomain or path, register one URI with a * wildcard instead of one URI per customer:https://*.example.com/makini/callback matches https://acme.example.com/makini/callback. A * in the host stands for exactly one subdomain label, must come before your own domain, and never matches a dot, so https://a.b.example.com/makini/callback does not match.
https://app.example.com/*/callback matches https://app.example.com/acme/callback. A * in the path stands for exactly one segment made of letters, digits, ., _, ~ and -.
A wildcard must replace a whole subdomain label or a whole path segment (https://acme-*.example.com is not accepted), needs https, and cannot be used in the port or the query string. Everything outside the wildcard is still compared exactly, and the redirect_uri you send must be written the way a browser would write it: lowercase host, no user name, no default port.You also need your client ID and client secret from the same page. The secret is used only on your server, when you exchange the code.The authorize URL#
https://link.makini.io/authorize?client_id=<CLIENT_ID>&redirect_uri=<REDIRECT_URI>&state=<STATE>
| Parameter | Required | Description |
|---|
client_id | Yes | Your application's client ID. |
redirect_uri | Yes | Where Link sends your customer back. Must match a registered URI exactly, or a registered wildcard URI. URL-encode it. |
state | Recommended | An opaque value (up to 512 characters) that Link returns unchanged. Use it to match the response to the request and to protect against CSRF. |
response_type | No | code, the only value. You can leave it out. |
platform | No | A platform key, such as upkeep. Link opens on that platform and your customer skips the platform list. |
metadata[<key>] | No | Your own key/value labels, stored on the connection's userMetadata. Repeat it for each key. user_metadata[<key>] means the same. |
forms, solutions, flow_folders | No | Features to turn on for the connection, as comma-separated names: form keys, solution slugs and flow folder IDs. A name that isn't offered on the platform your user picks is left out. |
name, email | No | Prefill the name and contact email Link asks for. Your customer can still change them. Ignored with connection_id, which keeps the connection's own. |
connection_id | No | An existing connection's ID. Link updates that connection's credentials instead of creating a new one. |
https://link.makini.io/authorize
?client_id=5b1f0c3e-8a2d-4c7e-9f10-2d3e4a5b6c7d
&redirect_uri=https%3A%2F%2Fapp.example.com%2Fmakini%2Fcallback
&state=f3a9c2e1
&platform=upkeep
&metadata[account_id]=acct_1042
&metadata[region]=eu
(Line breaks added for reading; send it as one URL.)
Full-page redirect
The simplest option. Navigate the current tab to the authorize URL. Link sends your customer back to your redirect_uri when they finish.
Popup window
Your page stays where it is. Open Link in a popup, and have your callback page hand the result back to the page that opened it.Open Link as a top-level page or a popup, not inside an iframe. Link protects each flow with a first-party session cookie, and browsers don't send it inside a frame.
A popup, from the page that starts the flow:And on your callback page (your redirect_uri), which loads inside the popup:Handle the redirect#
When your customer finishes, Link redirects to your redirect_uri with the code and your state:https://app.example.com/makini/callback?code=<CODE>&state=f3a9c2e1
Check that state is the value you sent before you use the code. The code is single-use and expires after 15 minutes, so exchange it right away.If the flow doesn't complete, Link redirects with error and error_description instead of code, and still includes your state:error | Meaning |
|---|
access_denied | Your customer chose not to connect. |
invalid_request | The connection_id, platform, forms, solutions or flow_folders you sent can't be used by your application. |
unsupported_response_type | response_type was something other than code. |
server_error | A temporary problem. Start the flow again. |
Link redirects only to a registered URI. If client_id is unknown, redirect_uri isn't registered, or a parameter is malformed (sent twice, or state or metadata over its limits), Link shows an error page and doesn't redirect.Exchange the code#
On your server, exchange the code at POST https://api.makini.io/oauth/token with grant_type=authorization_code, and authenticate with your client ID and secret. redirect_uri is optional; if you send it, send the same one you used on the authorize URL (the full address, not the wildcard URI you registered):The response is a connection-scoped access token, a refresh token, the connection_id of the new connection and enabled: the forms, solutions and flow folders on for it. Store the connection ID and the refresh token with your customer's account. The refresh token rotates on every use. See Access tokens for refreshing and revoking.Reconnect an existing connection#
When a customer's password changes or their credentials expire, send them through Link again with connection_id:https://link.makini.io/authorize?client_id=<CLIENT_ID>&redirect_uri=<REDIRECT_URI>&state=<STATE>&connection_id=<CONNECTION_ID>
Link updates that connection instead of creating a second one:The connection keeps its ID, so every reference you hold stays valid.
Your customer confirms consent, then sees only the steps that still need an answer. The platform and connection method stay as they are. The name and email are prefilled, and your customer can still correct them.
The new credentials replace the stored ones.
The same parameter completes a connection you created through the Management API without credentials: your customer fills in what's missing.Link accepts only connections that belong to your application. Any other value redirects with error=invalid_request.platform skips the platform list. Use it when your product already knows which system the customer runs, such as from a "Connect UpKeep" button. The platform must be one your application offers in Platforms. On a reconnect, it must match the connection's own platform.metadata[<key>]=<value> labels the connection with your own records, such as your customer's account ID. The values are stored on the connection's userMetadata, which the Management API returns, so you can match a connection to your own records without keeping a separate table.Up to 20 keys. Keys up to 64 characters; values up to 512.
On a reconnect, your keys are merged into the connection's existing metadata. Keys you don't send are kept.
source and linkFlowId are set by Makini on every connection Link creates and can't be overridden.
To hand a customer a link without writing any code, create the connection in the dashboard and send them a magic link instead. See Magic links.