Skip to main content
A dedicated Python SDK is not yet available. Use the Nango REST API directly with the requests library or any HTTP client. This page shows how to authenticate and call the most common endpoints.

Authentication

All requests to https://api.nango.dev require your secret key as a Bearer token.
import requests

NANGO_SECRET_KEY = "<YOUR-SECRET-KEY>"
NANGO_BASE_URL = "https://api.nango.dev"

headers = {
    "Authorization": f"Bearer {NANGO_SECRET_KEY}",
    "Content-Type": "application/json",
}
Get your secret key from Settings > Environment Settings in the Nango dashboard.
Never expose your secret key in client-side code or public repositories. Store it in an environment variable.
For self-hosted instances, replace https://api.nango.dev with your instance URL (e.g. http://localhost:3003).

Integrations

List integrations

response = requests.get(f"{NANGO_BASE_URL}/integrations", headers=headers)
integrations = response.json()
# returns {"data": [...]}

Get an integration

unique_key = "my-github-integration"
response = requests.get(
    f"{NANGO_BASE_URL}/integrations/{unique_key}",
    headers=headers
)
integration = response.json()

Create an integration

payload = {
    "provider": "github",
    "unique_key": "my-github-integration",
    "display_name": "GitHub",
    "credentials": {
        "oauth_client_id": "<CLIENT-ID>",
        "oauth_client_secret": "<CLIENT-SECRET>",
    },
}
response = requests.post(f"{NANGO_BASE_URL}/integrations", json=payload, headers=headers)
created = response.json()

Delete an integration

unique_key = "my-github-integration"
response = requests.delete(
    f"{NANGO_BASE_URL}/integrations/{unique_key}",
    headers=headers
)

Connect sessions

Create a connect session

Generate a short-lived session token to open the Connect UI for an end user.
payload = {
    "tags": {
        "end_user_id": "user-123",
        "end_user_email": "[email protected]",
        "organization_id": "org-456",
    },
    "allowed_integrations": ["github", "slack"],
}
response = requests.post(
    f"{NANGO_BASE_URL}/connect/sessions",
    json=payload,
    headers=headers,
)
session = response.json()
token = session["data"]["token"]
connect_link = session["data"]["connect_link"]

Connections

List connections

params = {
    "integrationId": "my-github-integration",
    "limit": 100,
}
response = requests.get(
    f"{NANGO_BASE_URL}/connections",
    params=params,
    headers=headers,
)
connections = response.json()["connections"]

Get a connection (with credentials)

Nango automatically refreshes expired tokens when you fetch a connection.
connection_id = "user-123"
params = {
    "provider_config_key": "my-github-integration",
    "force_refresh": False,
}
response = requests.get(
    f"{NANGO_BASE_URL}/connections/{connection_id}",
    params=params,
    headers=headers,
)
connection = response.json()
access_token = connection["credentials"]["access_token"]

Delete a connection

connection_id = "user-123"
params = {"provider_config_key": "my-github-integration"}
requests.delete(
    f"{NANGO_BASE_URL}/connections/{connection_id}",
    params=params,
    headers=headers,
)

Get connection metadata

connection_id = "user-123"
params = {"provider_config_key": "my-github-integration"}
response = requests.get(
    f"{NANGO_BASE_URL}/connections/{connection_id}",
    params=params,
    headers=headers,
)
metadata = response.json().get("metadata", {})

Set connection metadata

payload = {
    "connection_id": "user-123",
    "provider_config_key": "my-github-integration",
    "metadata": {"plan": "pro", "repo": "my-repo"},
}
requests.post(
    f"{NANGO_BASE_URL}/connections/metadata",
    json=payload,
    headers=headers,
)

Update connection metadata

Merges the supplied keys into existing metadata without overwriting other keys.
payload = {
    "connection_id": "user-123",
    "provider_config_key": "my-github-integration",
    "metadata": {"plan": "enterprise"},
}
requests.patch(
    f"{NANGO_BASE_URL}/connections/metadata",
    json=payload,
    headers=headers,
)

Proxy

Route authenticated requests to external APIs through Nango. Nango injects credentials automatically.
proxy_headers = {
    **headers,
    "Connection-Id": "user-123",
    "Provider-Config-Key": "my-github-integration",
}

# GET request
response = requests.get(
    f"{NANGO_BASE_URL}/proxy/repos/octocat/hello-world",
    headers=proxy_headers,
)
repo = response.json()

