Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.appnigma.ai/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Every Salesforce account that your user connects through Appnigma Integrations is stored as a Connection — an encrypted record linking a user’s Salesforce org to one of your integrations. This guide shows you how to manage those connections end-to-end using your credentials. You get two credentials when you create an integration:

API Key

Server-side only. Used to list connections, read their credentials, and make proxied Salesforce API calls. Never expose this in a browser.

Public Key

Frontend-safe. Used only to initiate the OAuth flow from a browser. Cannot read data or call APIs on its own.
All examples below use the official @appnigma/integrations-client Node SDK and the appnigma-integrations-client Python SDK.

Install the SDK

npm install @appnigma/integrations-client
Initialize the client once on your backend:
import { AppnigmaClient } from '@appnigma/integrations-client';

const appnigma = new AppnigmaClient({
  apiKey: process.env.APPNIGMA_API_KEY,
  baseUrl: 'https://integrations.appnigma.ai', // optional
});
The Python SDK is async — all methods must be called with await inside an async function. Use async with AppnigmaClient(...) as client: for automatic session cleanup.

1. Initiate a connection (public key)

This is the only step that uses your public key, and it happens in the browser. Redirect your user to the connect URL and AP-Integrations handles the entire OAuth handshake with Salesforce.

Connect URL format

https://integrations.appnigma.ai/connect/{integrationId}?public_key={publicKey}
integrationId
string
required
The ID of the integration you created via the admin API.
public_key
string
required
Your frontend-safe public key. Safe to include in client-side code.
A redirect_uri query parameter is also supported but not required. If omitted, the user will see a default success page after connecting.

Example: backend route that builds the URL

app.get('/api/connect-url', (req, res) => {
  const url =
    `https://integrations.appnigma.ai/connect/${process.env.AP_INTEGRATION_ID}` +
    `?public_key=${encodeURIComponent(process.env.AP_PUBLIC_KEY)}` +
    `&redirect_uri=${encodeURIComponent('https://yourapp.com/connected')}`;
  res.json({ url });
});

Example: frontend button

<button id="connect">Connect Salesforce</button>
<script>
  document.getElementById('connect').onclick = async () => {
    const { url } = await fetch('/api/connect-url').then(r => r.json());
    location.href = url;
  };
</script>
After the user approves, they land on your redirect_uri with a connection_id you should persist against your internal user record.

2. List connections (API key)

Fetch every connection tied to your integration. Useful for building an admin dashboard or letting users pick which org to query.
const result = await appnigma.listConnections({
  status: 'connected',
  environment: 'production',
  limit: 20,
});

console.log(result.connections);
// [
//   {
//     connectionId: 'abc-123',
//     userEmail: 'sarah@acme.com',
//     userName: 'Sarah Chen',
//     orgName: 'Acme Corp',
//     status: 'connected',
//     ...
//   }
// ]

Query parameters

status
string
Filter by status: connected, expired, revoked, deleted.
environment
string
default:"production"
production or sandbox.
Case-insensitive substring match against userEmail.
limit
number
default:"20"
Max connections to return per page.
cursor
string
Pagination cursor from the previous response’s nextCursor.

Response

connections
Connection[]
Array of connection summaries. Encrypted tokens are never included here.
totalCount
number
Number of connections in this page.
nextCursor
string
Opaque cursor for the next page. Omitted when there are no more results.

3. Inspect a single connection’s credentials (API key)

Retrieve a live, decrypted access token for a specific connection. The token is refreshed automatically if it’s within 5 minutes of expiring.
Returning a raw access token over the wire is powerful. Only call this endpoint server-side, and never forward the token to a browser.
const creds = await appnigma.getConnectionCredentials('conn-abc-123');

console.log(creds);
// {
//   accessToken: '00D...xxxx',
//   instanceUrl: 'https://acme.my.salesforce.com',
//   environment: 'production',
//   region: 'NA',
//   tokenType: 'Bearer',
//   expiresAt: '2026-04-10T14:32:00.000Z'
// }

When to use this

  • You need to call a Salesforce endpoint that isn’t supported by the proxy
  • You’re embedding a Salesforce SDK that expects a raw access token
  • You’re building a background worker that holds a token for a short burst of operations
