The email marketing tool “Benchmark Email” offers an official API that lets you exchange contact and campaign information with external tools. You can automatically sync data you manage in e-commerce, booking systems, CRMs, Google Sheets, and more with Benchmark Email, which frees you from the routine of “exporting a CSV and importing it again every week.”

In this article, based on the official documentation as of October 2026, I explain in detail the Benchmark Email API’s overview, what it can and can’t do, usage conditions, how to get an API key, and a concrete example of integrating with Google Sheets.

What Is the Benchmark Email API?

The Benchmark Email API is a mechanism for connecting your Benchmark Email account to external software. The official page introduces it with the concept that “your stack should work together,” and it has these features:

  • JSON over HTTP (a common REST format), and an OpenAPI specification is also published
  • Authentication with an API key (the X-API-Key header)
  • Scoped permissions, so you can limit the access range by contacts, campaigns, reports, and domains
  • You can set an expiration date for each key, and you can disable and re-enable keys without deleting them
  • There are rate limits per hour and per month, and you can check what remains in the response headers
  • There are scenario guides for major workflows and a migration guide from Benchmark Classic

And the important point is that the API can be used on all plans at no additional cost. All you need is an account in a usable state and an API key.

Who the API Is For

The official page introduces it as a feature that solves problems like these:

  • Customers from your e-commerce site, leads in a spreadsheet, and contacts from your POS or CRM all exist separately
  • To build an email list, you keep repeating CSV export → cleaning → import
  • You copy and paste campaign results into spreadsheets or slides every time

In other words, it is for teams whose data is scattered across multiple tools and who match records by hand. Conversely, if everything is handled within the Benchmark Email screens alone, you don’t need the API.

What You Can Do with the Benchmark Email API

The resources you can work with through the API fall into four main groups.

ResourceRequired scopeWhat you can do
Contacts (including lists)contacts:read / contacts:writeCreate, retrieve, update, and delete contacts, manage lists, update custom fields, search, export
Campaignscampaigns:read / campaigns:writeCreate, retrieve, update, delete, and duplicate campaigns, view templates
Reportsreports:readRetrieve dashboard summaries and email delivery performance reports
Domainsdomains:readCheck sending domains (read-only)

Managing Contacts

Contacts are what you’ll use most often.

  • Create, update, and delete contacts: Using the email address as the key, you can register contacts with a name and any custom fields.
  • Search and segments: You can search by email address, email domain, custom fields, tags, lists, status, creation and update dates, and more. You can choose from multiple operators such as “equals,” “contains,” “starts with,” “within a period,” and “is empty,” and combine them with AND/OR.
  • Duplicate check: If you search by email address before creating a contact, you can avoid adding a contact that is already registered a second time.
  • Differential updates: There is also an endpoint that does adding to and removing from lists, adding and removing tags, and updating fields together for a single contact.
  • Export and event retrieval: You can also export contacts and retrieve the event history for each contact.

Managing Lists

You can create, rename, duplicate, merge, and delete lists through the API. This is useful when your CRM or e-commerce tool holds the authoritative answer on “how to group customers.” For example, you can have the external system decide groups such as “purchased 3 or more times” or “membership tier is Gold” and reflect them in Benchmark lists.

Note that merging creates a new list while keeping the original lists, and duplicate contacts are handled automatically.

Creating and Configuring Campaigns

You can set the campaign name, subject, preview text, sender name and from address, reply-to address, recipient list, HTML body, and more through the API, and create the campaign as a draft. Duplicating an existing campaign is also possible, and the duplicate always becomes a draft regardless of the state of the original.

Retrieving Reports

You can retrieve these five kinds of information:

  • Dashboard overview (the last 1 to 90 days, with percentage change from the previous period)
  • Overall delivery performance (sent, delivered, opens, clicks, bounces, unsubscribes, complaints)
  • Time series data of delivery performance (handy for charting)
  • Reports for individual campaigns (including clicks per link)
  • Engagement trends for individual campaigns