# POST request
response = requests.post(
    f"{NANGO_BASE_URL}/proxy/issues",
    json={"title": "Bug report", "body": "Something is broken."},
    headers=proxy_headers,
)
issue = response.json()
To configure retries, pass the Retries header:
proxy_headers["Retries"] = "3"

Syncs

List records

params = {
    "model": "GithubIssue",
    "limit": 100,
}
sync_headers = {
    **headers,
    "Connection-Id": "user-123",
    "Provider-Config-Key": "my-github-integration",
}
response = requests.get(
    f"{NANGO_BASE_URL}/records/",
    params=params,
    headers=sync_headers,
)
data = response.json()
records = data["records"]
next_cursor = data.get("next_cursor")
To paginate, pass cursor in the params:
params["cursor"] = next_cursor
response = requests.get(f"{NANGO_BASE_URL}/records/", params=params, headers=sync_headers)

Trigger a sync

payload = {
    "provider_config_key": "my-github-integration",
    "syncs": ["github-issues"],
    "connection_id": "user-123",
}
requests.post(f"{NANGO_BASE_URL}/sync/trigger", json=payload, headers=headers)

Get sync status

params = {
    "provider_config_key": "my-github-integration",
    "syncs": "github-issues",
    "connection_id": "user-123",
}
response = requests.get(f"{NANGO_BASE_URL}/sync/status", params=params, headers=headers)
status = response.json()["syncs"]

Actions

Trigger an action

action_headers = {
    **headers,
    "Connection-Id": "user-123",
    "Provider-Config-Key": "my-github-integration",
}
payload = {
    "action_name": "create-issue",
    "input": {"title": "New issue", "body": "Description"},
}
response = requests.post(
    f"{NANGO_BASE_URL}/action/trigger",
    json=payload,
    headers=action_headers,
)
result = response.json()

Error handling

All API errors return JSON with an error field. Check the HTTP status code and handle accordingly.
response = requests.get(f"{NANGO_BASE_URL}/connections", headers=headers)

if response.status_code == 429:
    retry_after = int(response.headers.get("Retry-After", "5"))
    print(f"Rate limited. Retry after {retry_after} seconds.")
elif not response.ok:
    error = response.json().get("error", {})
    print(f"Error {response.status_code}: {error.get('message', 'Unknown error')}")
else:
    data = response.json()

Helper class

For convenience, you can wrap the common patterns in a simple client class:
import requests


class NangoClient:
    def __init__(self, secret_key: str, host: str = "https://api.nango.dev"):
        self.base_url = host.rstrip("/")
        self.headers = {
            "Authorization": f"Bearer {secret_key}",
            "Content-Type": "application/json",
        }

    def list_connections(self, integration_id: str | None = None) -> list:
        params = {}
        if integration_id:
            params["integrationId"] = integration_id
        response = requests.get(f"{self.base_url}/connections", params=params, headers=self.headers)
        response.raise_for_status()
        return response.json()["connections"]

    def get_connection(self, provider_config_key: str, connection_id: str) -> dict:
        params = {"provider_config_key": provider_config_key}
        response = requests.get(
            f"{self.base_url}/connections/{connection_id}",
            params=params,
            headers=self.headers,
        )
        response.raise_for_status()
        return response.json()

    def trigger_action(self, provider_config_key: str, connection_id: str, action_name: str, input_data: dict | None = None) -> dict:
        action_headers = {
            **self.headers,
            "Connection-Id": connection_id,
            "Provider-Config-Key": provider_config_key,
        }
        payload = {"action_name": action_name, "input": input_data or {}}
        response = requests.post(f"{self.base_url}/action/trigger", json=payload, headers=action_headers)
        response.raise_for_status()
        return response.json()

    def proxy_get(self, provider_config_key: str, connection_id: str, endpoint: str) -> dict:
        proxy_headers = {
            **self.headers,
            "Connection-Id": connection_id,
            "Provider-Config-Key": provider_config_key,
        }
        response = requests.get(f"{self.base_url}/proxy{endpoint}", headers=proxy_headers)
        response.raise_for_status()
        return response.json()


# Usage
nango = NangoClient(secret_key="<YOUR-SECRET-KEY>")
connections = nango.list_connections(integration_id="my-github-integration")

Build docs developers (and LLMs) love