NIN Connect Docs
REST API

Connections API

Manage end-user connections — hosted connect URLs, direct credentials, OAuth flows, listing active connections, and disconnecting users from plugins.

Initiate Connection (Hosted Connect URL)

POST /api/v1/connections/initiate

The primary way to connect end-users. Returns a URL you can redirect or link the user to. NIN handles the rest — showing the right UI, collecting credentials or running OAuth, encrypting, and storing.

Only approved plugins can be connected. Attempting to initiate a connection to a plugin that is still in draft, pending_review, declined, or revision_requested status will return a 404 error.

Authentication

API key required: Authorization: Bearer nk_live_...

Request Body

{
  "userId": "user_123",
  "plugin": "gmail",
  "redirectUrl": "https://your-app.com/callback"
}
FieldTypeRequiredDescription
userIdstringYesYour app's end-user identifier
pluginstringYesPlugin slug (e.g. gmail, stripe, openai)
authMethodstringNoSpecific auth method type to use (see behavior below)
connectionTypestringNo"rest" (default) or "mcp". When "mcp", initiates an OAuth flow with PKCE targeting the plugin's MCP server.
redirectUrlstringYes*Where to send the user after connecting

returnUrl, return_url, callbackUrl, and callback_url are accepted as aliases. If none are provided, NIN tries X-NIN-Redirect-URL, X-Return-URL, Referer, then Origin. Server-to-server callers should still send redirectUrl explicitly.

Response

{
  "connectUrl": "https://connect.nin.in/connect/gmail?developerId=...&userId=...&redirectUrl=...",
  "redirectUrl": "https://your-app.com/callback"
}

Behavior

What connectUrl returns depends on the plugin's auth methods, connectionType, and whether you pass authMethod:

connectionTypeauthMethod paramWhat happens
"mcp"Returns an OAuth authorization URL with PKCE for the plugin's MCP server. Requires the plugin to have mcpConfig set.
"rest" or omitted"oauth2"Returns the REST OAuth provider's authorization URL directly
"rest" or omittedOmitted (default is oauth2)Same — goes straight to OAuth
"rest" or omittedOmitted (default is non-OAuth)Returns a hosted connect page URL showing all available auth methods
"rest" or omitted"api_key" or otherReturns a hosted connect page URL filtered to that specific method

Hosted Connect Page

When the connectUrl points to NIN's hosted connect page (/connect/[plugin]), the end-user sees:

  • The plugin name and description
  • All available auth methods (if authMethod was omitted) or a single method (if specified)
  • For MCP-enabled plugins: a "Connect with [Service] MCP" button that initiates OAuth with PKCE
  • For OAuth methods: a button that redirects through the provider's authorization flow
  • For API key / bearer token: a form to paste credentials
  • For service accounts: a textarea for JSON credentials
  • For no_auth: a simple "Connect" button

After the user completes the flow, they're redirected back to your redirectUrl with ?status=success or ?status=error&error=....

Example: MCP Connection

const session = nin.session("user_123");

const { connectUrl } = await session.initiateConnection({
  plugin: "notion",
  connectionType: "mcp",
  redirectUrl: "https://your-app.com/callback",
});
// User clicks → Notion OAuth with PKCE → tokens stored → redirected back

Example: "Connect your Gmail" Button

// in your backend
const session = nin.session("user_123");

const { connectUrl } = await session.initiateConnection({
  plugin: "gmail",
  redirectUrl: "https://your-app.com/settings?tab=integrations",
});

// send connectUrl to your frontend, render as a link or button
// the user clicks it → authorizes with Google → returns to your app

Example: Show All Auth Options

If a plugin has multiple auth methods (e.g. Gmail has OAuth + service account), omit authMethod to let the user choose:

const { connectUrl } = await session.initiateConnection({
  plugin: "gmail",
  redirectUrl: "https://your-app.com/callback",
  // no authMethod → hosted page shows all options
});

Example: Force a Specific Method