If you feed the data into a BI tool or your own dashboard, you can eliminate the chore of “copying open rates into slides.”

Checking Sending Domains

You can read the authentication status of private sending domains. This is useful when you want to monitor deliverability on a separate dashboard, or let another system know that “this domain is now ready to send.”

Retrieving Account Information

With GET /api/account, you can retrieve basic information such as the account’s city, country, country code, currency code, and time zone. You can use it to check that your API key is working before calling other endpoints, and to match the time zone when retrieving reports. Note that the unlayerKey included in the response is a secret key (a SHA256 hash) for the Unlayer integration, so be careful not to expose it in logs or on screen.

What the API Can’t Do (What Stays in the Benchmark Email Interface)

The API is not all-purpose, and some operations are intentionally left out for safe sending.

OperationAPINotes
Sending, scheduling, canceling, and test-sending campaignsNot possibleDo it in the Benchmark Email interface
Newly authenticating a sending domainNot possibleGo through the process on the web interface (the API only reads authentication status)
Final design editing of emailsLimitedDuplicate a past campaign to carry it over, and make final adjustments in the interface
Reactivating contacts who have unsubscribedNot possibleFor compliance protection. For re-registration, have them opt in again

In other words, it is designed so that operations that could cause an accidental send can’t be run from an API key. The assumed workflow is to prepare campaign drafts through the API, and have a person do the final check and press the send button.

Usage Conditions, Rate Limits, and Pricing

Pricing and the Number of API Keys

  • The API itself is free on all plans
  • The free plan allows 2 active API keys, and the Pro plan allows up to 10 (talk to sales if you need more than 10)
  • The official recommendation is to “create one key per integration.” You can narrow the scope (permissions) for each key, and disable them individually when they are no longer needed

Rate Limits and Monthly Quota

According to the developer documentation, the limits are as follows.

TypeDetails
Hourly limit3,600 requests per hour per account (about 1 request per second). Even with multiple API keys, usage is consumed as a total
Monthly quota (free plan)Contact limit × 10
Monthly quota (paid plans)Contact limit × 100

For example, for a plan with a hypothetical contact limit of 1,000, the guideline is 10,000 requests per month on the free plan and 100,000 requests per month on paid plans (this is only a calculation example. Check the actual numbers for the plan you subscribe to).

When you exceed a limit, you get 429 Too Many Requests, and the Retry-After header shows the number of seconds to wait. The response also carries headers such as X-RateLimit-Remaining (the remainder for the hour) and X-Monthly-Remaining (the remainder for the month), so you can adjust your processing while watching what remains.

Also, if you repeatedly try an invalid API key, that IP address is temporarily blocked. If you keep getting 401, review the key instead of retrying over and over.

Other Conditions

  • Only users with owner permission can create and manage API keys
  • A key can be used only while the account is “Open” or “Pending Cancel” (during payment delays or suspension, you get 403)
  • A User-Agent header is required on every request (described below)

From Getting an API Key to Your First Request

1. Create an API Key

  1. Log in to Benchmark Email with the owner account
  2. Open Settings > API Keys
  3. Click Create API Key
  4. Give it a clear name (for example, Sheets Sync) and select only the scopes you need
  5. Set an expiration date if needed (if you don’t, it never expires)
  6. Copy the key shown after creation right then, and store it safely

The key is shown only once, at creation. If you lose it, you can regenerate it from the API Keys screen, but the old key becomes invalid.

An API key is bme_ + a 2-character region code (such as us, jp, or eu) + a 43-character random string, 50 characters in total.

2. Check the Base URL

The base URL differs by your account’s region and cluster, and takes the form https://api-{region}-{cluster}.benchmarkemail.io (for example, https://api-us-west-2-a.benchmarkemail.io). Your own base URL is shown on the Settings > API Keys screen, so use that.

3. Send Your First Request

bash
curl -H "X-API-Key: bme_your-api-key-here" \
  -H "User-Agent: MyIntegration/1.0" \
  "<your-api-base-url>/api/contact-structure"

