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,
)
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", {})
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,
)
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")