⏳ This skill is pending AI review.

Scores will appear once the review pipeline completes.

version unknown

cold-email-salesblink

@open-salesblink⭐ 22 stars

>

Choose how to use this skill

You do not need every option. Choose the path your AI client supports. The stable page stays the same; versioned files are immutable.

1. Native installer

This listing has no registered native installer command. Use the complete package or source fallback below, depending on what your client supports.

Do not guess an installer command or replace an existing version without reviewing the diff.

2. Complete package recommended

Download the ZIP when available. It includes SKILL.md plus the references, security notes and version metadata.

No complete ProSkills package is published for this listing yet.

3. Prompt-only

Copy the prompt above when the agent can read the stable page or when you want to adopt the workflow without installing a skill.

Need only the instruction file?

Download SKILL.md only if your client requires a single file. The complete ZIP is safer for a full installation because it preserves the references and release context.

No path installs or executes anything by itself. Your agent still needs access to the project files. Before updating, compare the installed version and review the diff.

—/10

// RATINGS

⭐GitHub Stars
⭐⭐ 22 on GitHubGitHub ↗

Growing

🟢ProSkills Score
—
📍

Not yet listed on ClawHub or SkillsMP

// README

SalesBlink Cold Email Outreach Skill

GitHub release Claude Desktop one-click install GitHub stars Last commit Release downloads Website License: MIT

Run cold email sequences and sales outreach on autopilot via the SalesBlink API. Works with any AI agent — Claude, Claude Code, Claude Desktop, ChatGPT, OpenClaw, Cursor, Codex, Hermes, and more. Install it as an agent skill, or use the one-click .mcpb bundle for MCPB-compatible hosts.


Install in 30 seconds

1. Get your API key (or sign up)

Grab your key from run.salesblink.io/account/integration/api, or use the salesblink_signup tool to get the public sign-up link.

2. Install the skill

Recommended: let your agent install it (copy-paste prompt)

Paste this into your AI agent and it will set everything up for you:

Set up the SalesBlink Cold Email agent skill from https://github.com/open-salesblink/skill
for me. Read the README and SKILL.md in that repo, then install the skill in this
environment using the method that fits you best.