If the contact structure (the definitions of custom fields) comes back as JSON, you’ve succeeded. If you get 401 or 403, check the key, the scope, and the account status.

If you get a 403 that returns HTML instead of JSON, it is highly likely that the User-Agent header isn’t being sent. This is because Benchmark Email’s edge protection rejects requests without a User-Agent. curl and the standard libraries of major languages add it automatically, but things like PHP’s cURL extension need it set explicitly.

Note: The curl sample on the marketing introduction page (the format that passes list_id to /v1/contacts) and the endpoints in the developer documentation (the format that passes contactStructureId and field _ids to /api/contact) are written differently. When you implement, always follow the developer documentation (developers.benchmarkemail.io).

How Scopes Work

The API documentation is easy to follow - Benchmark Email

You attach scopes to an API key in the {resource}:{access type} format.

ScopeDetails
contacts:readViewing and searching contacts, lists, and the contact structure, export, event history
contacts:writeCreating, updating, and deleting contacts and lists, updating the contact structure
campaigns:readViewing campaigns, viewing templates
campaigns:writeCreating, updating, deleting, and duplicating campaigns
reports:readViewing the dashboard and delivery reports
domains:readViewing sending domains

There are three key points:

  • write includes read: With contacts:write, you can also read contacts
  • Principle of least privilege: Split your keys, for example only reports:read for a reporting dashboard, and only contacts:write for syncing contacts from a spreadsheet
  • read is enough for search: Contact search is done with POST, but all you need is contacts:read

Concrete Use Cases

From here, based on the specifications in the official documentation, I consider integration examples that look genuinely useful.

Note: The code below is sample code written according to the specifications in the official documentation. Before you run it against your production list, always check that it works with a test list or a small amount of data.

Example 1: Sync Contacts from Google Sheets to Benchmark Email

Assume you collect seminar sign-ups or survey responses in Google Sheets. You register only the newly added rows in a Benchmark Email list, and avoid duplicating email addresses that are already registered.

Preparation

  1. Create an API key with the contacts:write scope
  2. With GET /api/contact-structure, note the contact structure’s _id and the _ids of the “first name” and “last name” fields
  3. Note the _id of the destination list (you can get the list with GET /api/contact-structure/{structure ID}/lists/all)
  4. Use the first row of the spreadsheet as the header, with column A = email, column B = first name, column C = last name, and column D = sync result
  5. Save the API key and IDs in Apps Script’s “script properties” (don’t hardcode them in the code)

Google Apps Script code

javascript
// ===== Settings (saved in script properties) =====
const P = PropertiesService.getScriptProperties();
const BASE_URL = P.getProperty('BME_BASE_URL');           // e.g. https://api-us-west-2-a.benchmarkemail.io
const API_KEY = P.getProperty('BME_API_KEY');             // bme_us_...
const STRUCTURE_ID = P.getProperty('BME_STRUCTURE_ID');   // _id of the contact structure
const LAST_NAME_ID = P.getProperty('BME_LAST_NAME_FIELD_ID');
const FIRST_NAME_ID = P.getProperty('BME_FIRST_NAME_FIELD_ID');
const LIST_ID = P.getProperty('BME_LIST_ID');

// ===== Common API call =====
function api_(method, path, body, retry) {
  retry = retry || 0;
  const res = UrlFetchApp.fetch(BASE_URL + path, {
    method: method,
    contentType: 'application/json',
    headers: { 'X-API-Key': API_KEY, 'User-Agent': 'SheetsToBenchmark/1.0' },
    payload: body ? JSON.stringify(body) : undefined,
    muteHttpExceptions: true,
  });
  const code = res.getResponseCode();
  if (code === 429 && retry < 3) {          // Rate limit: wait, then retry
    Utilities.sleep(60 * 1000);
    return api_(method, path, body, retry + 1);
  }
  if (code >= 400) throw new Error(code + ' ' + res.getContentText());
  const text = res.getContentText();
  return text ? JSON.parse(text) : null;
}