const { connectUrl } = await session.initiateConnection({
  plugin: "openai",
  authMethod: "api_key",
  redirectUrl: "https://your-app.com/callback",
});
// hosted page only shows the API key form

Create Connection (Direct)

POST /api/v1/connections

Submit credentials directly from your backend — no redirect or UI needed. Best for cases where you already have the user's credentials (e.g. they entered an API key in your own settings page).

Authentication

API key required: Authorization: Bearer nk_live_...

Request Body

{
  "userId": "user_123",
  "plugin": "openai",
  "authMethod": "api_key",
  "credentials": {
    "api_key": "sk-..."
  },
  "accountLabel": "My OpenAI Key"
}
FieldTypeRequiredDescription
userIdstringYesYour app's end-user identifier
pluginstringYesPlugin slug
authMethodstringYesAuth method type (e.g. api_key, bearer_token)
credentialsobjectYesKey-value pairs of credentials
accountLabelstringNoDisplay label for this connection

Response

{
  "connected": true
}

If a connection already exists for the same developer + user + plugin, the credentials are updated (upsert behavior).


Disconnect Connection

DELETE /api/v1/connections

Removes an end-user connection and clears any live MCP client cached for that user/plugin.

Authentication

API key required: Authorization: Bearer nk_live_...

Request Body

You can disconnect by plugin slug:

{
  "userId": "user_123",
  "plugin": "gmail"
}

Or by a connection ID returned from GET /api/v1/connections:

{
  "userId": "user_123",
  "connectionId": "550e8400-e29b-41d4-a716-446655440002"
}
FieldTypeRequiredDescription
userIdstringYesYour app's end-user identifier
pluginstringYes, unless connectionId is providedPlugin slug to disconnect
connectionIdstringYes, unless plugin is providedSpecific connection ID returned by GET /api/v1/connections

Response

{
  "disconnected": true
}

If no matching connection exists for the authenticated developer and userId, the API returns 404.

The SDK exposes this as:

await session.disconnectConnection({ plugin: "gmail" });
await session.disconnectConnection({
  connectionId: "550e8400-e29b-41d4-a716-446655440002",
});

List Connections

GET /api/v1/connections?userId=user_123

Returns the user's active connections.

Authentication

API key required: Authorization: Bearer nk_live_...

Query Parameters

ParameterTypeRequiredDescription
userIdstringYesThe end-user identifier

Response

{
  "connections": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440002",
      "pluginSlug": "gmail",
      "pluginName": "Gmail",
      "pluginDescription": "Send and manage emails via Gmail API",
      "pluginIconUrl": "https://example.com/gmail-icon.png",
      "authMethodType": "oauth2",
      "accountLabel": "work@company.com",
      "hasMcpTokens": false,
      "createdAt": "2025-01-15T10:30:00.000Z"
    },
    {
      "id": "660e8400-e29b-41d4-a716-446655440003",
      "pluginSlug": "notion",
      "pluginName": "Notion",
      "pluginDescription": "Search and update Notion pages",
      "pluginIconUrl": "https://example.com/notion-icon.png",
      "authMethodType": null,
      "accountLabel": null,
      "hasMcpTokens": true,
      "createdAt": "2025-03-01T14:00:00.000Z"
    }
  ]
}

OAuth Callback

GET /api/v1/oauth/callback

This is the fixed callback URL for all OAuth providers. You do not call this endpoint directly — it is called by the OAuth provider after user authorization.

The callback:

  1. Verifies the HMAC-signed state token
  2. Detects whether this is a REST or MCP OAuth flow (via isMcp flag in state)
  3. Finds the pending connection record
  4. Exchanges the authorization code for tokens (includes code_verifier for MCP PKCE flows)
  5. Encrypts and stores the tokens — REST tokens in credentials, MCP tokens in mcpAccessToken/mcpRefreshToken
  6. Cleans up the pending connection
  7. Redirects the user to your redirectUrl with ?status=success or ?status=error&error=...

On this page