For most use cases, prefer the proxy (next section) — it handles auth, refresh, and usage tracking for you.

4. Make proxied Salesforce API calls (API key)

The proxy is the easiest way to talk to Salesforce. You never see the token — you just describe the request you want to make.
const result = await appnigma.proxySalesforceRequest('conn-abc-123', {
  method: 'GET',
  path: '/services/data/v59.0/query',
  query: {
    q: 'SELECT Id, Name FROM Account LIMIT 10',
  },
});

console.log(result.records);

Request body

method
string
required
HTTP method: GET, POST, PUT, PATCH, or DELETE.
path
string
required
Salesforce API path, e.g. /services/data/v59.0/query. Do not include the instance URL.
query
object
Query string parameters (merged into the final URL).
data
object
JSON body for POST/PUT/PATCH requests.

What the proxy does for you

  1. Validates your API key and looks up the connection
  2. Refreshes the token automatically if it’s close to expiring
  3. Forwards your request to the correct Salesforce instance URL
  4. Tracks the call against your plan’s usage quota
  5. Returns the raw Salesforce response

Example: create an Opportunity

const newOpp = await appnigma.proxySalesforceRequest('conn-abc-123', {
  method: 'POST',
  path: '/services/data/v59.0/sobjects/Opportunity',
  data: {
    Name: 'Acme Deal Q2',
    StageName: 'Prospecting',
    CloseDate: '2026-06-30',
    Amount: 50000,
  },
});

console.log(newOpp.id); // '006xx0000011AbCdEF'

End-to-end example

Here’s a complete minimal backend that implements the user journey: user connects Salesforce → your app queries their pipeline → user can disconnect.
import express from 'express';
import 'dotenv/config';
import { AppnigmaClient } from '@appnigma/integrations-client';

const app = express();

const INTEGRATIONS_BASE = "https://integrations.appnigma.ai";

const appnigma = new AppnigmaClient({ apiKey: process.env.APPNIGMA_API_KEY });

// Step 1: browser asks for the connect URL
app.get('/api/connect-url', (_req, res) => {
  const url =
    `${INTEGRATIONS_BASE}/connect/${process.env.AP_INTEGRATION_ID}` +
    `?public_key=${process.env.AP_PUBLIC_KEY}` +
    `&redirect_uri=${encodeURIComponent('https://yourapp.com/connected')}`;
  res.json({ url });
});

// Step 2: AP-Integrations redirects here after approval
app.get('/connected', (req, res) => {
  const { connection_id } = req.query;
  // Persist connection_id against your internal user
  res.redirect(`/dashboard?connection_id=${connection_id}`);
});

// Step 3: list all connected orgs
app.get('/api/orgs', async (_req, res) => {
  const result = await appnigma.listConnections({ status: 'connected' });
  res.json(result.connections);
});

// Step 4: query a specific connection's pipeline
app.get('/api/pipeline/:connectionId', async (req, res) => {
  const result = await appnigma.proxySalesforceRequest(req.params.connectionId, {
    method: 'GET',
    path: '/services/data/v59.0/query',
    query: {
      q: `SELECT Id, Name, Amount, StageName FROM Opportunity
          WHERE IsClosed = false ORDER BY Amount DESC LIMIT 25`,
    },
  });
  res.json(result.records);
});

app.listen(4000);

Error handling

All SDK methods throw errors with a status property matching the HTTP status code returned by AP-Integrations.
try {
  const result = await appnigma.proxySalesforceRequest(connectionId, { ... });
} catch (err) {
  if (err.status === 404) {
    // Connection not found or deleted
  } else if (err.status === 401) {
    // Connection expired — user needs to reconnect
  } else if (err.status === 429) {
    // Monthly request limit exceeded
  } else {
    // Unknown error
    console.error(err);
  }
}

Common error codes

StatusMeaningWhat to do
400Missing required fieldCheck your request body
401Invalid API key or expired connectionPrompt user to reconnect
403API key doesn’t match the integrationVerify key/integration pairing
404Connection not foundPrompt user to connect
429Plan limit exceededUpgrade plan or wait for next month

Next steps

Node SDK

Node.js source code, issues, and changelog

Python SDK

Python source code, issues, and changelog