// ===== Duplicate check by email address =====
function emailExists_(email) {
  const r = api_('post', '/api/contact/search', {
    contactStructureId: STRUCTURE_ID,
    page: 1,
    pageSize: 1,
    source: ['_id'],
    contactSpecification: {
      filters: [{ criterias: [{ columnToFilter: 'KEY', operator: 'EQ', values: [email] }] }],
    },
  });
  return r.totalRecords > 0;
}

// ===== Register only unsynced rows =====
function syncNewRows() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Applicants');
  const rows = sheet.getDataRange().getValues();

  for (let i = 1; i < rows.length; i++) {
    const email = String(rows[i][0]).trim();
    const firstName = rows[i][1];
    const lastName = rows[i][2];
    const synced = rows[i][3];
    if (!email || synced) continue;       // Skip empty and already-synced rows

    let result;
    if (emailExists_(email)) {
      result = 'Skipped (already registered)';
    } else {
      api_('post', '/api/contact', {
        key: email,
        contactStructureId: STRUCTURE_ID,
        fields: [
          { _id: LAST_NAME_ID, value: lastName },
          { _id: FIRST_NAME_ID, value: firstName },
        ],
        lists: [{ _id: LIST_ID }],
      });
      result = 'Synced ' + new Date().toLocaleString();
    }
    sheet.getRange(i + 1, 4).setValue(result);
    Utilities.sleep(300);                  // Avoid back-to-back requests
  }
}

After that, if you run syncNewRows on an Apps Script time-driven trigger such as “every hour” or “every morning,” it is automatically reflected in your Benchmark Email list as rows are added to the spreadsheet. If it’s the response sheet for a Google Form, you can also use the “on form submit” trigger.

Each row takes at most 2 requests (search + create), so there is plenty of room under the 3,600 requests per hour limit.

Example 2: Automatically Write Delivery Results to Google Sheets

Next is an example in the opposite direction. It automatically compiles the results of sent campaigns into a spreadsheet. The campaign list API (GET /api/email/campaign) also returns the statistics for sent campaigns (opens, clicks, open rate, and so on). You can reuse the api_ function from before as is.

It works with a key that has the campaigns:read scope.

javascript
function exportCampaignStats() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName('Delivery Report') || ss.insertSheet('Delivery Report');

  const res = api_('get', '/api/email/campaign?page=1&size=25&statuses=sent&sort=scheduledAt:desc');

  const header = ['Campaign name', 'Subject', 'Sent at', 'Sent', 'Delivered',
                  'Opens (unique)', 'Open rate (%)', 'Clicks (unique)', 'Click rate (%)'];
  const rows = res.records.map(function (c) {
    const s = c.stats || {};
    return [
      c.name, c.subject, c.scheduledAt,
      s.sent, s.delivered,
      s.opens && s.opens.unique, s.opens && s.opens.rate,
      s.clicks && s.clicks.unique, s.clicks && s.clicks.rate,
    ];
  });

  sheet.clearContents();
  sheet.getRange(1, 1, 1, header.length).setValues([header]);
  if (rows.length) sheet.getRange(2, 1, rows.length, header.length).setValues(rows);
}

If you run it on a daily morning trigger, the latest results are ready as soon as you open the sheet. From there, you can automate a weekly report by making charts with Google Sheets’ standard features or connecting to Looker Studio.

If you need more detailed analysis, use the reports API as well.

  • GET /api/reports/dashboard?pastDays=30&timezone=America/New_York: Overview of the last 30 days (with percentage change from the previous period)
  • GET /api/reports/email/{campaign ID}: Clicks per link for a specific campaign
  • GET /api/reports/email/{campaign ID}/engagement?period=week: Trend of opens and clicks for one week after sending

If you set timezone to your own time zone (for example, America/New_York), dates are cut off and aggregated in that time zone, which is convenient for reports for your own region.

Example 3: Automatically Add Customers from an E-commerce Site or Booking Form to a List (n8n, Zapier, and More)

