Instantly
by @byungkyu
Instantly API integration with managed OAuth. Cold email outreach platform for managing campaigns, leads, accounts, and analytics. Use this skill when users...
clawhub install instantlyπ About This Skill
name: instantly description: | Instantly API integration with managed OAuth. Cold email outreach platform for managing campaigns, leads, accounts, and analytics. Use this skill when users want to create campaigns, manage leads, send emails, or view analytics. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway). compatibility: Requires network access and valid Maton API key metadata: author: maton version: "1.0" clawdbot: emoji: π§ homepage: "https://maton.ai" requires: env: - MATON_API_KEY
Instantly
Access the Instantly API v2 with managed authentication. Manage cold email campaigns, leads, sending accounts, and view analytics.
Quick Start
# List campaigns
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/instantly/api/v2/campaigns?limit=10')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Base URL
https://api.maton.ai/instantly/{native-api-path}
Maton proxies requests to api.instantly.ai and automatically injects your API key.
Authentication
All requests require the Maton API key in the Authorization header:
Authorization: Bearer $MATON_API_KEY
Environment Variable: Set your API key as MATON_API_KEY:
export MATON_API_KEY="YOUR_API_KEY"
Getting Your API Key
1. Sign in or create an account at maton.ai 2. Go to maton.ai/settings 3. Copy your API key
Connection Management
Manage your Instantly connections at https://api.maton.ai.
List Connections
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections?app=instantly&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Create Connection
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'instantly'}).encode()
req = urllib.request.Request('https://api.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Get Connection
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Response:
{
"connection": {
"connection_id": "{connection_id}",
"status": "ACTIVE",
"creation_time": "2026-02-11T22:19:35.798712Z",
"last_updated_time": "2026-02-11T22:20:15.702846Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "instantly",
"metadata": {}
}
}
Open the returned url in a browser to complete authorization.
Delete Connection
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Specifying Connection
If you have multiple Instantly connections, specify which one to use with the Maton-Connection header:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/instantly/api/v2/campaigns')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '{connection_id}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If you have multiple connections, always include this header to ensure requests go to the intended account.
Security & Permissions
API Reference
Campaigns
#### List Campaigns
GET /instantly/api/v2/campaigns?limit=10&status=1&search=keyword
Query parameters:
limit - Number of results (default: 10)status - Campaign status filter (0=draft, 1=active, 2=paused, 3=completed)search - Search by campaign namestarting_after - Cursor for pagination#### Get Campaign
GET /instantly/api/v2/campaigns/{campaign_id}
#### Create Campaign
POST /instantly/api/v2/campaigns
Content-Type: application/json{
"name": "My Campaign",
"campaign_schedule": {
"schedules": [
{
"name": "My Schedule",
"timing": {
"from": "09:00",
"to": "17:00"
},
"days": {
"0": true,
"1": true,
"2": true,
"3": true,
"4": true
},
"timezone": "Etc/GMT+5"
}
]
}
}
Note: Timezone must use Etc/GMT format (e.g., "Etc/GMT+5", "Etc/GMT-8", "Etc/GMT+12").
#### Activate Campaignbash
POST /instantly/api/v2/campaigns/{campaign_id}/activate
#### Pause Campaignbash
POST /instantly/api/v2/campaigns/{campaign_id}/pause
#### Delete Campaignbash
DELETE /instantly/api/v2/campaigns/{campaign_id}
#### Search Campaigns by Lead Emailbash
GET /instantly/api/v2/campaigns/search-by-contact?search=lead@example.com
Leads
#### Create Lead
bash
POST /instantly/api/v2/leads
Content-Type: application/json{ "campaign_id": "019bb3bd-9963-789e-b776-6c6927ef3f79", "email": "lead@example.com", "first_name": "John", "last_name": "Doe", "company_name": "Acme Inc", "variables": { "custom_field": "custom_value" } }
#### Bulk Add Leadsbash
POST /instantly/api/v2/leads
Content-Type: application/json{ "campaign_id": "019bb3bd-9963-789e-b776-6c6927ef3f79", "leads": [ { "email": "lead1@example.com", "first_name": "John" }, { "email": "lead2@example.com", "first_name": "Jane" } ] }
#### List LeadsNote: This is a POST endpoint due to complex filtering requirements.
bash
POST /instantly/api/v2/leads/list
Content-Type: application/json{ "campaign_id": "019bb3bd-9963-789e-b776-6c6927ef3f79", "limit": 100 }
#### Get Leadbash
GET /instantly/api/v2/leads/{lead_id}
#### Delete Leadbash
DELETE /instantly/api/v2/leads/{lead_id}
#### Move Leadsbash
POST /instantly/api/v2/leads/move
Content-Type: application/json{ "lead_ids": ["lead_id_1", "lead_id_2"], "to_campaign_id": "target_campaign_id" }
Lead Lists
#### List Lead Lists
bash
GET /instantly/api/v2/lead-lists?limit=10
#### Create Lead Listbash
POST /instantly/api/v2/lead-lists
Content-Type: application/json{ "name": "My Lead List" }
#### Get Lead Listbash
GET /instantly/api/v2/lead-lists/{list_id}
#### Update Lead Listbash
PATCH /instantly/api/v2/lead-lists/{list_id}
Content-Type: application/json{ "name": "Updated List Name" }
#### Delete Lead Listbash
DELETE /instantly/api/v2/lead-lists/{list_id}
Accounts (Sending Email Accounts)
#### List Accounts
bash
GET /instantly/api/v2/accounts?limit=10
#### Get Accountbash
GET /instantly/api/v2/accounts/{email}
#### Create Accountbash
POST /instantly/api/v2/accounts
Content-Type: application/json{ "email": "sender@example.com", "first_name": "John", "last_name": "Doe", "provider_code": "google", "smtp_host": "smtp.gmail.com", "smtp_port": 587, "smtp_username": "sender@example.com", "smtp_password": "app_password", "imap_host": "imap.gmail.com", "imap_port": 993, "imap_username": "sender@example.com", "imap_password": "app_password" }
#### Update Accountbash
PATCH /instantly/api/v2/accounts/{email}
Content-Type: application/json{ "first_name": "Jane" }
#### Delete Accountbash
DELETE /instantly/api/v2/accounts/{email}
#### Enable Warmupbash
POST /instantly/api/v2/accounts/warmup/enable
Content-Type: application/json{ "emails": ["account1@example.com", "account2@example.com"] }
#### Disable Warmupbash
POST /instantly/api/v2/accounts/warmup/disable
Content-Type: application/json{ "emails": ["account1@example.com"] }
Emails (Unibox)
#### List Emails
bash
GET /instantly/api/v2/emails?limit=20
#### Get Emailbash
GET /instantly/api/v2/emails/{email_id}
#### Reply to Emailbash
POST /instantly/api/v2/emails/reply
Content-Type: application/json{ "reply_to_uuid": "email_uuid", "body": "Thank you for your response!" }
#### Forward Emailbash
POST /instantly/api/v2/emails/forward
Content-Type: application/json{ "email_uuid": "email_uuid", "to": "forward@example.com" }
#### Mark Thread as Readbash
POST /instantly/api/v2/emails/threads/{thread_id}/mark-as-read
#### Get Unread Countbash
GET /instantly/api/v2/emails/unread/count
#### Update Emailbash
PATCH /instantly/api/v2/emails/{email_id}
Content-Type: application/json{ "is_read": true }
#### Delete Emailbash
DELETE /instantly/api/v2/emails/{email_id}
Analytics
#### Get Campaign Analytics
bash
GET /instantly/api/v2/campaigns/analytics?id={campaign_id}
Query parameters:
id - Campaign ID (leave empty for all campaigns)
start_date - Filter start date (YYYY-MM-DD)
end_date - Filter end date (YYYY-MM-DD)
exclude_total_leads_count - Set to true for faster response#### Get Campaign Analytics Overview
bash
GET /instantly/api/v2/campaigns/analytics/overview?id={campaign_id}
#### Get Daily Campaign Analyticsbash
GET /instantly/api/v2/campaigns/analytics/daily?id={campaign_id}
#### Get Campaign Step Analyticsbash
GET /instantly/api/v2/campaigns/analytics/steps?id={campaign_id}
#### Get Warmup Analyticsbash
POST /instantly/api/v2/accounts/warmup/analytics
Content-Type: application/json{ "emails": ["account@example.com"] }
Block List
#### List Block List Entries
bash
GET /instantly/api/v2/block-lists-entries?limit=100
Query parameters:
domains_only - Filter to domain entries only
search - Search entries#### Create Block List Entry
bash
POST /instantly/api/v2/block-lists-entries
Content-Type: application/json{ "bl_value": "blocked@example.com" }
Or block a domain:bash
POST /instantly/api/v2/block-lists-entries
Content-Type: application/json{ "bl_value": "blockeddomain.com" }
#### Delete Block List Entrybash
DELETE /instantly/api/v2/block-lists-entries/{entry_id}
Email Verification
#### Verify Email
bash
GET /instantly/api/v2/email-verification/{email}
If verification takes longer than 10 seconds, status will be pending. Poll this endpoint to check status.Response fields:
verification_status - Use this field (not status) to determine verification resultBackground Jobs
#### Get Background Job Status
bash
GET /instantly/api/v2/background-jobs/{job_id}
Query parameters:
data_fields - Comma-separated fields (e.g., success_count,failed_count,total_to_process)Workspace
#### Get Current Workspace
bash
GET /instantly/api/v2/workspaces/current
Custom Tags
#### Toggle Tag on Resource
bash
POST /instantly/api/v2/custom-tags/toggle-resource
Content-Type: application/json{ "tag_id": "tag_uuid", "resource_id": "campaign_or_account_id", "resource_type": "campaign" }
Pagination
Instantly uses cursor-based pagination with limit and starting_after:
bash
GET /instantly/api/v2/campaigns?limit=10&starting_after=cursor_value
Response includes pagination info:json
{
"items": [...],
"next_starting_after": "cursor_for_next_page"
}
Use next_starting_after value in the next request's starting_after parameter.Code Examples
JavaScript
javascript
const response = await fetch(
'https://api.maton.ai/instantly/api/v2/campaigns?limit=10',
{
headers: {
'Authorization': Bearer ${process.env.MATON_API_KEY}
}
}
);
const data = await response.json();
Python
python
import os
import requestsresponse = requests.get( 'https://api.maton.ai/instantly/api/v2/campaigns', headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}, params={'limit': 10} ) data = response.json()
Notes
Instantly API v2 uses snake_case for all field names
Lead custom variables must be string, number, boolean, or null (no objects/arrays)
The List Leads endpoint is POST (not GET) due to complex filtering requirements
Campaign status values: 0=draft, 1=active, 2=paused, 3=completed
Email verification may return pending status if it takes longer than 10 seconds
Warmup operations return background job IDs - poll the background jobs endpoint for status
IMPORTANT: When using curl commands, use curl -g when URLs contain brackets to disable glob parsing
IMPORTANT: When piping curl output to jq, environment variables may not expand correctly. Use Python examples instead. Error Handling
| Status | Meaning |
|--------|---------|
| 400 | Missing Instantly connection or invalid request |
| 401 | Invalid or missing Maton API key |
| 403 | Insufficient API key scopes |
| 429 | Rate limited |
| 4xx/5xx | Passthrough error from Instantly API |
Troubleshooting: API Key Issues
1. Check that the MATON_API_KEY environment variable is set:
bash
echo $MATON_API_KEY
2. Verify the API key is valid by listing connections:bash
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
``Troubleshooting: Invalid App Name
1. Ensure your URL path starts with
instantly. For example:Correct: https://api.maton.ai/instantly/api/v2/campaigns
Incorrect: https://api.maton.ai/api/v2/campaigns`Resources
π‘ Examples
# List campaigns
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/instantly/api/v2/campaigns?limit=10')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
π Tips & Best Practices
pending status if it takes longer than 10 secondscurl -g when URLs contain brackets to disable glob parsingjq, environment variables may not expand correctly. Use Python examples instead.