Ask me for my SalesBlink API key (from
https://run.salesblink.io/account/integration/api), or use the salesblink_signup
tool to get the sign-up link if I don't have an account yet. Configure the API key
as SALESBLINK_API_KEY. Verify the setup works, then help me launch my first cold
email sequence: ask what product I'm selling and who I'm targeting, create the
list, contacts, templates, and sequence, and walk me through launching it.

Or install manually

Any agent (npx)

npx skills add open-salesblink/skill

Claude Code

/plugin marketplace add https://github.com/open-salesblink/skill
/plugin install cold-email-salesblink

Hermes

hermes skills tap add open-salesblink/skill
hermes skills install cold-email-salesblink

OpenClaw / ClawHub

openclaw skills install cold-email-salesblink

3. Set your API key

export SALESBLINK_API_KEY="key-****"

4. Start working

  • "Create a cold email sequence for my SaaS product"
  • "Add these leads to a new list and launch a campaign"
  • "Check analytics for opens and replies from last week"
  • "Run an inbox placement test for my template"

What you can do

  • Cold email campaigns — build sequences, write templates, and launch outreach
  • Lead management — create lists, import contacts in bulk, move and update leads
  • Sender management — connect Gmail/Outlook via OAuth; add SMTP/IMAP senders directly or in bulk from a CSV
  • Inbox & replies — read threads, reply to prospects, mark conversations
  • Analytics — track opens, clicks, replies, and sent events
  • Deliverability testing — run inbox placement tests across providers
  • Workspace & team management — users, roles, folders, and account config

Other platforms

Codex

codex plugin marketplace add https://github.com/open-salesblink/skill

Invoke by referencing the plugin namespace.

Cursor

git clone https://github.com/open-salesblink/skill.git

Load the plugin from the cloned directory in Cursor's plugin settings.

Gemini CLI

gemini extensions install https://github.com/open-salesblink/skill

Gemini CLI prompts for your SALESBLINK_API_KEY and stores it in the system keychain.

ChatGPT

ChatGPT connects via MCP — visit https://mcp.salesblink.io and add SalesBlink as an MCP connector, or use the .mcpb bundle below in an MCPB-compatible host.

MCP

Visit https://mcp.salesblink.io to connect via MCP.

Claude Desktop / MCP Bundle (.mcpb)

Download MCPB

⬇ Download cold-email-salesblink.mcpb — one-click install of this skill in MCPB-compatible hosts (e.g. Claude for macOS/Windows). Open the downloaded file and enter your SALESBLINK_API_KEY when prompted.

The bundle runs a local Node.js MCP server with hardened gateway tools plus the full bundled API reference. Source lives in mcpb/cold-email-salesblink/. To build it yourself instead of downloading:

cd mcpb/cold-email-salesblink
npm install --omit=dev
npm test                            # protocol smoke test (no API key needed)
npx @anthropic-ai/mcpb pack .       # produces cold-email-salesblink.mcpb

See mcpb/cold-email-salesblink/README.md for tools, configuration, and security details.

Note: All platforms above require the same SALESBLINK_API_KEY environment variable shown in Step 3.


API Quick Reference

Base URL

https://run.salesblink.io/api/public/v1.0.0

Authentication Pass your API key in the Authorization header with no "Bearer" prefix:

Authorization: key-****

Pagination

  • Most list endpoints: limit (max 100) and skip
  • Activity endpoints (/sent, /opens, /clicks, /replies): per_page (max 100) and page (1-indexed)

Always paginate — never assume a single request returns all data.

Error Handling

StatusMeaningAction
200SuccessCheck success field
400Bad requestRe-check payload structure against the reference file
401UnauthorizedVerify API key
403ForbiddenInsufficient permissions (role too low)
404Not foundVerify the ID / endpoint
409ConflictResource already exists or connection failed
429Rate limitedWait 60s, then retry
500Server errorRetry once after 10s

Quick Start: End-to-End Campaign

See skills/cold-email-salesblink/references/workflows.md for full examples. High-level flow:

  1. Create a list → POST /lists
  2. Add contacts → POST /contacts (batch up to 500, snake_case fields)
  3. Create templates → POST /templates (merge vars like {{first_name}})
  4. Fetch senders → GET /senders
  5. Create sequence → POST /sequences (steps: email → delay → email …)
  6. Launch → PATCH /sequences/:id with paused: false & launchTimingMode: "now"

Evaluations

The evals/evals.json file contains test scenarios covering list creation, bulk contact import, sequence creation, large CSV ingestion, inbox replies with CC, and paginated activity tracking.


Compatibility

  • Requires network access to run.salesblink.io
  • Supports any HTTP client (curl, Node.js fetch, Python requests, PowerShell, etc.)

License

MIT — © FUTUREBLINK Inc. See LICENSE.

// HOW IT'S BUILT

// FILES

20 files shipped with this skill. Inline text is the catalog copy. The upstream link is the source repository.

  • skills/cold-email-salesblink/SKILL.md14 KB564d9d622104upstream ↗
    ---
    name: cold-email-salesblink
    description: >
      Run cold email sequences on autopilot and manage full sales outreach campaigns via the SalesBlink API.
      Use this skill to build automated multi-step email campaigns (sequences), manage leads and email lists,
      create reusable templates with merge variables and spintax, connect Gmail/Outlook sending accounts via OAuth
      and SMTP/IMAP senders directly or by CSV,
      handle inbox replies, and track campaign analytics (opens, clicks, replies, sent).
      Also supports bulk contact imports, email deliverability testing (inbox placement / spam checks),
      sender warmup links, workspace/team management, and any HTTP request to the SalesBlink platform.
    compatibility: >
      Requires network access to run.salesblink.io and a SALESBLINK_API_KEY.
      Supports any HTTP client (curl, Node.js fetch, Python requests, PowerShell, etc.).
      No prior knowledge of SalesBlink is needed: the skill guides you through connecting email accounts,
      importing leads, writing templates, building sequences, launching campaigns, and monitoring deliverability.
    metadata:
      openclaw:
        requires:
          env:
            - SALESBLINK_API_KEY
        primaryEnv: SALESBLINK_API_KEY
    ---
    
    # SalesBlink Public REST API v1.0.0
    
    ## When to use this skill
    
    Use this skill when the user wants to:
    
    - Create, update, or manage email lists, sequences, templates, or senders
    - Add, update, move, or remove contacts/leads
    - Send or reply to emails via the inbox
    - Check campaign analytics (opens, clicks, replies, sent)
    - Set up outreach campaigns end-to-end
    - Manage workspaces, users, folders, or deliverability tests
    - Make any HTTP request to `https://run.salesblink.io/api/public/v1.0.0`
    
    ## Gotchas
    
    - **ID types matter**: Templates and contact archive use MongoDB ObjectId (24-char hex). All other entities use UUID v4.
    - **GET `/lists/:id` returns a single object**: The API returns the list object directly under `data`, including a `fields` array of its column names in snake_case.
    - **Sequence status filters differ by endpoint**: `GET /sequences` uses status values `running`, `paused`, `completed`, `needs-attention`. `POST /sequences/:id/status` uses `ACTIVE`, `PAUSED`, `STOPPED`, `ARCHIVED`. Do not mix them up.
    - **GET `/sequences/:id` returns the internal flowchart**: The response includes the full internal `flowchart` object, not a simplified step list. Use `flowchart` to inspect steps.
    - **POST `/sequences/:id/clone` returns `clonedSequenceId`**: The response shape is `{ success, data: { clonedSequenceId }, message }`, not `data.id` or `data.name`.
    - **OAuth `redirectUrl` is ignored**: The API does not use a custom `redirectUrl` for `/oauth/google` or `/oauth/outlook`. The response field is `data.auth_url`, not `data.url`.
    - **messageId** is the RFC822 Message-ID (e.g. `<[email protected]>`) or Microsoft Graph ID. **Crucial:** Always URL-encode this ID when using it as a path parameter (e.g. in `/inbox/:messageId/thread`). This is distinct from the internal UUID `id`.
    - **`senders` is a comma-separated string**, not an array. It can mix sender IDs and folder IDs — the server auto-detects each.
    - **Sequence `steps` fully replace on PATCH**. Send the complete desired array.
    - **Email steps accept `send_as: "new" | "followup"`**: `"followup"` replies in the lead's existing thread (`Re: <original subject>`); it is ignored on the first email step, which always starts a new thread. The stored value reads back as `flowchart.nodes[].data.send_as`.
    - **Verification flags are IRREVERSIBLE**: `verification`, `archive_invalid`, `archive_risky` on lists can only be turned ON, never OFF.
    - **Sequences default to paused**: If `paused` is omitted on create, it defaults to `true`.
    - **`launchTimingMode: "now"` starts in 5 minutes**, not instantly.
    - **Template attachments use FormData field `attachment`** (not `attachments`). Max 3 per template.
    - **Remove template attachments via `remove_attachments`** array of file **names**.
    - **GET `/senders/connect-link` returns a login link; it does not create a sender**. For Gmail and Outlook, use `/oauth/google` or `/oauth/outlook`, which return an `auth_url` the user must open in a browser; the sender is created automatically after OAuth completion. SMTP/IMAP senders can be added with `POST /senders/add-sender` (JSON) or `POST /senders/add-bulk-senders` (CSV, `multipart/form-data`, field `csvFile`); they connect in the background, so wait for `sendingEnabled: true` before using them in a sequence.
    - **Forward content is optional**: `POST /inbox/:messageId/forward` uses the original email body when `content` is omitted.
    - **Archiving is done via dedicated archive routes**: `PATCH /lists/:id`, `PATCH /templates/:id`, and `PATCH /sequences/:id` ignore the `archived` field. Use `PUT /lists/:id/archive`, `PUT /templates/:id/archive`, and `PUT /sequences/:id/archive` instead.
    - **Folder types matter**: General folders (created without a `type`) hold lists, templates, and sequences. `type: "email-sender"` folders hold email senders only. The API rejects a folder assignment to the wrong resource type.
    
    
    ## Base URL
    
    `https://run.salesblink.io/api/public/v1.0.0`
    
    ## Authentication
    
    This API uses a SalesBlink API key. Get or create an API key at `https://run.salesblink.io/account/integration/api`.
    
    Pass the key in every request as the `Authorization` header (no "Bearer" prefix):
    
    **Header:** `Authorization: key-****`
    
    ## Rate Limits
    
    | Method        | Limit | Window     | Applies To |
    | ------------- | ----- | ---------- | ---------- |
    | GET           | 30    | per minute | Most GET endpoints |
    | POST / PATCH  | 15    | per minute | POST and PATCH endpoints |
    | PUT (archive) | 10    | per minute | PUT and DELETE endpoints |
    | GET /signup-link | 250   | per day    | Public signup link (per IP) |
    
    On `429 Too Many Requests`: wait at least 60 seconds before retrying. For batch operations, insert a 4-second delay between requests.
    
    ## Public Signup
    
    **GET** `/signup-link`
    
    Get the public SalesBlink sign-up link. This is a public endpoint and does not require an API key. It returns a sign-up link to the SalesBlink web UI:
    
    **Response Body:**
    ```json
    {
      "success": true,
      "message": "Please sign up through the SalesBlink web UI.",
      "data": {
        "login_link": "https://run.salesblink.io/signup",
        "destination": "/signup",
        "purpose": "signup"
      }
    }
    ```
    
    **Rate Limit**: 5 requests per day per IP.
    
    ## Pagination
    
    Most list endpoints use `limit` (max 100) and `skip`. Activity endpoints (`/sent`, `/opens`, `/clicks`, `/replies`) use `per_page` (max 100) and `page` (1-indexed).
    
    Some endpoints support higher limits:
    - `/sequences/:id/leads` and `/leads/:id/activity` — max 500
    - `/sequences/:id/export` — max 50,000 (default 10,000)
    
    Always paginate. Never assume a single request returns all data.
    
    ## Endpoint Categories
    
    Read the relevant reference file before performing operations in that domain:
    
    - **Lists & contacts/leads** → [references/lists.md](references/lists.md) and [references/contacts.md](references/contacts.md)
      - Use these endpoints when the user wants to fetch or manage lists that contain leads/contacts. A list is a container for contacts/leads. Each contact/lead contains fields like email, first_name, last_name, phone, company_name, job_title, and custom fields. All contact field names sent to the API must be snake_case; requests with other casings are rejected. Contacts are added to lists in batches (up to 500 per request), can be moved between lists, updated, or removed.
    
    - **Email templates** → [references/templates.md](references/templates.md)
      - Use these endpoints when the user wants to create or manage reusable email templates. A template has a name, subject_line, and HTML content that supports merge variables like {{first_name}} and {{company}}. Templates can have up to 3 attachments and are referenced by sequences when building outreach steps.
    
    - **Sequences & email campaigns** → [references/sequences.md](references/sequences.md)
      - Use these endpoints when the user wants to create or manage automated email campaigns (sequences). A sequence connects lists (who to email), senders (which accounts send), and templates (what to send) into a timed step-by-step workflow. Steps alternate between email sends and delay periods. Sequences can be launched, paused, resumed, cloned, or archived.
    
    - **Senders, OAuth & warmup links** → [references/senders.md](references/senders.md)
      - Use these endpoints when the user wants to connect or manage email sending accounts. A sender is an email account (SMTP/IMAP or OAuth-connected Gmail/Outlook) that sends emails on behalf of sequences. Multiple senders can be assigned to a sequence. Senders can also be organized into folders. Warmup links are used in email warmup processes to improve deliverability.
    
    - **Inbox & replies** → [references/inbox.md](references/inbox.md)
      - Use these endpoints when the user wants to view or interact with email conversations. The inbox contains reply threads, sent emails, scheduled emails, and drafts. Each thread has a messageId. The user can reply to a lead's email, mark messages as read/unread, or classify outcomes.
    
    - **Activity tracking** → [references/activity.md](references/activity.md)
      - Use these endpoints when the user wants to query engagement events. The system tracks four event types: sent (emails sent), opens (emails opened), clicks (links clicked), and replies (responses received). Events can be filtered by sequence, recipient email, and date range. Also includes per-lead activity history.
    
    - **Analytics** → [references/analytics.md](references/analytics.md)
      - Use these endpoints when the user wants aggregated campaign analytics: overall stats across all sequences, day-wise breakdowns, lead-level stats, and per-mailbox/sender stats.
    
    - **Blocklist / unsubscribes** → [references/blocklist.md](references/blocklist.md)
      - Use these endpoints when the user wants to manage account-level unsubscribes and blocked emails/domains. The public API uses `/unsubscribe` routes for all blocklist operations.
    
    - **Users & workspaces** → [references/organization.md](references/organization.md)
      - Use these endpoints when the user wants to manage team membership or workspaces. A workspace is an account boundary. Users have roles (client, user, admin, developer). Only owners and admins can invite users or create workspaces.
    
    - **Folders** → [references/folders.md](references/folders.md)
      - Use these endpoints when the user wants to organize resources into folders. Folders have a type (`general` or `email-sender`) and group related resources together for easier management.
    
    - **Domains & signatures** → [references/account-config.md](references/account-config.md)
      - Use these endpoints when the user wants to view account-level configuration. Custom tracking domains are used for click tracking in emails (returns both verified and unverified domains with DNS setup instructions and "not verified" tags). Signatures are appended to outgoing emails.
    
    - **DFY domains & mailboxes** → [references/dfy.md](references/dfy.md)
      - Use these endpoints when the user wants to purchase domains and provision mailboxes through the Done-For-You service. Start with `/domains/search` to find available domains, then place an order with Google Workspace, Outlook, or Azure mailboxes. Supports buying new domains or connecting existing ones.
    
    - **Billing & payment methods** → [references/billing.md](references/billing.md)
      - Use these endpoints when the user wants to add or remove a saved payment card. Returns magic login links to the billing page.
    
    - **API Key Management** → [references/api-keys.md](references/api-keys.md)
      - Use these endpoints when the user wants to manage API keys. Users can list all keys, create new keys, refresh an existing key (which generates a new one and revokes the old one), or delete a key.
    
    - **Reports** → [references/reports.md](references/reports.md)
      - Use these endpoints when the user wants to fetch aggregated activity reports over a date range. Reports combine data across campaigns into summary views.
    
    - **Inbox placement tests** → [references/inbox-placement.md](references/inbox-placement.md)
      - Use these endpoints when the user wants to test email deliverability. An inbox placement test sends a test email to seed email addresses across providers (Gmail, Outlook, etc.) and reports whether the email landed in inbox, spam, promotions, or other tabs. Tests can be one-time or recurring.
    
    - **End-to-end workflow examples** → [references/workflows.md](references/workflows.md)
      - Use this reference when the user wants to set up a complete outreach campaign from scratch. It shows the full chain: create list → add contacts → create templates → fetch senders → create sequence → launch.
    
    ## Error Handling
    
    Always check the `success` boolean in the response body. A `200` status can still return `{ success: false, message: "..." }`.
    
    | Status | Meaning      | Action                                                |
    | ------ | ------------ | ----------------------------------------------------- |
    | 200    | Success      | Check `success` field                                 |
    | 400    | Bad request  | Re-check payload structure against the reference file |
    | 401    | Unauthorized | Verify API key                                        |
    | 403    | Forbidden    | Insufficient permissions (role too low)               |
    | 404    | Not found    | Verify the ID / endpoint                              |
    | 409    | Conflict     | Resource already exists or connection failed          |
    | 429    | Rate limited | Wait 60s, then retry                                  |
    | 500    | Server error | Retry once after 10s                                  |
    
  • skills/cold-email-salesblink/references/account-config.md3.0 KB776af6c93527upstream ↗
    # Account Config — Domains & Signatures
    
    ## Endpoints
    
    | Endpoint | Method | Description |
    |----------|--------|-------------|
    | `/account/verify` | GET | Verify API key and return account info |
    | `/domains` | GET | List custom tracking domains (both verified and unverified with DNS setup instructions) |
    | `/signatures` | GET | List email signatures |
    
    ## Verify Account
    
    **GET** `/account/verify`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Returns account info and confirms the API key is valid.
    
    ## Domains
    
    **GET** `/domains`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Query Parameters:
    - `owned_by` (optional string): Filter by owner email (admin/owner only). Also accepts `ownedby`, `userID`, `uid`, or `user`.
    
    List custom tracking domains for the account. Both verified and unverified domains are returned.
    
    ### Verification Status & Tag
    - **Verified domains**: have `verified: true`, `status: "verified"`, `tag: "verified"`, and `instructions: null`.
    - **Unverified domains**: have `verified: false`, `status: "not verified"`, `tag: "not verified"`, and include DNS setup `instructions` (`record_type`, `host`, `value`, `message`) to guide DNS configuration.
    
    ### DNS Instructions Details
    - **Root/Apex domains** (e.g. `example.com`): require an `A` record with Host `@` pointing to `143.244.213.24`.
    - **Subdomains** (e.g. `track.example.com`): require a `CNAME` record with Host (e.g. `track`) pointing to `cname.salesblink.io` (for click-tracker), `meet.salesblink.io` (for meet-link), or `run.salesblink.io` (for white-label).
    
    ### Response Example
    
    ```json
    {
      "success": true,
      "message": "Custom domains retrieved successfully",
      "data": [
        {
          "id": "64f1a2b3c4d5e6f7a8b9c0d1",
          "_id": "64f1a2b3c4d5e6f7a8b9c0d1",
          "domain": "track.mycompany.com",
          "type": "click-tracker",
          "verified": false,
          "status": "not verified",
          "tag": "not verified",
          "instructions": {
            "record_type": "CNAME",
            "host": "track",
            "value": "cname.salesblink.io",
            "message": "Add a CNAME record for \"track.mycompany.com\" with Host \"track\" pointing to \"cname.salesblink.io\". It can take up to 24 hours for DNS changes to propagate."
          },
          "uid": "user_123",
          "owned_by": "[email protected]"
        },
        {
          "id": "64f1a2b3c4d5e6f7a8b9c0d2",
          "_id": "64f1a2b3c4d5e6f7a8b9c0d2",
          "domain": "clicks.mycompany.com",
          "type": "click-tracker",
          "verified": true,
          "status": "verified",
          "tag": "verified",
          "instructions": null,
          "uid": "user_123",
          "owned_by": "[email protected]"
        }
      ]
    }
    ```
    
    ## Signatures
    
    **GET** `/signatures`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    List email signatures.
    
    > Signature IDs can be referenced when adding senders via the `signature_id` field. You can pass either the signature ID or its name.
    
    
    
    Note: For GET domains, GET signatures, and GET warmup-links, you can use `owned_by`, `ownedby`, `userID`, `uid`, or `user` to filter by user.
    
  • skills/cold-email-salesblink/references/activity.md2.0 KB20f0d42b5549upstream ↗
    # Activity Tracking
    
    ## Endpoints
    
    | Endpoint | Method | Description |
    |----------|--------|-------------|
    | `/sent` | GET | Log of all sent emails |
    | `/opens` | GET | Email open events |
    | `/clicks` | GET | Link click events |
    | `/replies` | GET | Reply events |
    | `/leads/:id/activity` | GET | Activity history for a specific lead |
    
    ## Query Parameters
    
    The `/sent`, `/opens`, `/clicks`, and `/replies` endpoints support:
    
    | Param | Type | Description |
    |-------|------|-------------|
    | `per_page` | integer | Max 100 |
    | `page` | integer | 1-indexed |
    | `sequence_id` | string | Filter by sequence UUID |
    | `recipient_email_address` | string | Filter by email address |
    | `since` | integer | Filter events after this timestamp (ms) |
    | `from` | integer | Start of date range (timestamp, ms) |
    | `to` | integer | End of date range (timestamp, ms) |
    
    > Use `per_page` and `page` for these activity endpoints — not `limit`/`skip`.
    > `/leads/:id/activity` uses `limit`/`skip` instead (see Lead Activity section below).
    
    ## Response Format
    
    Each event includes:
    ```json
    {
      "id": "...",
      "time": 1715000000000,
      "message": "Sent",
      "type": "outreach",
      "sequence": "sequence-uuid",
      "email": "[email protected]",
      "sequence_name": "Campaign Name"
    }
    ```
    
    For clicks and replies, `template_name` is also included.
    
    ## Examples
    
    **GET** `/opens?sequence_id=SEQ_ID&per_page=100&page=1`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    **GET** `/replies?since=TIMESTAMP_30_DAYS_AGO&per_page=100`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    ## Lead Activity
    
    **GET** `/leads/:id/activity`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Query params:
    
    | Param | Type | Description |
    |-------|------|-------------|
    | `sequence_id` | string | Filter by sequence UUID |
    | `from` | integer | Start of date range (timestamp, ms) |
    | `to` | integer | End of date range (timestamp, ms) |
    | `limit` | integer | Maximum number of results (max 500) |
    | `skip` | integer | Offset for pagination |
    
    Returns the activity history for a specific lead across sequences.
    
  • skills/cold-email-salesblink/references/analytics.md2.0 KBa067ad5023bcupstream ↗
    # Analytics
    
    Cross-campaign and account-level analytics endpoints.
    
    ## Endpoints
    
    | Endpoint | Method | Description |
    |----------|--------|-------------|
    | `/analytics/overall` | GET | Overall stats across all sequences |
    | `/analytics/daily` | GET | Day-wise overall stats |
    | `/analytics/lead-stats` | GET | Lead-level stats |
    | `/analytics/mailbox-stats` | GET | Overall mailbox stats |
    
    ## Overall Analytics
    
    **GET** `/analytics/overall`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Query params:
    
    | Param | Type | Description |
    |-------|------|-------------|
    | `from` | integer | Start date timestamp (milliseconds) |
    | `to` | integer | End date timestamp (milliseconds) |
    
    Returns aggregated stats (sent, opens, clicks, replies, bounces, unsubscribes) across all sequences.
    
    ## Daily Analytics
    
    **GET** `/analytics/daily`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Query params:
    
    | Param | Type | Description |
    |-------|------|-------------|
    | `from` | integer | Start date timestamp (milliseconds) |
    | `to` | integer | End date timestamp (milliseconds) |
    | `timezone` | string | IANA timezone (e.g. `America/New_York`) |
    
    Returns day-wise aggregated stats.
    
    ## Lead Stats
    
    **GET** `/analytics/lead-stats`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Query params:
    
    | Param | Type | Description |
    |-------|------|-------------|
    | `from` | integer | Start date timestamp (milliseconds) |
    | `to` | integer | End date timestamp (milliseconds) |
    | `limit` | integer | Maximum number of results (default: 100) |
    | `skip` | integer | Offset for pagination |
    
    Returns per-lead activity statistics.
    
    ## Mailbox Stats
    
    **GET** `/analytics/mailbox-stats`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Query params:
    
    | Param | Type | Description |
    |-------|------|-------------|
    | `from` | integer | Start date timestamp (milliseconds) |
    | `to` | integer | End date timestamp (milliseconds) |
    | `limit` | integer | Maximum number of results (default: 100) |
    | `skip` | integer | Offset for pagination |
    
    Returns per-sender/mailbox performance statistics.
    
  • skills/cold-email-salesblink/references/api-keys.md2.1 KB4fe42e98f673upstream ↗
    # API Key Management
    
    ## Endpoints
    
    | Endpoint | Method | Description |
    |----------|--------|-------------|
    | `/keys` | GET | List all API keys for the account |
    | `/keys/create-link` | GET | Get a magic login link to the API keys page in the SalesBlink web UI |
    | `/keys/:id/refresh-link` | GET | Get a magic login link to refresh an API key in the SalesBlink web UI |
    | `/keys/:id` | DELETE | Delete an API key |
    
    ## Get API Keys
    
    **GET** `/keys`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Returns a list of all API keys associated with the account.
    
    ## Get API Key Creation Link
    
    **GET** `/keys/create-link`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    > **Important**: Creating an API key through this API gateway is no longer supported. **GET** `/keys/create-link` returns a magic login link to the API keys page in the SalesBlink web UI:
    
    ```json
    {
      "success": true,
      "message": "Please manage API keys through the SalesBlink web UI.",
      "data": {
        "login_link": "https://run.salesblink.io/magic?token=...&redirect=%2Faccount%2Fintegration%2Fapi",
        "destination": "/account/integration/api",
        "purpose": "manage_api_keys"
      }
    }
    ```
    
    ## Get API Key Refresh Link
    
    **GET** `/keys/:id/refresh-link`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    > **Important**: Refreshing an API key through this API gateway is no longer supported. **GET** `/keys/:id/refresh-link` returns a magic login link to the API keys page in the SalesBlink web UI:
    
    ```json
    {
      "success": true,
      "message": "Please refresh API keys through the SalesBlink web UI.",
      "data": {
        "login_link": "https://run.salesblink.io/magic?token=...&redirect=%2Faccount%2Fintegration%2Fapi",
        "destination": "/account/integration/api",
        "purpose": "manage_api_keys"
      }
    }
    ```
    
    ## Delete API Key
    
    **DELETE** `/keys/:id`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Deletes the specified API key.
    
    > [!IMPORTANT]
    > - You cannot delete the API key you are currently using.
    > - At least one API key is required per account. If you want to replace your only key, use the Refresh endpoint instead.
    
  • skills/cold-email-salesblink/references/billing.md1.1 KB1da2348fba61upstream ↗
    # Billing & Payment Methods
    
    ## Add Card Login Link
    
    **GET** `/billing/add-card-link`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Generates a time-limited magic login link that redirects the user to the billing page where they can add a payment card.
    
    Response:
    ```json
    {
      "success": true,
      "message": "Add card login link generated successfully",
      "data": {
        "login_link": "https://run.salesblink.io/magic?token=...&redirect=%2Faccount%2Fbilling%3Ftab%3Dcard",
        "destination": "/account/billing?tab=card",
        "purpose": "add_card"
      }
    }
    ```
    
    ## Remove Card Login Link
    
    **GET** `/billing/remove-card-link`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Generates a time-limited magic login link that redirects the user to the billing page where they can remove their saved payment card.
    
    Response:
    ```json
    {
      "success": true,
      "message": "Remove card login link generated successfully",
      "data": {
        "login_link": "https://run.salesblink.io/magic?token=...&redirect=%2Faccount%2Fbilling%3Ftab%3Dcard",
        "destination": "/account/billing?tab=card",
        "purpose": "remove_card"
      }
    }
    ```
    
  • skills/cold-email-salesblink/references/blocklist.md2.4 KB341225931882upstream ↗
    # Blocklist / Unsubscribe Management
    
    Manage account-level unsubscribes and blocklisted emails/domains.
    
    ## Endpoints
    
    | Endpoint | Method | Description |
    |----------|--------|-------------|
    | `/unsubscribe` | GET | List blocked emails and domains |
    | `/unsubscribe` | POST | Add emails/domains to the blocklist |
    | `/unsubscribe/remove` | POST | Remove emails/domains from the blocklist |
    | `/unsubscribe/:id` | DELETE | Remove a single blocklist entry by ID |
    | `/unsubscribe` | DELETE | Delete all blocklist entries |
    | `/unsubscribe/check` | GET | Check if an email is blocked |
    
    ## List Blocklist
    
    **GET** `/unsubscribe`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Query params:
    
    | Param | Type | Description |
    |-------|------|-------------|
    | `limit` | integer | Maximum number of results (default: 50, capped at 100) |
    | `skip` | integer | Offset for pagination — must be a multiple of `limit` (e.g. with `limit=50` use `skip=0`, `50`, `100`, …); non-multiples are rejected with a 400 error |
    | `search` | string | Search query |
    | `type` | string | Filter by entry type: `email` or `domain` |
    
    ## Add to Blocklist
    
    **POST** `/unsubscribe`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    {
      "emails": ["[email protected]", "competitor.com"]
    }
    ```
    
    | Field | Type | Req | Description |
    |-------|------|-----|-------------|
    | `emails` | string[] | ✅ | Array of emails or domains to block |
    
    ## Remove from Blocklist
    
    **POST** `/unsubscribe/remove`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    {
      "emails": ["[email protected]", "competitor.com"]
    }
    ```
    
    | Field | Type | Req | Description |
    |-------|------|-----|-------------|
    | `emails` | string[] | ✅ | Array of emails or domains to unblock |
    
    ## Delete Blocklist Entry by ID
    
    **DELETE** `/unsubscribe/:id`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    ## Delete All Blocklist Entries
    
    **DELETE** `/unsubscribe`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    > Use with caution — this removes every entry in the account blocklist.
    
    ## Check Blocklist
    
    **GET** `/unsubscribe/[email protected]`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Query params:
    
    | Param | Type | Description |
    |-------|------|-------------|
    | `email` | string | Email address to check |
    
    Returns whether the email is currently blocked.
    
  • skills/cold-email-salesblink/references/contacts.md5.9 KB6c78fee6ab63upstream ↗
    # Contacts & Leads
    
    ## Endpoints
    
    | Endpoint | Method | Description |
    |----------|--------|-------------|
    | `/lists/:id/leads` | GET | Get leads in a list (paginated, supports `sequence` + `status` filters) |
    | `/contacts` | POST | Add up to 500 leads to a list |
    | `/contacts/remove` | POST | Remove a single lead by email from a list |
    | `/leads/:id` | PATCH | Update lead fields |
    | `/leads/:id/move` | PUT | Move a lead to a different list |
    | `/contacts/:id/archive` | PUT | Archive or unarchive a contact |
    | `/leads/activity` | GET | Get activity history for a lead by email query parameter |
    | `/leads/:id/activity` | GET | Get activity history for a lead by ID |
    | `/leads/:id/unsubscribe` | POST | Globally unsubscribe a lead from all sequences |
    
    ## Get Lead Activity by ID
    
    **GET** `/leads/:id/activity`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Query params: `sequence_id`, `from`, `to` (Unix ms), `limit` (max 500), `skip`
    
    Response: `{ success, data: [...], lead, count, skip, limit }`
    
    ## Get Lead Activity by Email
    
    **GET** `/leads/[email protected]`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Query params: `email` (required), `sequence_id`, `from`, `to` (Unix ms), `limit` (max 500), `skip`
    
    > Use this endpoint when you have the lead's email address but not the internal lead ID. Response shape is the same as `/leads/:id/activity`.
    
    ## Globally Unsubscribe Lead
    
    **POST** `/leads/:id/unsubscribe`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Adds the lead to the global unsubscribe list and cancels pending tasks across all sequences.
    
    ## Get Leads
    
    **GET** `/lists/:id/leads?limit=100&skip=0`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Query params: `limit` (max 100), `skip`, `search`, `archived`, `sort` (`asc`/`desc`), `sequence`, `status`
    
    The `status` filter (`not_contacted`, `contacted`, `opened`, `clicked`, `replied`, `bounced`, `unsubscribed`) works with or without `sequence`. Without it, the status matches across all sequences (e.g. `replied` = replied in any sequence); `not_contacted` matches leads with no activity in any sequence. Omit `status` (or use `all`) to return the full list.
    
    ## Add Contacts
    
    **POST** `/contacts`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    {
      "list_id": "a1b2c3d4-e5f6-7890-abcd-abcdef123456",
      "contacts": [
        {
          "email": "[email protected]",
          "first_name": "John",
          "last_name": "Doe",
          "phone": "+1234567890",
          "company_name": "Acme Inc",
          "job_title": "VP Sales",
          "custom_field": "any value"
        }
      ],
      "remove_duplicates": true
    }
    ```
    
    | Field | Type | Req | Description |
    |-------|------|-----|-------------|
    | `list_id` | string | ✅ | List UUID to add leads to |
    | `contacts` | object[] | ✅ | Array of lead objects (**max 500 per request**) |
    | `remove_duplicates` | boolean | | Remove duplicate emails after insert |
    
    Each contact object:
    
    | Field | Type | Req | Description |
    |-------|------|-----|-------------|
    | `email` | string | ✅ | Lead's email address |
    | `first_name` | string | | First name |
    | `last_name` | string | | Last name |
    | `phone` | string | | Phone number |
    | `company_name` | string | | Company name |
    | `job_title` | string | | Job title |
    | `starred` | boolean | | Mark/unmark the contact as starred. This is a contact setting, not a data field/column. |
    | _(any key)_ | string | | Custom fields are supported |
    
    > **Field naming**: All field names **must be snake_case** (`first_name`, `last_name`, `email`, `company_name`, `lead_score`). Requests with non-snake_case field names are rejected with a 400 error. New custom fields are automatically added to the list's columns. The `starred` boolean is a contact setting and is NOT added as a list column. Use `PUT /contacts/:id/archive` to archive/unarchive contacts.
    
    ## Remove Contact
    
    **POST** `/contacts/remove`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    {
      "list_id": "a1b2c3d4-e5f6-7890-abcd-abcdef123456",
      "email": "[email protected]"
    }
    ```
    
    | Field | Type | Req | Description |
    |-------|------|-----|-------------|
    | `list_id` | string | ✅ | List UUID |
    | `email` | string | ✅ | Email address of the lead to remove |
    
    ## Update Lead
    
    **PATCH** `/leads/:id` (UUID)
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    {
      "first_name": "Updated",
      "last_name": "Name",
      "job_title": "CTO",
      "starred": true
    }
    ```
    
    Any standard or custom contact fields can be updated. All field names **must be snake_case**; requests with non-snake_case field names are rejected with a 400 error. System fields (`_id`, `id`, `list_id`, `account_id`, `user_id`, `accuracy`, `provider`, `custom_fields`, `removed_sequences`, `verification_required`, `archive_invalid_contacts`, `archive_risky_contacts`, `processing`, `completed`, `completedAt`, `last_modified`, `created_date`, `verification_blocked`, `didOpen`, `didClick`, `didReply`, `contactStats`, `retryCount`, `esg_name`, `archived`, `deleted`) **cannot** be modified.
    
    Use the dedicated `starred` boolean property to mark/unmark the lead as starred; `starred` is a contact setting and is NOT added as a list column. Use `PUT /contacts/:id/archive` to archive/unarchive contacts.
    
    If updating `email`, it is automatically lowercased.
    
    ## Move Lead
    
    **PUT** `/leads/:id/move` (UUID)
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    { "list_id": "destination_list_uuid" }
    ```
    
    | Field | Type | Req | Description |
    |-------|------|-----|-------------|
    | `list_id` | string | ✅ | Destination list UUID |
    
    ## Archive Contact
    
    **PUT** `/contacts/:id/archive`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    { "archived": true }
    ```
    
    > ⚠️ **The `:id` here is a MongoDB ObjectId** (24-char hex), NOT a UUID. This is the only contact endpoint that uses ObjectId.
    
  • skills/cold-email-salesblink/references/dfy.md3.7 KB9c216ee55f30upstream ↗
    # Done-For-You (DFY) — Domains & Mailboxes
    
    Use these endpoints to search domains and view existing Done-For-You orders.
    
    > **Important**: Placing new DFY orders and adding mailboxes to an existing order must be done through the SalesBlink web UI. The API supports searching domains, listing orders, and canceling a mailbox (which returns a billing management link).
    
    ## Endpoints
    
    | Endpoint                                    | Method | Description                                        |
    | ------------------------------------------- | ------ | -------------------------------------------------- |
    | `/domains/search`                           | GET    | Search available .com domains for DFY purchase     |
    | `/dfy/orders`                               | GET    | List all DFY orders                                |
    | `/dfy/order-link`                           | GET    | Get a magic login link to place a DFY order        |
    | `/dfy/orders/:orderId/mailbox-link`         | GET    | Get a magic login link to add mailboxes to an order |
    | `/dfy/orders/:orderId/mailboxes/:mailboxId/cancel-link` | GET | Get a magic login link to cancel a mailbox (billing management) |
    
    ## Placing Orders and Adding Mailboxes
    
    `GET /dfy/order-link` and `GET /dfy/orders/:orderId/mailbox-link` return magic login links to the relevant page in the SalesBlink web UI:
    
    **GET** `/dfy/order-link` response:
    
    ```json
    {
      "success": true,
      "message": "Please place Done-For-You orders through the SalesBlink web UI.",
      "data": {
        "login_link": "https://run.salesblink.io/magic?token=...&redirect=%2Foutreach%2Femail-senders%3Faddsenders%3Dtrue",
        "destination": "/outreach/email-senders?addsenders=true",
        "purpose": "place_dfy_order"
      }
    }
    ```
    
    **GET** `/dfy/orders/:orderId/mailbox-link` response:
    
    ```json
    {
      "success": true,
      "message": "Please manage mailbox subscriptions through the SalesBlink web UI.",
      "data": {
        "login_link": "https://run.salesblink.io/magic?token=...&redirect=%2Faccount%2Fbilling%3Ftab%3Dsubscriptions",
        "destination": "/account/billing?tab=subscriptions",
        "purpose": "manage_subscriptions"
      }
    }
    ```
    
    ## Search Domains
    
    **GET** `/domains/search`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Query params:
    - `keyword` (required) — domain name to search (e.g. `mybrand` or `mybrand.com`). Only `.com` domains are supported.
    
    Returns up to 10 available `.com` domains with pricing and workspace availability.
    
    Response:
    ```json
    {
      "success": true,
      "message": "Domain search completed successfully",
      "data": [
        {
          "domain": "mybrand.com",
          "price": 15.00,
          "status": "available",
          "google_workspace_available": true,
          "ms365_workspace_available": true
        }
      ]
    }
    ```
    
    ## List DFY Orders
    
    **GET** `/dfy/orders`
    
    Headers:
    
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Response:
    
    ```json
    {
      "success": true,
      "message": "DFY orders retrieved successfully",
      "data": [
        {
          "id": "...",
          "type": "google",
          "status": "paid",
          "amount": 23.00,
          "domains": [...],
          "nameservers": null
        }
      ]
    }
    ```
    
    ## Get Mailbox Cancel Link
    
    **GET** `/dfy/orders/:orderId/mailboxes/:mailboxId/cancel-link`
    
    Headers:
    
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Returns a billing management login link because subscription changes must be managed from the web UI.
    
    Response:
    
    ```json
    {
      "success": true,
      "message": "Please manage your mailbox subscription from the billing page.",
      "data": {
        "login_link": "https://run.salesblink.io/magic?token=...&redirect=%2Faccount%2Fbilling%3Ftab%3Dsubscriptions",
        "destination": "/account/billing?tab=subscriptions",
        "purpose": "manage_subscriptions"
      }
    }
    ```
    
    To place a new DFY order or add mailboxes to an order, open the SalesBlink app and go to the email-sender connection flow.
    
  • skills/cold-email-salesblink/references/folders.md2.3 KB997a728f0960upstream ↗
    # Folders
    
    SalesBlink has two kinds of folders:
    
    - **General folders** — used for lists, templates, and sequences.
    - **Email-sender folders** — used only for email senders.
    
    Only include `type` when creating an email-sender folder. For general folders (lists, templates, sequences), do not include the `type` field.
    
    ## Endpoints
    
    | Endpoint   | Method | Description     |
    | ---------- | ------ | --------------- |
    | `/folders` | GET | List folders — supports `type` filter: `all`, `general`, or `email-sender` |
    | `/folders` | POST | Create a folder — returns `{ success: true }` only |
    
    ## Get Folders
    
    **GET** `/folders`
    
    Headers:
    
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Query params: `limit` (max 100), `skip`, `search`, `type`
    
    | `type` value | Result |
    | ------------ | ------ |
    | `all` | All folders (default if omitted) |
    | `general` | Non-email-sender folders only |
    | `email-sender` | Email-sender folders only |
    
    ## Create Folder
    
    **POST** `/folders`
    
    Headers:
    
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    
    ```json
    {
      "name": "Q1 Campaigns"
    }
    ```
    
    For an email-sender folder:
    
    ```json
    {
      "name": "Warm Senders",
      "type": "email-sender"
    }
    ```
    
    | Field  | Type   | Req | Description                                               |
    | ------ | ------ | --- | --------------------------------------------------------- |
    | `name` | string | ✅  | Folder name                                               |
    | `type` | string |     | Only include this field when creating an email-sender folder. For general folders, do not include this field. |
    
    > **Response:** The API returns `{ success: true }` only. It does not return the created folder object.
    
    > Only `"email-sender"` is accepted as a `type` value. Any other value is rejected.
    
    ## Folder assignment rules
    
    - Lists, templates, and sequences can only be placed in **general folders** (folders created without a `type`).
    - Email senders can only be placed in **email-sender folders** (folders created with `type: "email-sender"`).
    - Use `PATCH /lists/:id`, `PATCH /templates/:id`, or `PATCH /sequences/:id` with `folder` to move a list, template, or sequence into a general folder (or pass an empty string to remove it from its folder).
    - Use `PATCH /senders/:id` with `folder` to move an email sender into an email-sender folder (or pass an empty string to remove it from its folder).
    
  • skills/cold-email-salesblink/references/inbox-placement.md6.0 KB12641df70519upstream ↗
    # Inbox Placement Tests
    
    ## Endpoints
    
    | Endpoint | Method | Description |
    |----------|--------|-------------|
    | `/inbox-placement` | GET | List deliverability tests |
    | `/inbox-placement` | POST | Create a new deliverability test |
    | `/inbox-placement/:id/pause` | PUT | Pause an active **recurring** test |
    | `/inbox-placement/:id` | DELETE | Delete a test |
    
    ## Get Tests
    
    **GET** `/inbox-placement`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Query params:
    
    | Param | Type | Description |
    |-------|------|-------------|
    | `search` | string | Filter by test name (case-insensitive) |
    | `status` | string | Filter by status: `pending`, `running`, `completed`, `stopped` |
    | `mode` | string | Filter by mode: `one-time`, `recurring` |
    | `ownedBy` | string | Filter by user ID |
    | `limit` | integer | Page size (default: 10) |
    | `skip` | integer | Offset (default: 0) |
    | `sortBy` | string | Sort field (default: `created_at`) |
    | `sortType` | integer | `-1` for descending, `1` for ascending |
    
    > Note: filtering by `status=completed` excludes recurring tests since they never truly complete.
    
    ## Create Test
    
    **POST** `/inbox-placement`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    | Field | Type | Req | Description |
    |-------|------|-----|-------------|
    | `name` | string | ✅ | Test name (min 3 characters) |
    | `mode` | string | ✅ | `"one-time"` or `"recurring"` |
    | `source` | string | ✅ | `"from-salesblink"` or `"from-outside"` |
    | `email_senders` | array | ✅* | Array of senders/folders to test from (see format below). Use `sender_id` for a legacy single sender instead. |
    | `sender_id` | string | ✅* | Legacy single sender UUID. Do not use together with `email_senders`. |
    | `content_type` | string | ✅* | `"custom"`, `"sequence"`, or `"template"` (required when `source="from-salesblink"` or `mode="recurring"`) |
    | `subject` | string | ✅* | Email subject (required when `content_type="custom"`) |
    | `body` | string | ✅* | Email HTML body (required when `content_type="custom"`) |
    | `sequence_id` | string | ✅* | Sequence UUID (required when `content_type="sequence"`) |
    | `template_id` | string | ✅* | Template ObjectId (required when `content_type="sequence"` or `"template"`) |
    | `schedule_day` | integer | ✅* | Day of week: `0`=Sunday through `6`=Saturday (required when `mode="recurring"`) |
    | `plainText` | boolean | | Send as plain text instead of HTML. |
    | `tracking_uuid` | string | | Optional UUID for `from-outside` tests. Auto-generated if omitted. |
    
    #### `email_senders` array format
    
    Each item in `email_senders` must include these fields:
    
    | Sub-field | Type | Description |
    |-----------|------|-------------|
    | `key` | string | UUID of the folder or sender. For folders this is the folder UUID; for senders this is the sender UUID. Same as `value`. |
    | `value` | string | UUID of the folder or sender (same as `key`). The UUID used by the server. |
    | `label` | string | Human-readable label, e.g. folder name or sender email address. |
    | `serviceName` | string | Selection type. **MUST be `"folder"`** for folders. For individual senders use any value other than `"folder"` (commonly the provider name). |
    
    You can mix folders and individual senders in the same array. Folders are expanded server-side into all senders they contain, and duplicates are automatically removed.
    
    > *Field requirement depends on `source`, `mode`, and `content_type` values.
    
    **Behavior:**
    - **One-time tests** run ~2 minutes after creation by default.
    - **Recurring tests** run weekly on the specified `schedule_day` at 09:00 UTC.
    - **`from-outside` tests** return `seed_emails` in the response — these are the addresses the user must send to.
    - **`from-salesblink` tests** send automatically using the selected sender.
    
    **V1 Wrapper behavior:** When `source="from-salesblink"` is provided without `content_type`:
    - If `subject` and `body` are present → `content_type` becomes `"custom"`
    - Otherwise → `content_type` becomes `"sequence"` with `sequence_id: "from_api"`
    
    ### Example: One-time custom content test with multiple senders
    
    **POST** `/inbox-placement`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    {
      "name": "Gmail Deliverability Check",
      "mode": "one-time",
      "source": "from-salesblink",
      "email_senders": [
        {
          "key": "folder-uuid-here",
          "value": "folder-uuid-here",
          "label": "Sales Team Senders",
          "serviceName": "folder"
        },
        {
          "key": "sender-uuid-here",
          "value": "sender-uuid-here",
          "label": "[email protected]",
          "serviceName": "gmail"
        }
      ],
      "content_type": "custom",
      "subject": "Hello from SalesBlink",
      "body": "<p>This is a test email.</p>"
    }
    ```
    
    ### Example: Recurring sequence-based test
    
    **POST** `/inbox-placement`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    {
      "name": "Weekly Sequence Check",
      "mode": "recurring",
      "source": "from-salesblink",
      "email_senders": [
        {
          "key": "sender-uuid-here",
          "value": "sender-uuid-here",
          "label": "[email protected]",
          "serviceName": "gmail"
        }
      ],
      "content_type": "sequence",
      "sequence_id": "sequence-uuid-here",
      "template_id": "507f1f77bcf86cd799439011",
      "schedule_day": 1
    }
    ```
    
    ### Example: From-outside test (returns seed emails)
    
    **POST** `/inbox-placement`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    {
      "name": "External Send Test",
      "mode": "one-time",
      "source": "from-outside"
    }
    ```
    
    Response for `from-outside`:
    ```json
    {
      "success": true,
      "data": { "id": "...", "tracking_uuid": "...", ... },
      "seed_emails": ["[email protected]", "[email protected]", ...]
    }
    ```
    
    ## Pause Test
    
    **PUT** `/inbox-placement/:id/pause`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Only works on **recurring** tests. Sets status to `stopped` and clears scheduling.
    
    ## Delete Test
    
    **DELETE** `/inbox-placement/:id`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Deletes the test and all associated tracking tasks.
    
  • skills/cold-email-salesblink/references/inbox.md5.7 KBd8a921fabc36upstream ↗
    # Inbox & Outreach
    
    ## Endpoints
    
    | Endpoint                   | Method | Description                                     |
    | -------------------------- | ------ | ----------------------------------------------- |
    | `/inbox`                   | GET    | Retrieve inbox threads                          |
    | `/inbox/:messageId/thread` | GET    | Get all messages in a specific thread           |
    | `/inbox/:messageId/reply`  | POST   | Reply to a lead's email                         |
    | `/inbox/:messageId/forward` | POST   | Forward an email to another recipient             |
    | `/inbox/:messageId`         | PATCH  | Mark as read/unread, set outcome classification   |
    
    ## Get Inbox
    
    **GET** `/inbox`
    
    Headers:
    
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Query params:
    
    | Param      | Type    | Description                                               |
    | ---------- | ------- | --------------------------------------------------------- |
    | `type`     | string  | `draft`, `scheduled`, `sent`, or omit for replies (default) |
    | `limit`    | integer | Max 100 (default: 10)                                     |
    | `skip`     | integer | Offset (default: 0)                                       |
    | `sequence` | string  | Filter by sequence UUID                                   |
    | `outcome`  | string  | Filter by outcome classification                          |
    | `search`   | string  | Search in body, subject, or email address                 |
    | `date`     | string  | Date range as `startTimestamp-endTimestamp`               |
    | `sender`   | string  | Filter by sender ID                                       |
    
    > **Note:** Query filtering is limited on this endpoint. `owned_by` and several documented advanced filters are not implemented in the current API. Use the response client-side for precise filtering where needed.
    
    ```
    GET /inbox?type=all&limit=50&skip=0
    GET /inbox?type=sent&sequence=SEQ_ID&limit=100
    GET /inbox?search=acme&limit=20
    ```
    
    Response includes `data.result` (thread array), `totalCount`, `count`, and `messageIDs`.
    
    ## Get Thread
    
    **GET** `/inbox/:messageId/thread`
    
    Headers:
    
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Returns all messages in a conversation thread, sorted newest first.
    
    ## Forward Email
    
    **POST** `/inbox/:messageId/forward`
    
    Headers:
    
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    
    ```json
    {
      "email": "[email protected]",
      "content": "<p>Please see below.</p>"
    }
    ```
    
    | Field     | Type    | Req | Description                                                         |
    | --------- | ------- | --- | ------------------------------------------------------------------- |
    | `email`   | string  |     | Recipient email address (defaults to the original contact if omitted) |
    | `content` | string  |     | Optional additional message content                                 |
    | `cc`      | string  |     | Optional CC email address                                           |
    | `bcc`     | string  |     | Optional BCC email address                                            |
    | `scheduled_time` | integer | | Schedule at this timestamp (ms). Defaults to ~20s delay |
    | `tzMode` | string | | Timezone mode: `"sequence"` or `"custom"` |
    | `selectedTimezone` | string | | Timezone identifier if tzMode is custom |
    
    > If `email` is omitted, the email is forwarded to the original contact. If `content` is omitted, the original email body is forwarded as-is.
    
    ## Reply to Email
    
    **POST** `/inbox/:messageId/reply`
    
    Headers:
    
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    
    ```json
    {
      "content": "<p>Thanks for getting back to me! Let's schedule a call.</p>",
      "cc": "[email protected]"
    }
    ```
    
    | Field              | Type    | Req | Description                                             |
    | ------------------ | ------- | --- | ------------------------------------------------------- |
    | `content`          | string  | ✅  | HTML content of the reply                               |
    | `cc`               | string  |     | Optional CC email address                               |
    | `bcc`              | string  |     | Optional BCC email address                              |
    | `scheduled_time`   | integer |     | Schedule at this timestamp (ms). Defaults to ~20s delay |
    | `tzMode`           | string  |     | Timezone mode: `"sequence"` or `"custom"`               |
    | `selectedTimezone` | string  |     | Timezone identifier if tzMode is custom                 |
    
    > Attachments are supported via FormData field `attachment`. Base64 images in HTML are automatically uploaded to S3.
    > The reply is automatically sent from the same sender that originally contacted the lead.
    
    ## Update Mail State
    
    **PATCH** `/inbox/:messageId`
    
    Headers:
    
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    
    ```json
    {
      "unread": false,
      "outcome": "interested"
    }
    ```
    
    | Field     | Type    | Description                                                                                                                                                              |
    | --------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
    | `unread`  | boolean | Mark as read (`false`) or unread (`true`)                                                                                                                                |
    | `outcome` | string  | Classify the reply: `"interested"`, `"not-interested"`, `"automatic-response"`, `"meeting-request"`, `"out-of-office"`, `"do-not-contact"`, `"wrong-person"`, `"closed"` |
    
    > **Note:** The underlying API applies any body fields directly to the task document. Only `unread` and `outcome` are documented/stable; use other fields with caution.
    
  • skills/cold-email-salesblink/references/lists.md3.2 KBbc0fc8e8fa34upstream ↗
    # Lists
    
    ## Endpoints
    
    | Endpoint | Method | Description |
    |----------|--------|-------------|
    | `/lists` | GET | Retrieve all lists. Query: `limit` (max 100), `skip`, `owned_by`, `folder` |
    | `/lists/:id` | GET | Get a specific list by UUID — returns a single object `{ ... }` |
    | `/lists/:id/leads` | GET | Get leads in a list — `total` reflects current page size |
    | `/lists` | POST | Create a new list |
    | `/lists/:id` | PATCH | Update a list |
    | `/lists/:id/archive` | PUT | Archive or unarchive a list |
    
    ## Get List by ID
    
    **GET** `/lists/:id` (UUID)
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    > **Note:** The API returns a single list object `{ ... }` for this endpoint.
    
    > **List responses include `fields`**: an array of the list's columns (from its Complete View) in snake_case, e.g. `["first_name", "last_name", "email", "lead_score"]`. This applies to `GET /lists`, `GET /lists/:id`, and `POST /lists` responses.
    
    ## Get Leads
    
    **GET** `/lists/:id/leads?limit=100&skip=0`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Query params: `limit` (max 100), `skip`
    
    > **Note:** `total` in the response reflects the number of leads in the current page, not the total count across all pages.
    
    ## Create List
    
    **POST** `/lists`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    {
      "name": "Q1 Prospects"
    }
    ```
    
    Required fields marked with ✅:
    
    | Field | Type | Req | Description |
    |-------|------|-----|-------------|
    | `name` | string | ✅ | List name |
    | `folder` | string | | General folder ID (UUID). Must be a folder created without a `type` (i.e., not an email-sender folder). |
    | `starred` | boolean | | Star the list (default: false) |
    | `verification` | boolean | | Enable email verification ⚠️ **IRREVERSIBLE** |
    | `archive_invalid` | boolean | | Auto-archive invalid emails ⚠️ **IRREVERSIBLE** |
    | `archive_risky` | boolean | | Auto-archive risky emails ⚠️ **IRREVERSIBLE** |
    
    ## Update List
    
    **PATCH** `/lists/:id` (UUID)
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    {
      "name": "Q2 Prospects Restructured",
      "folder": "folder_uuid",
      "starred": true,
      "archive_invalid": true
    }
    ```
    
    | Field | Type | Description |
    |-------|------|-------------|
    | `name` | string | New name |
    | `folder` | string | Move list to a general folder (a folder created without a `type`, not an email-sender folder) |
    | `starred` | boolean | Star or unstar |
    | `duplicate_removal` | boolean | Remove duplicates from this list |
    | `duplicate_removal_other_list` | boolean | Remove contacts in other lists |
    | `duplicate_removal_team_list` | boolean | Remove contacts in team members' lists |
    | `verification` | boolean | Enable verification ⚠️ **IRREVERSIBLE** |
    | `archive_invalid` | boolean | Archive invalid emails ⚠️ **IRREVERSIBLE** |
    | `archive_risky` | boolean | Archive risky emails ⚠️ **IRREVERSIBLE** |
    
    > Use `PUT /lists/:id/archive` for archiving — not this endpoint.
    
    ## Archive List
    
    **PUT** `/lists/:id/archive`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    { "archived": true }
    ```
    
    Set `"archived": false` to unarchive.
    
  • skills/cold-email-salesblink/references/organization.md2.3 KBe0d723d3c7caupstream ↗
    # Organization — Users & Workspaces
    
    ## Users
    
    | Endpoint | Method | Description |
    |----------|--------|-------------|
    | `/users` | GET | List workspace users |
    | `/users` | POST | Invite a user |
    | `/users/:id` | PATCH | Update user name or role |
    
    ### Create User
    
    **POST** `/users`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    {
      "email": "[email protected]",
      "role": "user",
      "url": "https://run.salesblink.io/dashboard"
    }
    ```
    
    | Field | Type | Req | Description |
    |-------|------|-----|-------------|
    | `email` | string | ✅ | Email address of the new user |
    | `role` | string | | `"client"`, `"user"`, `"admin"`, or `"developer"`. Default: `"user"` |
    | `url` | string | | Optional redirect URL after accepting invitation |
    
    > Only **owners and admins** can add users. Returns 403 otherwise.
    
    ### Update User
    
    **PATCH** `/users/:id` (UUID)
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    {
      "name": "Updated Name",
      "role": "admin"
    }
    ```
    
    | Field | Type | Description |
    |-------|------|-------------|
    | `name` | string | New display name |
    | `role` | string | One of: `client`, `user`, `admin`, `developer` |
    
    ---
    
    ## Workspaces
    
    | Endpoint | Method | Description |
    |----------|--------|-------------|
    | `/workspaces` | GET | List all accessible workspaces |
    | `/workspaces` | POST | Create a new workspace |
    | `/workspaces/:id` | PATCH | Update workspace name |
    
    > **Owner only.** Returns 403 for non-owners.
    
    ### Create Workspace
    
    **POST** `/workspaces`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    { "name": "Sales Team" }
    ```
    
    | Field | Type | Req | Description |
    |-------|------|-----|-------------|
    | `name` | string | ✅ | Workspace name (min 4 characters) |
    
    > **Note:** The API returns HTTP `201 Created`, not `200 OK`.
    
    ### Update Workspace
    
    **PATCH** `/workspaces/:id` (UUID)
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    { "name": "New Workspace Name" }
    ```
    
    | Field | Type | Req | Description |
    |-------|------|-----|-------------|
    | `name` | string | ✅ | New workspace name (min 4 characters) |
    
    
    Note: For POST /workspaces, you can also optionally pass `workspaceName` in the body.
    
  • skills/cold-email-salesblink/references/reports.md862 Bcb622b4635dcupstream ↗
    # Reports
    
    ## Endpoints
    
    | Endpoint | Method | Description |
    |----------|--------|-------------|
    | `/reports` | GET | Retrieve activity reports with aggregated data |
    
    ## Get Reports
    
    **GET** `/reports`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Query params:
    
    | Param | Type | Description |
    |-------|------|-------------|
    | `from` | integer | Start date timestamp (milliseconds) |
    | `to` | integer | End date timestamp (milliseconds) |
    | `limit` | integer | Max 100 (default enforced server-side) |
    | `skip` | integer | Page number (0-based). The server converts this to skip × limit as the database offset. |
    
    > The endpoint maps `from`/`to` to a date range filter internally. Both are optional; omitting them returns all available report data.
    
    **GET** `/reports?from=1715000000000&to=1717600000000`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
  • skills/cold-email-salesblink/references/senders.md18 KB09fd16792f3fupstream ↗
    # Email Senders & OAuth
    
    ## Endpoints
    
    | Endpoint | Method | Description |
    |----------|--------|-------------|
    | `/senders` | GET | List all connected senders (flat list, not grouped by folder) |
    | `/senders/connect-link` | GET | Get a magic login link to the email-sender connection page in the SalesBlink web UI. |
    | `/senders/bulk-connect-link` | GET | Get a magic login link to the bulk CSV sender upload page in the SalesBlink web UI. |
    | `/senders/add-sender` | POST | Add one SMTP/IMAP sender directly from JSON credentials |
    | `/senders/add-bulk-senders` | POST | Add or update many SMTP/IMAP senders from a CSV file (`multipart/form-data`) |
    | `/senders/:id` | PATCH | Update sender settings (warmup, inbox, signature, tracking, folder, etc.) |
    | `/senders/:id/reconnect` | POST | Reconnect a failed sender |
    | `/senders/:id/health` | GET | Get sender health/reputation score |
    | `/senders/:id/warmup-stats` | GET | Date-wise warmup stats |
    | `/senders/:id/fetch-messages` | POST | Retrieve sent emails and received replies for a sender (max 50 messages, use `?skip` for pagination) |
    | `/senders/multi/fetch-messages` | POST | Bulk retrieve sent emails and received replies across senders (max 50 messages, use `?skip` for pagination) |
    | `/warmup-links` | GET | List warmup link configurations |
    | `/oauth/google` | POST | Get Google OAuth URL for connecting Gmail |
    | `/oauth/outlook` | POST | Get Microsoft OAuth URL for connecting Outlook |
    
    ## Get Senders
    
    **GET** `/senders`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Query params: `limit` (max 100), `skip`, `folder` (email-sender folder UUID), `filter` (legacy filter string)
    
    > **Note:** The response is a flat array of senders. It is **not** grouped by folder. The `owned_by` query parameter is not supported; use the `folder` (email-sender folder UUID) and `filter` query parameters if needed.
    
    > Use `PATCH /senders/:id` with `folder` to move a sender into an email-sender folder, or pass an empty string to remove it from its folder. The `folder` field is **not** accepted when creating a sender.
    
    ## Get Single Sender Connection Link
    
    **GET** `/senders/connect-link`
    
    This endpoint does not create a sender. It returns a magic login link to the email-sender connection page in the SalesBlink web UI. Ways to connect a sender:
    - **Gmail / Google Workspace**: use **POST** `/oauth/google` to get an authorization URL. The sender is created automatically after OAuth completion.
    - **Microsoft 365 / Outlook**: use **POST** `/oauth/outlook` to get an authorization URL. The sender is created automatically after OAuth completion.
    - **SMTP/IMAP, via the API**: use **POST** `/senders/add-sender` (one sender, JSON) or **POST** `/senders/add-bulk-senders` (CSV upload).
    - **SMTP/IMAP, in the web UI**: request this endpoint and give the user the `login_link`. Prefer this when the user would rather not share mailbox passwords in the conversation.
    
    Response (`LoginLinkResponse`):
    
    ```json
    {
      "success": true,
      "message": "Please connect your email sender through the SalesBlink web UI.",
      "data": {
        "login_link": "https://run.salesblink.io/magic?token=eyJ...&redirect=%2Foutreach%2Femail-senders%3Faddsenders%3Dtrue",
        "destination": "/outreach/email-senders?addsenders=true",
        "purpose": "connect_sender"
      }
    }
    ```
    
    
    For existing senders, use **PATCH** `/senders/:id` to update settings such as warmup, inbox, signature, tracking, or folder.
    
    ## Add Sender (SMTP/IMAP)
    
    **POST** `/senders/add-sender`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Creates one SMTP/IMAP sender. The credentials are tested in the background, not during the request (see [After adding](#after-adding-a-sender)).
    
    Minimal body:
    ```json
    {
      "from_email": "[email protected]",
      "password": "app-password",
      "smtp_host": "smtp.mycompany.com",
      "smtp_port": 465,
      "imap_host": "imap.mycompany.com",
      "imap_port": 993
    }
    ```
    
    > **Handle credentials carefully**: `password` / `imap_password` are mailbox secrets. Never echo them back to the user or write them into logs or files. Recommend an app password where the provider supports one. If the user prefers not to share a password, use `GET /senders/connect-link` instead.
    
    ### Connection fields
    
    | Field | Type | Required | Description |
    |-------|------|----------|-------------|
    | `from_email` | string | ✓ | Sender address. Stored lowercased |
    | `password` | string | ✓ | SMTP password. Also used for IMAP unless `imap_user_name` + `imap_password` are both given |
    | `smtp_host` | string | ✓ | SMTP server host |
    | `smtp_port` | integer | ✓ | SMTP port (e.g. `465`, `587`) |
    | `from_name` | string | | Display name. Defaults to `"Admin User"` |
    | `user_name` | string | | SMTP username. Defaults to `from_email` |
    | `imap_host` | string | | IMAP server host. **Omit for an SMTP-only sender**: an SMTP-only sender can send, but it cannot receive replies, monitor the inbox or warm up |
    | `imap_port` | integer | | IMAP port (e.g. `993`) |
    | `imap_user_name` | string | | Separate IMAP username. Only used when `imap_password` is also set; otherwise IMAP uses `from_email` / `password` |
    | `imap_password` | string | | Separate IMAP password. Only used together with `imap_user_name` |
    
    ### Warmup & inbox fields
    
    Warmup only applies to senders with IMAP. If `imap_host` is set, inbox monitoring is always enabled.
    
    | Field | Type | Default | Description |
    |-------|------|---------|-------------|
    | `warmup_enabled` | boolean | `false` | Start warmup. Ignored for SMTP-only senders |
    | `auto_ramp_up_enabled` | boolean | `true` | Ramp warmup volume up daily from the starting value to the max |
    | `starting_warmup_frequency` | integer | `5` | Warmup emails on day one (1–50, capped at `max_daily_frequency`) |
    | `total_warmup_per_day` | integer | `5` | Older name for the starting value; used only when `starting_warmup_frequency` is omitted |
    | `ramp_up_frequency` | integer | `1` | Daily warmup increase (1–50, capped at `max_daily_frequency`) |
    | `max_daily_frequency` | integer | `30` | Max warmup emails per day (1–50) |
    | `warmup_tag` | string | `""` | Warmup keyword/tag |
    | `inbox_path` | string | `"INBOX"` | IMAP inbox folder |
    | `spam_path` | string | `""` | IMAP spam folder |
    
    ### Sequence sending fields
    
    | Field | Type | Default | Description |
    |-------|------|---------|-------------|
    | `sequence_auto_ramp_up_enabled` | boolean | `false` | Ramp sequence volume up from the initial value to the max |
    | `sequence_initial_daily_frequency` | integer | `30` | Starting daily sequence sends (min 1, capped at the max) |
    | `sequence_ramp_up_frequency` | integer | `3` | Daily sequence-send increase (min 1, capped at the max) |
    | `sequence_max_daily_frequency` | integer | `30` | Max daily sequence sends (min 1). `max_emails_per_day` is accepted as an alias |
    | `pause_cold_emails_when_health_low` | boolean | `false` | Pause sequence sends when health drops below the threshold |
    | `pause_cold_emails_health_threshold` | integer | `80` | Health score threshold |
    
    The sender's daily sending limit starts at `sequence_initial_daily_frequency` when sequence ramp-up is on, otherwise at `sequence_max_daily_frequency`.
    
    ### Other fields
    
    | Field | Type | Description |
    |-------|------|-------------|
    | `signature_id` | string | Signature ID **or** name (case-insensitive). Silently ignored if no signature matches |
    | `custom_tracking_url` | string | Click-tracking domain, e.g. `track.mycompany.com`. A verified tracking domain in the account is used right away. Any other domain is registered as a tracking domain during connection and its DNS is checked (see `account-config.md`). If the domain belongs to another SalesBlink account, the connection fails |
    | `dkim_identifier` | string | DKIM selector/identifier |
    | `reply_to_email` | string | Reply-to address |
    
    Notes:
    - `folder` is not accepted here. Move the sender afterwards with `PATCH /senders/:id`.
    - Booleans may be sent as `true` or `"true"`.
    - camelCase aliases are also accepted: `email`, `senderName`, `smtpHost`, `smtpPort`, `smtpPassword`, `smtpUsername`, `imapHost`, `imapPort`, `imapUsername`, `imapPassword`, `autoRampUpEnabled`, `rampUpFrequency`, `maxDailyFrequency`, `startingWarmupFrequency`.
    
    Response (`200`); `data` has the same shape as a `GET /senders` item and never includes passwords:
    ```json
    {
      "success": true,
      "message": "Email Sender will be connected in a few minutes.",
      "data": {
        "id": "6c1f0b8e-3a5d-4e0f-9a51-2b7d8e4c1a90",
        "smtpImapEmail": "[email protected]",
        "senderType": "smtp",
        "serviceName": "smtpimap",
        "sendingEnabled": false,
        "receivingEnabled": false,
        "inboxEnabled": true
      }
    }
    ```
    
    `serviceName` is `"smtpimap"`, or `"smtponly"` when no `imap_host` was given.
    
    Errors:
    
    | Status | `message` | Cause |
    |--------|-----------|-------|
    | 400 | `from_email is required` (likewise `password`, `smtp_host`, `smtp_port`) | Missing required field |
    | 403 | `Email sender limit reached. Limit: N` | The plan's sender limit is used up |
    | 409 | `Sender already in use` | That address is already connected to SalesBlink, in this or another account, including as a Gmail/Outlook OAuth sender |
    
    ### After adding a sender
    
    The connection is tested in the background, usually within a few minutes:
    - **Success**: `sendingEnabled` becomes `true` (and `receivingEnabled` too, when IMAP is set). Check with `GET /senders`.
    - **Failure** (wrong credentials, host or port): the sender stays disabled and the user is notified of the sender error. Fix the settings with `PATCH /senders/:id`, or have the user fix them in the web UI, then call `POST /senders/:id/reconnect`.
    
    Only add a sender to a sequence once `sendingEnabled` is `true`.
    
    ## Add Senders in Bulk (CSV)
    
    **POST** `/senders/add-bulk-senders`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `multipart/form-data`
    
    Upload a CSV file in the form field **`csvFile`**. Each row is matched by `from_email` against the account's existing senders:
    - **No match**: a new sender is created.
    - **Match with an existing SMTP/IMAP sender**: that sender's settings are updated from the row.
    - **Match with a Gmail/Outlook OAuth sender**: the row is skipped.
    
    > **Requires `multipart/form-data`.** The JSON-only MCP gateway cannot upload this file. In that case, use `GET /senders/bulk-connect-link`, or the CLI: `salesblink senders add-bulk-senders --csv-file senders.csv`.
    
    ```bash
    curl -X POST "https://run.salesblink.io/api/public/v1.0.0/senders/add-bulk-senders" \
      -H "Authorization: $SALESBLINK_API_KEY" \
      -F "[email protected]"
    ```
    
    Example CSV:
    ```csv
    from_email,from_name,user_name,password,smtp_host,smtp_port,imap_host,imap_port,warmup_enabled
    [email protected],Alex,[email protected],app-password-1,smtp.mycompany.com,465,imap.mycompany.com,993,true
    [email protected],Sam,[email protected],app-password-2,smtp.mycompany.com,465,,,false
    ```
    
    The second row has an empty `imap_host`, so it is added as SMTP-only.
    
    ### CSV columns
    
    The CSV uses the same column names as the single-sender body, **except for the warmup columns**, which use `warmup_*` names:
    
    | Group | Columns |
    |-------|---------|
    | Connection | `from_email`, `password`, `smtp_host`, `smtp_port`, `from_name`, `user_name`, `imap_host`, `imap_port`, `imap_user_name`, `imap_password` |
    | Warmup | `warmup_enabled`, `warmup_auto_ramp_up_enabled` (default `true`), `warmup_initial_daily_frequency` (default `5`), `warmup_ramp_up_frequency` (default `1`), `warmup_max_daily_frequency` (default `30`); frequencies 1–50 |
    | Inbox | `inbox_enable`, `warmup_tag`, `inbox_path`, `spam_path` |
    | Sequence | `sequence_auto_ramp_up_enabled`, `sequence_initial_daily_frequency`, `sequence_ramp_up_frequency`, `sequence_max_daily_frequency` (or `max_emails_per_day`), `pause_cold_emails_when_health_low`, `pause_cold_emails_health_threshold`; same defaults as the single-sender body |
    | Other | `signature_id`, `custom_tracking_url`, `dkim_identifier`, `reply_to_email` |
    
    CSV vs. the single-sender endpoint:
    - **No per-row validation, and fewer defaults.** Fill in `from_email`, `password`, `smtp_host`, `smtp_port`, `from_name` and `user_name` on every row; `from_name` and `user_name` are **not** filled in from `from_email`.
    - **SMTP-only rows**: include the `imap_host` column and leave it empty.
    - **Inbox monitoring** is only enabled when the row sets `inbox_enable` to `true`. `warmup_enabled` only applies when IMAP is set.
    - **Skipped rows**: blank `from_email`, rows whose `from_email` contains `Email address` (a template's example row), and later duplicates of the same `from_email` within the file.
    - **Missing `from_email` header**: the whole upload fails.
    
    Response (`200`):
    ```json
    {
      "success": true,
      "data": null,
      "message": "Bulk senders uploaded successfully"
    }
    ```
    
    The response does not list the senders it created. Call `GET /senders` to see them. Each sender connects in the background as described in [After adding](#after-adding-a-sender).
    
    Errors:
    
    | Status | `message` |
    |--------|-----------|
    | 400 | `csvFile is required (multipart/form-data)` |
    | 403 | `Bulk sender upload is not available on your plan.` |
    | 403 | `Email sender limit reached. Limit: N` (checked before the upload) |
    
    ## Sender Lifecycle & Diagnostics
    
    **POST** `/senders/:id/reconnect`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Re-queues a failed SMTP/IMAP sender for connection, or refreshes OAuth tokens for Gmail/Outlook senders.
    
    **GET** `/senders/:id/health`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Returns sender health/reputation score and diagnostic info.
    
    **GET** `/senders/:id/warmup-stats`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Query params: `days` (integer, max 90, default 30)
    
    Returns date-wise warmup statistics for the sender.
    
    **POST** `/senders/:id/fetch-messages`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Schedules an inbox fetch for the sender.
    
    **POST** `/senders/multi/fetch-messages`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    { "ids": ["sender-id-1", "sender-id-2"] }
    ```
    
    Bulk fetch messages across multiple senders.
    
    ## Get Bulk Sender Upload Link
    
    **GET** `/senders/bulk-connect-link`
    
    This endpoint returns a magic login link for uploading a sender CSV in the SalesBlink web UI. Use it when the CSV can't be sent as `multipart/form-data` (for example through the MCP gateway), or when the user prefers the UI. To upload the CSV through the API, use **POST** `/senders/add-bulk-senders`.
    
    Calling **GET** `/senders/bulk-connect-link` returns a magic login link to the email-sender connection page:
    
    ```json
    {
      "success": true,
      "message": "Please upload senders in bulk through the SalesBlink web UI.",
      "data": {
        "login_link": "https://run.salesblink.io/magic?token=...&redirect=%2Foutreach%2Femail-senders%3Faddsenders%3Dtrue",
        "destination": "/outreach/email-senders?addsenders=true",
        "purpose": "bulk_upload_senders"
      }
    }
    ```
    
    ## Update Sender
    
    **PATCH** `/senders/:id`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Pass any of the fields below to update specific sender settings. Only provided fields are updated.
    
    ### Warmup fields
    
    | Field | Type | Description |
    |-------|------|-------------|
    | `warmup_enabled` | boolean | Enable/disable warmup |
    | `warmup_urls` | array | Warmup link URLs |
    | `warmup_templates` | array | Warmup template IDs |
    | `auto_ramp_up_enabled` | boolean | Enable auto ramp-up |
    | `ramp_up_frequency` | integer | Ramp-up increment |
    | `max_daily_frequency` | integer | Max daily warmup emails |
    | `starting_warmup_frequency` | integer | Starting warmup frequency |
    | `open_rate` | integer | Target open rate % |
    | `spam_protection` | integer | Spam protection level |
    | `read_emulation` | integer | Read emulation level |
    | `warmup_keyword` | string | Warmup keyword/tag |
    
    ### Sequence / sending fields
    
    | Field | Type | Description |
    |-------|------|-------------|
    | `sequence_auto_ramp_up_enabled` | boolean | Enable sequence auto ramp-up |
    | `sequence_initial_daily_frequency` | integer | Initial daily sequence sends |
    | `sequence_ramp_up_frequency` | integer | Sequence ramp-up increment |
    | `sequence_max_daily_frequency` | integer | Max daily sequence sends |
    | `pause_cold_emails_when_health_low` | boolean | Pause cold emails when health is low |
    | `pause_cold_emails_health_threshold` | integer | Health threshold to pause at |
    
    ### Inbox fields
    
    | Field | Type | Description |
    |-------|------|-------------|
    | `inbox_enabled` | boolean | Enable inbox monitoring |
    | `inbox_path` | string | Inbox folder path |
    | `spam_path` | string | Spam folder path |
    
    ### Other fields
    
    | Field | Type | Description |
    |-------|------|-------------|
    | `signature` | string | Signature ID or name |
    | `reply_to` | string | Reply-to email address |
    | `dkim_identifier` | string | DKIM identifier |
    | `use_custom_tracking_domain` | boolean | Use custom tracking domain |
    | `tracking_domain` | string | Tracking domain ID |
    | `folder` | string | Email-sender folder ID to move the sender into. Must be a folder created with `type: "email-sender"`. Pass an empty string to remove from folder. |
    
    Response:
    ```json
    {
      "success": true,
      "message": "Sender settings updated successfully",
      "data": { ... }
    }
    ```
    
    ## Warmup Links
    
    **GET** `/warmup-links`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Query params: `limit` and `skip` are accepted for compatibility but currently have no effect — all matching links are returned.
    
    List warmup link configurations. These URLs are used in sender warmup campaigns to improve deliverability.
    
    ## Google OAuth
    
    **POST** `/oauth/google`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Body is optional. A custom `redirectUrl` in the body is ignored by the API.
    
    Returns an `auth_url` that the user must visit to authorize Gmail access.
    
    Response:
    ```json
    {
      "success": true,
      "data": { "auth_url": "https://accounts.google.com/o/oauth2/v2/auth?..." }
    }
    ```
    
    ## Outlook OAuth
    
    **POST** `/oauth/outlook`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Body is optional. A custom `redirectUrl` in the body is ignored by the API.
    
    Returns an `auth_url` for Microsoft Outlook authorization.
    
    Response:
    ```json
    {
      "success": true,
      "data": { "auth_url": "https://login.microsoftonline.com/..." }
    }
    ```
    
  • skills/cold-email-salesblink/references/sequences.md11 KB839c7db40742upstream ↗
    # Sequences
    
    ## Endpoints
    
    | Endpoint | Method | Description |
    |----------|--------|-------------|
    | `/sequences` | GET | List all sequences. Query: `limit`, `skip`, `owned_by`, `status` (`running`, `paused`, `completed`, `needs-attention`), `folder`, `sendAll`, `sortBy`, `sortType`, `search` |
    | `/sequences/:id` | GET | Get sequence details including the internal `flowchart` object |
    | `/sequences/:id/stats` | GET | Get performance analytics. Query: `from`, `to`, `sender` (filter ignored by current API) |
    | `/sequences/:id/leads` | GET | List leads in a sequence (supports `status` filter) |
    | `/sequences/:id/leads/:leadId/messages` | GET | Message history for a lead in a sequence |
    | `/sequences/:id/leads/:leadId/unsubscribe` | POST | Remove a lead from a sequence |
    | `/sequences/:id/export` | GET | Export sequence leads as CSV |
    | `/sequences/:id/status` | POST | Update sequence status (ACTIVE, PAUSED, STOPPED, ARCHIVED) |
    | `/sequences` | POST | Create a full sequence with steps, senders, lists |
    | `/sequences/:id` | PATCH | Update settings, pause/resume, rewrite steps |
    | `/sequences/:id/clone` | POST | Duplicate an existing sequence (created paused) |
    | `/sequences/:id/archive` | PUT | Archive or unarchive a sequence |
    
    ## Get Sequences
    
    **GET** `/sequences`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Query params: `limit` (max 100), `skip`, `owned_by`, `status`, `folder`, `sendAll`, `sortBy`, `sortType`, `search`
    
    | `status` value | Meaning |
    |----------------|---------|
    | `running` | Active sequences |
    | `paused` | Paused sequences |
    | `completed` | Sequences that have completed all sends |
    | `needs-attention` | Sequences with issues (e.g. bounces, errors) |
    
    ## Get Sequence by ID
    
    **GET** `/sequences/:id` (UUID)
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    > **Note:** The response exposes the internal `flowchart` object. Step data must be read from `flowchart`, not from a simplified `steps` array.
    
    ## Create Sequence
    
    **POST** `/sequences`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    {
      "name": "Q1 Outbound Campaign",
      "senders": "a1b2c3d4-e5f6-7890-abcd-000000000001,a1b2c3d4-e5f6-7890-abcd-000000000002",
      "lists": ["b2c3d4e5-f6a7-8901-bcde-000000000001"],
      "steps": [
        { "type": "email", "template_id": "507f1f77bcf86cd799439011" },
        { "type": "delay", "days": 3 },
        { "type": "email", "template_id": "507f1f77bcf86cd799439012", "send_as": "followup" }
      ],
      "paused": false,
      "launchTimingMode": "schedule",
      "scheduledAt": 1751983200000,
      "timezone": "Asia/Calcutta",
      "delayEnabled": true,
      "delayFrom": 10,
      "delayTo": 20,
      "stopWhenReplyRecieved": true,
      "stopWhenReplyRecievedWhen": "contact",
      "emailSendingHours": [
        { "enabled": true, "name": "Monday", "fromTime": "09:00", "toTime": "17:00" },
        { "enabled": true, "name": "Tuesday", "fromTime": "09:00", "toTime": "17:00" },
        { "enabled": true, "name": "Wednesday", "fromTime": "09:00", "toTime": "17:00" },
        { "enabled": true, "name": "Thursday", "fromTime": "09:00", "toTime": "17:00" },
        { "enabled": true, "name": "Friday", "fromTime": "09:00", "toTime": "17:00" },
        { "enabled": false, "name": "Saturday", "fromTime": "09:00", "toTime": "17:00" },
        { "enabled": false, "name": "Sunday", "fromTime": "09:00", "toTime": "17:00" }
      ]
    }
    ```
    
    Required fields marked with ✅:
    
    | Field | Type | Req | Description |
    |-------|------|-----|-------------|
    | `name` | string | ✅ | Sequence name |
    | `senders` | string | ✅ | **Comma-separated string** of sender/folder IDs (NOT an array). Folder IDs here must be email-sender folders. |
    | `lists` | string[] | ✅ | Array of list UUIDs |
    | `steps` | Step[] | ✅ | Ordered array of email and delay steps |
    | `folder` | string | | General folder ID (UUID). Must be a folder created without a `type` (i.e., not an email-sender folder). |
    | `starred` | boolean | | Star the sequence |
    | `paused` | boolean | | Create in paused state (default: **true**) |
    | `launchTimingMode` | string | | `"now"` (starts in 5 mins) or `"schedule"` (requires `scheduledAt` and `timezone`) |
    | `scheduledAt` | integer \| string | | UTC timestamp in **milliseconds** (recommended). ISO 8601 strings with timezone offset are documented but are not parsed correctly by the current API. Convert the desired time to Unix milliseconds before sending. (required if `launchTimingMode = "schedule"`) |
    | `timezone` | string | | IANA timezone for sending, e.g. `"Asia/Calcutta"` or `"America/New_York"`. Required when scheduling to avoid defaulting to `"America/New_York"` |
    | `delayEnabled` | boolean | | Enable random delay between emails (default: true) |
    | `delayFrom` | integer | | Minimum delay in minutes (default: 10) |
    | `delayTo` | integer | | Maximum delay in minutes (default: 20) |
    | `stopWhenReplyRecieved` | boolean | | Stop sequence when lead replies (default: true) |
    | `stopWhenReplyRecievedWhen` | string | | `"contact"` or `"contact-with-same-domain"` (default: `"contact"`) |
    | `evergreen` | boolean | | Enable evergreen mode — continuously running (default: false) |
    | `bounceThreshold` | integer | | Bounces before pausing (default: 2) |
    | `bouncePause` | boolean | | Pause sequence on bounce threshold (default: false) |
    | `autoPause` | boolean | | Auto-pause on high bounce rate (default: true) |
    | `autoTagReplies` | boolean | | Auto-tag reply outcomes (default: false) |
    | `plainText` | boolean | | Send as plain text email (default: true) |
    | `auto_reply` | boolean | | Enable auto-reply detection (default: true) |
    | `matchProvider` | boolean | | Match sender email provider with recipient (default: true) |
    | `skip_esg` | boolean | | Skip ESG detection (default: true) |
    | `sendToOnlyVerifiedEmail` | boolean | | Only send to verified emails (default: false) |
    | `validEmail` | boolean | | Send to contacts with valid email status (default: true) |
    | `riskyEmail` | boolean | | Send to contacts with risky email status (default: true) |
    | `invalidEmail` | boolean | | Send to contacts with invalid email status (default: true) |
    | `checkEmailOpen` | boolean | | Check if recipient opened previous email before sending next (default: false) |
    | `checkEmailClick` | boolean | | Check if recipient clicked link before sending next (default: false) |
    | `checkEmailReply` | boolean | | Check if recipient replied before sending next (default: true) |
    | `checkEmailBeforeSending` | boolean | | Verify email before sending (default: true) |
    | `bcc` | string | | BCC email address for all outgoing emails (default: `""`) |
    | `emailSendingHours` | array | | Sending hours per day of the week (see default below) |
    
    **Steps structure** — ordered array mixing `email` and `delay` types:
    
    ```json
    "steps": [
      { "type": "email", "template_id": "507f1f77bcf86cd799439011" },
      { "type": "delay", "days": 3 },
      { "type": "email", "template_id": "507f1f77bcf86cd799439012", "send_as": "followup" }
    ]
    ```
    
    - `type: "email"` → MUST include `template_id` (the template's MongoDB ObjectId). MAY include `send_as`: `"new"` (default) sends a fresh thread; `"followup"` sends the email as a reply in the lead's existing thread (`"Re: <original subject>"`).
    - `send_as: "followup"` is ignored on the **first email step** of the sequence — there is no previous thread to reply to, so it always sends as a new thread. Only steps after the first email can follow up.
    - `type: "delay"` → MUST include `days` (integer, number of days to wait). `send_as` is not valid on delay steps.
    - Omitting `type` or misspelling it will fail or create a broken sequence.
    - The stored value is readable back on `GET /sequences/:id` as `flowchart.nodes[].data.send_as` (`{ "label": "RE: Follow Up", "value": "followup" }`); nodes without `send_as` send as new threads.
    
    **Default `emailSendingHours`:**
    ```json
    [
      { "enabled": true, "name": "Monday", "fromTime": "09:00", "toTime": "17:00" },
      { "enabled": true, "name": "Tuesday", "fromTime": "09:00", "toTime": "17:00" },
      { "enabled": true, "name": "Wednesday", "fromTime": "09:00", "toTime": "17:00" },
      { "enabled": true, "name": "Thursday", "fromTime": "09:00", "toTime": "17:00" },
      { "enabled": true, "name": "Friday", "fromTime": "09:00", "toTime": "17:00" },
      { "enabled": false, "name": "Saturday", "fromTime": "09:00", "toTime": "17:00" },
      { "enabled": false, "name": "Sunday", "fromTime": "09:00", "toTime": "17:00" }
    ]
    ```
    
    ## Update Sequence
    
    **PATCH** `/sequences/:id` (UUID)
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    {
      "folder": "folder_uuid",
      "paused": true
    }
    ```
    
    Accepts the same fields as create (all optional). Additionally used to **pause/resume**.
    
    > **Critical**: When updating `steps`, the entire array is **replaced** — send the full desired step list.
    
    > Updates to `name`, `starred`, or `folder` do **not** trigger task rescheduling. `folder` must be a folder created without a `type` (i.e., not an email-sender folder). All other field updates do.
    
    ## Clone Sequence
    
    **POST** `/sequences/:id/clone` (UUID)
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Creates a paused duplicate of an existing sequence.
    
    Response:
    ```json
    {
      "success": true,
      "data": { "clonedSequenceId": "new-sequence-uuid" },
      "message": "Sequence cloned successfully"
    }
    ```
    
    ## Archive Sequence
    
    **PUT** `/sequences/:id/archive` (UUID)
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    { "archived": true }
    ```
    
    Archiving a sequence automatically pauses it and removes pending email tasks.
    
    ## Sequence Lead Lifecycle
    
    **GET** `/sequences/:id/leads`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Query params: `limit` (max 500), `skip`, `status` (`not_contacted`, `contacted`, `opened`, `clicked`, `replied`, `bounced`, `unsubscribed`)
    
    The status filter works in two scopes: `not_contacted` (first email not yet sent) and `contacted` (first email sent) are evaluated on the lead's first-outreach task. `opened`, `clicked`, `replied`, `bounced` and `unsubscribed` match engagement recorded on any step of the sequence, so leads who engaged with a follow-up step are included.
    
    Response: `{ success, data: [...], count, total, skip, limit }`
    
    **GET** `/sequences/:id/leads/:leadId/messages`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Query params: `from`, `to` (Unix ms), `limit` (max 500), `skip`
    
    Response: `{ success, data: [...], count, skip, limit }`
    
    **POST** `/sequences/:id/leads/:leadId/unsubscribe`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Removes the lead from the sequence (same behavior as the internal remove-from-sequence action). Returns `{ success: true }`.
    
    ## Sequence Export & Status
    
    **GET** `/sequences/:id/export`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Query params: `limit` (max 50000, default 10000)
    
    Returns a CSV download of sequence leads.
    
    **POST** `/sequences/:id/status`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    { "status": "PAUSED" }
    ```
    
    Allowed statuses: `ACTIVE`, `PAUSED`, `STOPPED`, `ARCHIVED`.
    
  • skills/cold-email-salesblink/references/templates.md2.8 KB7a2e6b57afb0upstream ↗
    # Email Templates
    
    ## Endpoints
    
    | Endpoint | Method | Description |
    |----------|--------|-------------|
    | `/templates` | GET | List all templates (includes `cold_email_score`) |
    | `/templates/:id` | GET | Get full template details + score breakdown |
    | `/templates` | POST | Create a template |
    | `/templates/:id` | PATCH | Update template content, attachments |
    | `/templates/:id/archive` | PUT | Archive or unarchive a template |
    
    ## Create Template
    
    **POST** `/templates`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    {
      "name": "Cold Outreach V1",
      "subject_line": "Quick question, {{first_name}}",
      "content": "<p>Hi {{first_name}},</p><p>I noticed {{company}} is scaling fast...</p>",
      "folder": "folder_id",
      "starred": false
    }
    ```
    
    | Field | Type | Req | Description |
    |-------|------|-----|-------------|
    | `name` | string | ✅ | Template name |
    | `subject_line` | string | ✅ | Email subject (supports `{{variables}}`) |
    | `content` | string | ✅ | HTML body (supports `{{first_name}}`, `{{company}}`, etc.) |
    | `folder` | string | | General folder ID (UUID). Must be a folder created without a `type` (i.e., not an email-sender folder). |
    | `starred` | boolean | | Star the template |
    | `attachments` | file[] | | Files to attach (**max 3 total**). Use FormData field name `attachment` |
    
    Response includes `cold_email_score`:
    ```json
    {
      "score": 72.5,
      "rating": "Good",
      "details": {
        "word_count": 85,
        "personalization_count": 3,
        "link_count": 1,
        "image_count": 0,
        "question_count": 1,
        "spam_word_count": 0
      }
    }
    ```
    
    ## Update Template
    
    **PATCH** `/templates/:id` (ObjectId)
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    {
      "name": "Updated Template",
      "subject_line": "New subject {{first_name}}",
      "content": "<p>Updated content here</p>",
      "remove_attachments": ["old_file.pdf"]
    }
    ```
    
    | Field | Type | Description |
    |-------|------|-------------|
    | `name` | string | New template name |
    | `subject_line` | string | New subject line |
    | `content` | string | New HTML body |
    | `folder` | string | Move template to a general folder (a folder created without a `type`, not an email-sender folder). Pass an empty string to remove from folder. |
    | `starred` | boolean | Star/unstar |
    | `attachments` | file[] | New files to **append** (total must not exceed 3). Use FormData field name `attachment` |
    | `remove_attachments` | string[] | Names of existing attachments to **remove** |
    
    > **IMPORTANT**: To remove attachments, use the `remove_attachments` array with file **names** — not the `attachments` field.
    
    ## Archive Template
    
    **PUT** `/templates/:id/archive` (ObjectId)
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    { "archived": true }
    ```
    
  • skills/cold-email-salesblink/references/workflows.md3.6 KB73353a6c6a2eupstream ↗
    # Workflow Examples
    
    ## End-to-End Campaign Setup
    
    Goal: Build a complete outreach campaign from scratch.
    
    ### Step 1 — Create a list
    
    **POST** `/lists`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    {
      "name": "Q1 Prospects",
      "removeDuplicates": {
        "inThisList": true,
        "inOtherLists": true
      }
    }
    ```
    
    Extract `LIST_ID` from the response.
    
    ### Step 2 — Add leads to the list
    
    **POST** `/contacts`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    {
      "list_id": "LIST_ID_HERE",
      "contacts": [
        { "email": "[email protected]", "first_name": "Alice", "company_name": "Corp Inc" },
        { "email": "[email protected]", "first_name": "Bob", "company_name": "Startup IO" }
      ],
      "remove_duplicates": true
    }
    ```
    
    ### Step 3 — Create email templates
    
    **POST** `/templates`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    {
      "name": "Intro Email",
      "subject_line": "Quick question, {{first_name}}",
      "content": "<p>Hi {{first_name}},</p><p>I noticed {{company}} is scaling fast...</p>"
    }
    ```
    
    Extract `TEMPLATE_1_ID` (MongoDB ObjectId). Repeat for follow-up templates.
    
    ### Step 4 — Fetch available senders
    
    **GET** `/senders`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Extract target `SENDER_ID` (UUID).
    
    ### Step 5 — Create the sequence
    
    **POST** `/sequences`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    {
      "name": "Q1 Outbound Campaign",
      "senders": "SENDER_ID_HERE",
      "lists": ["LIST_ID_HERE"],
      "steps": [
        { "type": "email", "template_id": "TEMPLATE_1_ID" },
        { "type": "delay", "days": 3 },
        { "type": "email", "template_id": "TEMPLATE_2_ID", "send_as": "followup" }
      ],
      "paused": false,
      "launchTimingMode": "schedule",
      "scheduledAt": 1751983200000,
      "timezone": "America/New_York"
    }
    ```
    
    ## Clone and Modify Workflow
    
    Goal: Duplicate an existing sequence and tweak it.
    
    ### 1. Clone the sequence (creates paused copy)
    
    **POST** `/sequences/:id/clone`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    
    Extract `NEW_SEQ_ID` from `response.data.clonedSequenceId`.
    
    ### 2. Update the cloned sequence with new settings
    
    **PATCH** `/sequences/:id`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    {
      "name": "Q1 Campaign — Variant B",
      "steps": [
        { "type": "email", "template_id": "NEW_TEMPLATE_ID" },
        { "type": "delay", "days": 5 },
        { "type": "email", "template_id": "FOLLOW_UP_TEMPLATE_ID", "send_as": "followup" }
      ]
    }
    ```
    
    ### 3. Launch when ready
    
    **PATCH** `/sequences/:id`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    {
      "paused": false,
      "launchTimingMode": "now"
    }
    ```
    
    ## Archive Cleanup Workflow
    
    Goal: Clean up old campaigns, lists, and templates.
    
    ### Archive a sequence (pauses it and removes pending tasks)
    
    **PUT** `/sequences/:id/archive`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    { "archived": true }
    ```
    
    ### Archive the associated list
    
    **PUT** `/lists/:id/archive`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    { "archived": true }
    ```
    
    ### Archive templates
    
    **PUT** `/templates/:id/archive`
    
    Headers:
    - `Authorization`: `SALESBLINK_API_KEY`
    - `Content-Type`: `application/json`
    
    Body:
    ```json
    { "archived": true }
    ```
    
    > Archiving a sequence automatically pauses it and removes pending email tasks. Archiving a list pauses it if active. Archiving a contact removes its pending tasks from all sequences.
    
  • README.mdupstream ↗

    Contents are not inlined in the catalog. Open the upstream file.

Plain-text copy, no login: /skill-bundles/open-salesblink-skill-skills-cold-email-salesblink.md

// REPO STATS

22 stars