Benchmark Email currently has no built-in no-code workflow tool. However, the official documentation also says that “you can automate workflows through the API with tools like Zapier and n8n.” If you use a node that can send HTTP requests (n8n’s HTTP Request node, Zapier’s Webhooks, and so on), you can integrate with almost no code.

For example, the flow looks like this:

  1. Trigger: An order comes in on your e-commerce site / a booking form is submitted / someone answers a Google Form
  2. Search: Use POST /api/contact/search to check whether the email address is already registered
  3. Branch
    • Not registered → Create it with POST /api/contact and add it to a list
    • Registered → Use the differential update endpoint to add it to lists, assign tags, and update fields
  4. Notify: If needed, tell Slack or Microsoft Teams “a new contact was registered”

If you filter by FIELD_ID during the search, you can also check conditions such as “only people whose membership tier is Gold.” You can keep the Benchmark Email lists automatically up to date while leaving the authoritative customer data in your e-commerce tool or CRM.

Example 4: Duplicate Last Month’s Newsletter to Create This Month’s Draft

For something like a monthly newsletter, where you send almost the same design every time, duplicating a past campaign to prepare a draft is a good fit.

bash
# 1. Duplicate last month's campaign to create this month's draft
curl -X POST "<your-api-base-url>/api/email/campaign/{last month's campaign ID}/duplicate" \
  -H "X-API-Key: $BENCHMARK_KEY" \
  -H "User-Agent: MonthlyNewsletter/1.0" \
  -H "Content-Type: application/json" \
  -d '{ "name": "November 2026 Newsletter" }'

# 2. Update the subject, preview text, and destination list (__v is the value you just retrieved)
curl -X PATCH "<your-api-base-url>/api/email/campaign/{new campaign ID}" \
  -H "X-API-Key: $BENCHMARK_KEY" \
  -H "User-Agent: MonthlyNewsletter/1.0" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "[November Issue] This Month'"'"'s Announcements",
    "previewText": "A roundup of new features and use cases",
    "lists": ["{destination list ID}"],
    "__v": 0
  }'

After that, open the draft in the Benchmark Email interface, rewrite the body, check the content, and send. If you split the work so that the API handles “preparing the draft” and a person handles “the final check and sending,” you can run it safely.

Example 5: Leave the Implementation to an AI Coding Assistant

The official developer documentation also provides materials for AI coding assistants.

  • llms.txt: A table of contents of all documentation pages
  • llms-full.txt: The full text of all the documentation in one file
  • SKILL.md: A guide for agents that summarizes the endpoints, decision guidelines, and common mistakes

When you ask an AI, it is a good idea to instruct it: “First read SKILL.md, then read the scenario guide that matches what I want to do, and then write the code.” For example, even a Google Apps Script like Example 1 above can be adjusted for your own use in a short time if you have the AI read the specifications and ask it to “write it to match the column layout of my spreadsheet.”

Points to Watch When Implementing

Here are the points that are easy to trip over, picked up from the scenario guides.

  • PUT is a “full replacement”: If you update a contact with PUT, any fields you didn’t include in the request are erased. Retrieve the latest data with GET first, and use it as the base, rewriting only the parts you want to change before sending
  • __v (version) is required: For PUT and for PATCH on campaigns and lists, you need to attach the __v you just retrieved with GET. With an old value, you get a ConcurrencyError (400), so retrieve it again and redo it
  • Statuses are case-sensitive: Active, Inactive, and Unsubscribe must be sent in exactly this form, and lowercase causes an error. When you set Inactive, both primary and secondary are required
  • Contacts who unsubscribed or bounced can’t be restored: Once a contact becomes Inactive, it can’t be returned to Active through the API. This is a specification for compliance protection, so the basic premise is not to try to reactivate them on your own
  • Duplicates cause errors: If the same email address already exists in the same structure, you get DuplicateFieldError. Check by search before creating, or look at the error and switch to an update
  • The source in search is required: Specify the fields you want returned as an array such as _id, key, and fields. Values are case-sensitive, and if even one unknown value is included, the entire request is rejected
  • Contact list retrieval has no paging: GET /api/contact returns all records at once, so for accounts with many records, the search API, which has paging, is safer
  • The from address must be from an authenticated domain: A campaign’s from must be an address on an authenticated sending domain
  • Always manage keys with environment variables or script properties: Don’t hardcode them in source code or spreadsheet cells. If you suspect a leak, disable and regenerate the key

Benefits and Cautions of the Benchmark Email API

Pros 6
  • Available on all plans at no additional cost (up to 2 API keys even on the free plan)

  • Covers the range needed for daily operations: contacts, lists, campaigns, reports, and domains

  • Scoped API keys let you narrow permissions for each integration

  • Supports per-key expiration, and disabling and re-enabling, which shows consideration for security

  • The documentation is thorough, with scenario guides, an OpenAPI specification, and materials for AI (llms.txt, SKILL.md)

  • Campaign sending can't be run through the API, so the risk of accidental sends from automation is low

Cons 5
  • There is no built-in no-code integration feature, so it assumes help from a developer, a technical person, or an AI tool

  • Sending, scheduling, and final design editing can't be done through the API and require work in the interface

  • With the limit of 3,600 requests per hour and a monthly quota, syncing large volumes of data requires planning

  • Contacts that became inactive through unsubscribing and similar can't be reactivated through the API

  • The free plan's API keys are limited to two, so if you have many integrations, you need the Pro plan

Who It Is and Isn’t For

Who it suits

  • Customer data sits in multiple places, such as an e-commerce site, a booking system, a CRM, and spreadsheets, and you spend time matching records by hand
  • You have a developer, or can leave the implementation to an AI coding tool
  • You want to see delivery results in your own dashboard or BI tool
  • You send emails in almost the same format every month, and want to automate only the draft preparation

Who it doesn’t suit

  • Your operations are complete within the Benchmark Email interface alone, and you don’t need integration with external tools
  • You want to set up integrations with fully no-code, click-only tools (at present, it means building HTTP requests into an external tool such as Zapier)
  • You want to run the sending of emails itself from the API (it is not suited to transactional-email-style uses)

Frequently Asked Questions (FAQ)

Q. Can I use the API on Benchmark Email’s free plan?

Yes. The API is included free on all plans. On the free plan, you can create up to 2 active API keys.

Q. Can I use it without programming knowledge?

You need to write, or generate, code for the integration. Even if you can’t write code yourself, you can make it happen by asking a developer or using an AI coding assistant.

Q. Can I send emails through the API?

Not directly. Creating, configuring, and duplicating campaigns is possible through the API, but scheduling and sending are done in the Benchmark Email interface.

Q. Where can I create an API key?

With an owner-permission account, you can create one from Settings > API Keys. The key is shown only once, at creation, so be sure to note it down right then.

Q. What are the rate limits?

According to the developer documentation, it is 3,600 requests per hour per account (the total across multiple keys), and the monthly quota is 10 times the contact limit (free) or 100 times (paid). The numbers may change, so check the latest information under “Rate Limits” in the documentation.

Q. Can I integrate with Google Sheets?

There is no official connector, but you can integrate by calling the API with UrlFetchApp from Google Apps Script. As in Examples 1 and 2 in this article, you can register contacts from a spreadsheet and write out delivery results.

Summary

The Benchmark Email API is an API, free on all plans, for connecting contacts, lists, campaigns, reports, and sending domains with external tools.

  • You can automate the manual work of moving data in and out, such as syncing contacts, searching, duplicate checks, list management, and retrieving reports
  • On the other hand, sending, scheduling, and final design can’t be handled through the API, and for safety, a check in the interface remains
  • To use it, you need help from a developer or an AI tool, but because the official side provides llms.txt and SKILL.md, the barrier isn’t high if you assume leaving the implementation to AI
  • With Google Sheets, using Google Apps Script, you can do automatic registration of sign-up lists and automatic aggregation of delivery results

To start, create one API key on the free plan, call GET /api/contact-structure, and check the structure of your own account. From there, I recommend automating the one task that takes the most effort, such as spreadsheet syncing.