Skip to content

mv.campaigns

Outbound calling campaigns. These methods are on mv.campaigns, where mv is your client (see the Node.js SDK). Each one returns the response object and throws when the API answers with an error.

Cancel a campaign. Stops the campaign for good: unanswered calls are hung up and the contacts not yet dialled are cancelled.

mv.campaigns.cancel(id: CampaignsCancelData["path"]["id"], body?: CampaignsCancelData["body"], options?: RequestOptions): Promise<CampaignsCancelResponse>

POST /campaigns/{id}/cancel · API reference

Name Type Required Description
id string yes A campaign ID (cmp_…).
options.headers["MoreVoice-Version"] string no The API version to use for this request. Defaults to the version the API key is pinned to.
options.headers["Idempotency-Key"] string no A unique key (for example a UUID) that makes this request safe to retry: for 24 hours, a retry with the same key and parameters returns the first response instead of acting twice.
options RequestOptions no idempotencyKey, extra headers and an abort signal: see retries and idempotency.

Campaign:

Field Type Description
id string A campaign ID (prefix cmp_).
object "campaign" Always campaign.
livemode boolean true in live mode, false in test mode.
name string —
state "draft" | "scheduled" | "running" | "paused" | "completed" | "cancelled" draft → running ⇄ paused → completed | cancelled (scheduled: waits for schedule.start_at).
purpose "marketing" | "service" | "survey" marketing needs recorded consent with evidence (§30A) and a national-registry check for Israeli numbers.
assistant_id string | null asst_… ID.
connection_id string | null The SIP connection it dials through; null: the default one.
caller_id string | null The number presented to contacts; null: the connection’s default.
priority integer 1–10; higher is served first when campaigns compete for lines.
max_concurrent integer Simultaneous calls this campaign may hold.
calls_per_second integer New calls per second; 0: only the connection limits it.
schedule CampaignSchedule When the campaign dials.
ring_timeout_seconds integer Hang up an unanswered call after this long.
retry CampaignRetry Retry policy per call result.
amd CampaignAmd Answering-machine detection.
disclosure CampaignDisclosure The AI and recording disclosure played at the start of each call.
first_message string Overrides the assistant’s first message ({{variables}} allowed); empty: the assistant’s.
script string Extra instructions for this campaign ({{variables}} allowed).
dispositions string[] Outcomes the assistant can record.
opt_out_dtmf_key string | null The key that opts a contact out; null: the organisation’s.
pause_reason string | null Why the campaign paused itself (for example, the national registry can’t check it).
stats CampaignStats Contact counts per status and the calls in progress.
created_at string An ISO-8601 timestamp in UTC.
updated_at string An ISO-8601 timestamp in UTC.
started_at string | null —
completed_at string | null —
import { createClient, createResources } from "@morevoice/sdk";
const mv = createResources({
client: createClient({ baseUrl: "https://api.morevoice.ai/v1", auth: process.env.MOREVOICE_API_KEY }),
});
const campaign = await mv.campaigns.cancel("cmp_ojFwMD7YNTROjaTP0i3ZFb", {});
console.log(campaign);

Add contacts to a campaign. Adds up to 1,000 contacts and answers what was added and what was left out, like a dashboard import of the same list: numbers are normalised and de-duplicated, do-not-call numbers are kept as dnc (never dialled), and in a marketing campaign a contact without consent evidence is added but skipped by the dialer (§30A).

mv.campaigns.contacts.create(id: CampaignsContactsCreateData["path"]["id"], body: CampaignsContactsCreateData["body"], options?: RequestOptions): Promise<CampaignsContactsCreateResponse>

POST /campaigns/{id}/contacts · API reference

Name Type Required Description
id string yes A campaign ID (cmp_…).
body.contacts ContactInputInput[] yes Up to 1000 contacts.
body.default_country string no Country of numbers written without a country code (ISO 3166-1 alpha-2, default IL).
body.drop_dnc boolean no Leave numbers on the do-not-call list out entirely (default false: they are kept with status dnc, for the record, and never dialled).
options.headers["MoreVoice-Version"] string no The API version to use for this request. Defaults to the version the API key is pinned to.
options.headers["Idempotency-Key"] string no A unique key (for example a UUID) that makes this request safe to retry: for 24 hours, a retry with the same key and parameters returns the first response instead of acting twice.
options RequestOptions no idempotencyKey, extra headers and an abort signal: see retries and idempotency.

ContactBatchResult:

Field Type Description
object "contact_batch_result" Always contact_batch_result.
campaign_id string A campaign ID (prefix cmp_).
livemode boolean true in live mode, false in test mode.
received integer Non-empty contacts / rows received.
imported integer Contacts added to the campaign for dialling.
rejected integer Contacts not added for dialling (invalid, duplicate, do-not-call).
rejected_reasons ContactRejectedReasons Rejected contacts per reason.
without_consent integer Marketing: contacts added without a consent record. The dialer skips them (§30A) unless consent is recorded first.
consent_recorded integer Consent records created from the evidence sent.
errors object[] Rejected contacts (the first 100).
warnings object[] Contacts added with a problem, e.g. consent claimed without complete evidence (the first 100).
import { createClient, createResources } from "@morevoice/sdk";
const mv = createResources({
client: createClient({ baseUrl: "https://api.morevoice.ai/v1", auth: process.env.MOREVOICE_API_KEY }),
});
const contactBatchResult = await mv.campaigns.contacts.create("cmp_ojFwMD7YNTROjaTP0i3ZFb", {
contacts: [
{
consent: {
channel: "web",
granted_at: "2026-09-20T14:02:00+03:00",
source: "website_form_2026",
},
name: "Dana Levi",
phone: "+972501234567",
variables: {
plan: "Gold",
},
},
{
name: "Yossi Cohen",
phone: "052-765-4321",
variables: {
plan: "Silver",
},
},
],
default_country: "IL",
});
console.log(contactBatchResult);

Import a contact list in the background. Imports a CSV or XLSX list in the background through the dashboard’s import path and answers 202 with the import; poll GET /v1/imports/{id} until it succeeds or fails. Send the file as multipart/form-data (a file part plus the options as text fields, mapping as a JSON string), or as JSON: CSV text, a base64 file, or an https URL to download. An Idempotency-Key is required, so a retried upload never imports twice.

mv.campaigns.contacts.import(id: CampaignsContactsImportData["path"]["id"], body: CampaignsContactsImportData["body"], options?: RequestOptions): Promise<CampaignsContactsImportResponse>

POST /campaigns/{id}/contacts/import · API reference

Name Type Required Description
id string yes A campaign ID (cmp_…).
body.consent_channel "web" | "phone" | "sms" | "email" | "whatsapp" | "app" | "written" | "in_person" | … no How every consenting row consented, when the file has no channel column.
body.consent_source string no Where every consenting row consented, when the file has no source column.
body.csv string no The list as CSV text (UTF-8; comma, semicolon, tab or pipe separated).
body.default_country string no Country of numbers written without a country code (ISO 3166-1 alpha-2, default IL).
body.drop_dnc boolean no Leave do-not-call numbers out entirely (default false: kept with status dnc, never dialled).
body.file object no A CSV or XLSX file.
body.has_header boolean no The first row holds column names (default: detected).
body.mapping ImportMappingInput no Which column holds what: contact field → header name (or 0-based index). Any other key names a {{variable}}. Omit the mapping to detect the columns like the dashboard does.
body.url string no An https URL to download the CSV / XLSX from (public addresses only, ≤ 10 MB).
options.headers["MoreVoice-Version"] string no The API version to use for this request. Defaults to the version the API key is pinned to.
options.headers["Idempotency-Key"] string no A unique key (for example a UUID) that makes this request safe to retry: for 24 hours, a retry with the same key and parameters returns the first response instead of acting twice.
options RequestOptions no idempotencyKey, extra headers and an abort signal: see retries and idempotency.

ContactImport:

Field Type Description
id string A import ID (prefix imp_).
object "import" Always import.
livemode boolean true in live mode, false in test mode.
campaign_id string A campaign ID (prefix cmp_).
status "pending" | "processing" | "succeeded" | "failed" pending → processing → succeeded | failed. Poll GET /v1/imports/{id}.
source "csv" | "xlsx" | "url" —
filename string | null —
received integer Non-empty contacts / rows received.
imported integer Contacts added to the campaign for dialling.
rejected integer Contacts not added for dialling (invalid, duplicate, do-not-call).
rejected_reasons ContactRejectedReasons Rejected contacts per reason.
without_consent integer Marketing: contacts added without a consent record. The dialer skips them (§30A) unless consent is recorded first.
consent_recorded integer Consent records created from the evidence sent.
errors object[] Rejected rows (the first 100).
warnings object[] Rows added with a problem (the first 100).
error object | null Why the import failed (status failed): a stable code and a message to show.
created_at string An ISO-8601 timestamp in UTC.
started_at string | null —
completed_at string | null —
import { createClient, createResources } from "@morevoice/sdk";
const mv = createResources({
client: createClient({ baseUrl: "https://api.morevoice.ai/v1", auth: process.env.MOREVOICE_API_KEY }),
});
const contactImport = await mv.campaigns.contacts.import("cmp_ojFwMD7YNTROjaTP0i3ZFb", {
csv: "Mobile,Name,Plan\n0501234567,Dana Levi,Gold\n0527654321,Yossi Cohen,Silver\n",
default_country: "IL",
mapping: {
name: "Name",
phone: "Mobile",
variables: {
plan: "Plan",
},
},
});
console.log(contactImport);

List a campaign’s contacts.

mv.campaigns.contacts.list(id: CampaignsContactsListData["path"]["id"], query?: NonNullable<CampaignsContactsListData["query"]>, options?: RequestOptions): PagedList<CampaignsContactsListResponse["data"][number], NonNullable<CampaignsContactsListData["query"]>>

GET /campaigns/{id}/contacts · API reference

Name Type Required Description
id string yes A campaign ID (cmp_…).
query.limit integer no How many objects to return, 1–100 (default 20).
query.starting_after string no A cursor (next_cursor) or object ID: return the objects after it (older).
query.ending_before string no A cursor or object ID: return the objects before it (newer).
query.status string no Only these statuses, comma-separated (e.g. pending,scheduled).
query.outcome string no Only contacts with this recorded disposition.
query.phone string no Only this number.
options.headers["MoreVoice-Version"] string no The API version to use for this request. Defaults to the version the API key is pinned to.
options RequestOptions no idempotencyKey, extra headers and an abort signal: see retries and idempotency.

A PagedList: await it for the first page, for await it for every item.

import { createClient, createResources } from "@morevoice/sdk";
const mv = createResources({
client: createClient({ baseUrl: "https://api.morevoice.ai/v1", auth: process.env.MOREVOICE_API_KEY }),
});
for await (const contact of mv.campaigns.contacts.list("cmp_ojFwMD7YNTROjaTP0i3ZFb")) {
console.log(contact);
}

List a contact’s dial attempts.

mv.campaigns.contacts.listAttempts(id: CampaignsContactsListAttemptsData["path"]["id"], contactId: CampaignsContactsListAttemptsData["path"]["contact_id"], query?: NonNullable<CampaignsContactsListAttemptsData["query"]>, options?: RequestOptions): PagedList<CampaignsContactsListAttemptsResponse["data"][number], NonNullable<CampaignsContactsListAttemptsData["query"]>>

GET /campaigns/{id}/contacts/{contact_id}/attempts · API reference

Name Type Required Description
id string yes A campaign ID (cmp_…).
contact_id string yes A contact ID (ctc_…).
query.limit integer no How many objects to return, 1–100 (default 20).
query.starting_after string no A cursor (next_cursor) or object ID: return the objects after it (older).
query.ending_before string no A cursor or object ID: return the objects before it (newer).
options.headers["MoreVoice-Version"] string no The API version to use for this request. Defaults to the version the API key is pinned to.
options RequestOptions no idempotencyKey, extra headers and an abort signal: see retries and idempotency.

A PagedList: await it for the first page, for await it for every item.

import { createClient, createResources } from "@morevoice/sdk";
const mv = createResources({
client: createClient({ baseUrl: "https://api.morevoice.ai/v1", auth: process.env.MOREVOICE_API_KEY }),
});
for await (const contact of mv.campaigns.contacts.listAttempts("cmp_ojFwMD7YNTROjaTP0i3ZFb", "ctc_NKhjnYPvBUr2gmEgqwqw5N")) {
console.log(contact);
}

Retrieve a campaign contact.

mv.campaigns.contacts.retrieve(id: CampaignsContactsRetrieveData["path"]["id"], contactId: CampaignsContactsRetrieveData["path"]["contact_id"], options?: RequestOptions): Promise<CampaignsContactsRetrieveResponse>

GET /campaigns/{id}/contacts/{contact_id} · API reference

Name Type Required Description
id string yes A campaign ID (cmp_…).
contact_id string yes A contact ID (ctc_…).
options.headers["MoreVoice-Version"] string no The API version to use for this request. Defaults to the version the API key is pinned to.
options RequestOptions no idempotencyKey, extra headers and an abort signal: see retries and idempotency.

CampaignContact:

Field Type Description
id string A contact ID (prefix ctc_).
object "campaign_contact" Always campaign_contact.
livemode boolean true in live mode, false in test mode.
campaign_id string A campaign ID (prefix cmp_).
phone string E.164.
name string —
variables Record<string, string> —
timezone string | null —
consent boolean The import said the person consented. Marketing calls also need a consent record with evidence (§30A).
status "pending" | "scheduled" | "callback" | "dialing" | "done" | "failed" | "dnc" | "skipped" | … pending → dialing → scheduled | callback → … → done | failed; skipped, dnc, invalid and cancelled are never dialled.
skip_reason string | null Why it is not dialled: dnc_import, dnc_dial_time, registry, no_consent, no_consent_evidence, no_calling_window, manual, …
attempts integer —
next_attempt_at string | null When it is due (dialable statuses only).
last_result string | null The last attempt’s result (answered, no_answer, busy, voicemail, …).
outcome string | null The disposition the assistant recorded.
outcome_data object | null —
last_call_id string | null call_… ID.
last_attempt_at string | null —
completed_at string | null —
row integer | null The row it came from in its import.
created_at string An ISO-8601 timestamp in UTC.
updated_at string An ISO-8601 timestamp in UTC.
import { createClient, createResources } from "@morevoice/sdk";
const mv = createResources({
client: createClient({ baseUrl: "https://api.morevoice.ai/v1", auth: process.env.MOREVOICE_API_KEY }),
});
const campaignContact = await mv.campaigns.contacts.retrieve("cmp_ojFwMD7YNTROjaTP0i3ZFb", "ctc_NKhjnYPvBUr2gmEgqwqw5N");
console.log(campaignContact);

Requeue or skip a campaign contact. status scheduled dials the contact again now (refused for a number on the do-not-call list); skipped takes it out of the campaign. A contact being dialled can’t change.

mv.campaigns.contacts.update(id: CampaignsContactsUpdateData["path"]["id"], contactId: CampaignsContactsUpdateData["path"]["contact_id"], body: CampaignsContactsUpdateData["body"], options?: RequestOptions): Promise<CampaignsContactsUpdateResponse>

PATCH /campaigns/{id}/contacts/{contact_id} · API reference

Name Type Required Description
id string yes A campaign ID (cmp_…).
contact_id string yes A contact ID (ctc_…).
body.status "scheduled" | "skipped" yes scheduled: dial it again now (refused for a do-not-call number); skipped: take it out of the campaign.
options.headers["MoreVoice-Version"] string no The API version to use for this request. Defaults to the version the API key is pinned to.
options RequestOptions no idempotencyKey, extra headers and an abort signal: see retries and idempotency.

CampaignContact:

Field Type Description
id string A contact ID (prefix ctc_).
object "campaign_contact" Always campaign_contact.
livemode boolean true in live mode, false in test mode.
campaign_id string A campaign ID (prefix cmp_).
phone string E.164.
name string —
variables Record<string, string> —
timezone string | null —
consent boolean The import said the person consented. Marketing calls also need a consent record with evidence (§30A).
status "pending" | "scheduled" | "callback" | "dialing" | "done" | "failed" | "dnc" | "skipped" | … pending → dialing → scheduled | callback → … → done | failed; skipped, dnc, invalid and cancelled are never dialled.
skip_reason string | null Why it is not dialled: dnc_import, dnc_dial_time, registry, no_consent, no_consent_evidence, no_calling_window, manual, …
attempts integer —
next_attempt_at string | null When it is due (dialable statuses only).
last_result string | null The last attempt’s result (answered, no_answer, busy, voicemail, …).
outcome string | null The disposition the assistant recorded.
outcome_data object | null —
last_call_id string | null call_… ID.
last_attempt_at string | null —
completed_at string | null —
row integer | null The row it came from in its import.
created_at string An ISO-8601 timestamp in UTC.
updated_at string An ISO-8601 timestamp in UTC.
import { createClient, createResources } from "@morevoice/sdk";
const mv = createResources({
client: createClient({ baseUrl: "https://api.morevoice.ai/v1", auth: process.env.MOREVOICE_API_KEY }),
});
const campaignContact = await mv.campaigns.contacts.update("cmp_ojFwMD7YNTROjaTP0i3ZFb", "ctc_NKhjnYPvBUr2gmEgqwqw5N", {
status: "skipped",
});
console.log(campaignContact);

Create a campaign. Creates a draft campaign. Add contacts, then start it. The purpose decides the compliance checks: marketing needs consent with evidence (§30A) and, for Israeli numbers, the national do-not-call registry.

mv.campaigns.create(body: CampaignsCreateData["body"], options?: RequestOptions): Promise<CampaignsCreateResponse>

POST /campaigns · API reference

Name Type Required Description
body.name string yes
body.purpose "marketing" | "service" | "survey" yes Required on create: marketing, service or survey. It decides the compliance checks.
body.amd object no
body.assistant_id string | null no asst_… ID.
body.caller_id string | null no
body.calls_per_second integer no
body.connection_id string | null no conn_… ID.
body.disclosure object no
body.dispositions string[] no
body.first_message string no Overrides the assistant’s first message. {{variables}} come from the contacts’ variables, name and phone.
body.max_concurrent integer no
body.opt_out_dtmf_key string | null no
body.priority integer no
body.retry object no
body.ring_timeout_seconds integer no
body.schedule object no
body.script string no Extra instructions for the assistant. {{variables}} come from the contacts’ variables, name and phone.
options.headers["MoreVoice-Version"] string no The API version to use for this request. Defaults to the version the API key is pinned to.
options.headers["Idempotency-Key"] string no A unique key (for example a UUID) that makes this request safe to retry: for 24 hours, a retry with the same key and parameters returns the first response instead of acting twice.
options RequestOptions no idempotencyKey, extra headers and an abort signal: see retries and idempotency.

Campaign:

Field Type Description
id string A campaign ID (prefix cmp_).
object "campaign" Always campaign.
livemode boolean true in live mode, false in test mode.
name string —
state "draft" | "scheduled" | "running" | "paused" | "completed" | "cancelled" draft → running ⇄ paused → completed | cancelled (scheduled: waits for schedule.start_at).
purpose "marketing" | "service" | "survey" marketing needs recorded consent with evidence (§30A) and a national-registry check for Israeli numbers.
assistant_id string | null asst_… ID.
connection_id string | null The SIP connection it dials through; null: the default one.
caller_id string | null The number presented to contacts; null: the connection’s default.
priority integer 1–10; higher is served first when campaigns compete for lines.
max_concurrent integer Simultaneous calls this campaign may hold.
calls_per_second integer New calls per second; 0: only the connection limits it.
schedule CampaignSchedule When the campaign dials.
ring_timeout_seconds integer Hang up an unanswered call after this long.
retry CampaignRetry Retry policy per call result.
amd CampaignAmd Answering-machine detection.
disclosure CampaignDisclosure The AI and recording disclosure played at the start of each call.
first_message string Overrides the assistant’s first message ({{variables}} allowed); empty: the assistant’s.
script string Extra instructions for this campaign ({{variables}} allowed).
dispositions string[] Outcomes the assistant can record.
opt_out_dtmf_key string | null The key that opts a contact out; null: the organisation’s.
pause_reason string | null Why the campaign paused itself (for example, the national registry can’t check it).
stats CampaignStats Contact counts per status and the calls in progress.
created_at string An ISO-8601 timestamp in UTC.
updated_at string An ISO-8601 timestamp in UTC.
started_at string | null —
completed_at string | null —
import { createClient, createResources } from "@morevoice/sdk";
const mv = createResources({
client: createClient({ baseUrl: "https://api.morevoice.ai/v1", auth: process.env.MOREVOICE_API_KEY }),
});
const campaign = await mv.campaigns.create({
assistant_id: "asst_3kTzL9Qe2R",
name: "November renewals",
purpose: "marketing",
retry: {
busy: {
delay_minutes: 30,
},
max_attempts: 3,
no_answer: {
delay_minutes: 240,
},
},
schedule: {
respect_shabbat: true,
timezone: "Asia/Jerusalem",
windows: [
{
days: [
"sun",
"mon",
"tue",
"wed",
"thu",
],
end: "19:00",
start: "09:00",
},
],
},
});
console.log(campaign);

Delete a campaign. Deletes a campaign that is not running or scheduled, with its contacts and attempts. Calls already made stay in the call log.

mv.campaigns.delete(id: CampaignsDeleteData["path"]["id"], options?: RequestOptions): Promise<CampaignsDeleteResponse>

DELETE /campaigns/{id} · API reference

Name Type Required Description
id string yes A campaign ID (cmp_…).
options.headers["MoreVoice-Version"] string no The API version to use for this request. Defaults to the version the API key is pinned to.
options.headers["Idempotency-Key"] string no A unique key (for example a UUID) that makes this request safe to retry: for 24 hours, a retry with the same key and parameters returns the first response instead of acting twice.
options RequestOptions no idempotencyKey, extra headers and an abort signal: see retries and idempotency.

DeletedCampaign:

Field Type Description
id string A campaign ID (prefix cmp_).
object "campaign" Always campaign.
deleted true —
import { createClient, createResources } from "@morevoice/sdk";
const mv = createResources({
client: createClient({ baseUrl: "https://api.morevoice.ai/v1", auth: process.env.MOREVOICE_API_KEY }),
});
const deletedCampaign = await mv.campaigns.delete("cmp_ojFwMD7YNTROjaTP0i3ZFb");
console.log(deletedCampaign);

Export a campaign’s contacts or attempts as CSV. The dashboard’s export, streamed: UTF-8 with a byte-order mark (opens in Excel with Hebrew intact). kind=contacts (default) has one row per contact with its result and variables; kind=attempts one row per dial attempt.

mv.campaigns.export(id: CampaignsExportData["path"]["id"], query?: NonNullable<CampaignsExportData["query"]>, options?: RequestOptions): Promise<CampaignsExportResponse>

GET /campaigns/{id}/export · API reference

Name Type Required Description
id string yes A campaign ID (cmp_…).
query.kind string no contacts (default) or attempts.
options.headers["MoreVoice-Version"] string no The API version to use for this request. Defaults to the version the API key is pinned to.
options RequestOptions no idempotencyKey, extra headers and an abort signal: see retries and idempotency.

Nothing, on success.

import { createClient, createResources } from "@morevoice/sdk";
const mv = createResources({
client: createClient({ baseUrl: "https://api.morevoice.ai/v1", auth: process.env.MOREVOICE_API_KEY }),
});
const result = await mv.campaigns.export("cmp_ojFwMD7YNTROjaTP0i3ZFb");
console.log(result);

List campaigns.

mv.campaigns.list(query?: NonNullable<CampaignsListData["query"]>, options?: RequestOptions): PagedList<CampaignsListResponse["data"][number], NonNullable<CampaignsListData["query"]>>

GET /campaigns · API reference

Name Type Required Description
query.limit integer no How many objects to return, 1–100 (default 20).
query.starting_after string no A cursor (next_cursor) or object ID: return the objects after it (older).
query.ending_before string no A cursor or object ID: return the objects before it (newer).
query.state string no Only campaigns in this state.
query.purpose string no Only campaigns with this purpose.
options.headers["MoreVoice-Version"] string no The API version to use for this request. Defaults to the version the API key is pinned to.
options RequestOptions no idempotencyKey, extra headers and an abort signal: see retries and idempotency.

A PagedList: await it for the first page, for await it for every item.

import { createClient, createResources } from "@morevoice/sdk";
const mv = createResources({
client: createClient({ baseUrl: "https://api.morevoice.ai/v1", auth: process.env.MOREVOICE_API_KEY }),
});
for await (const campaign of mv.campaigns.list()) {
console.log(campaign);
}

Pause a campaign. Stops dialling new calls; calls in progress finish. Resume it to continue.

mv.campaigns.pause(id: CampaignsPauseData["path"]["id"], body?: CampaignsPauseData["body"], options?: RequestOptions): Promise<CampaignsPauseResponse>

POST /campaigns/{id}/pause · API reference

Name Type Required Description
id string yes A campaign ID (cmp_…).
options.headers["MoreVoice-Version"] string no The API version to use for this request. Defaults to the version the API key is pinned to.
options.headers["Idempotency-Key"] string no A unique key (for example a UUID) that makes this request safe to retry: for 24 hours, a retry with the same key and parameters returns the first response instead of acting twice.
options RequestOptions no idempotencyKey, extra headers and an abort signal: see retries and idempotency.

Campaign:

Field Type Description
id string A campaign ID (prefix cmp_).
object "campaign" Always campaign.
livemode boolean true in live mode, false in test mode.
name string —
state "draft" | "scheduled" | "running" | "paused" | "completed" | "cancelled" draft → running ⇄ paused → completed | cancelled (scheduled: waits for schedule.start_at).
purpose "marketing" | "service" | "survey" marketing needs recorded consent with evidence (§30A) and a national-registry check for Israeli numbers.
assistant_id string | null asst_… ID.
connection_id string | null The SIP connection it dials through; null: the default one.
caller_id string | null The number presented to contacts; null: the connection’s default.
priority integer 1–10; higher is served first when campaigns compete for lines.
max_concurrent integer Simultaneous calls this campaign may hold.
calls_per_second integer New calls per second; 0: only the connection limits it.
schedule CampaignSchedule When the campaign dials.
ring_timeout_seconds integer Hang up an unanswered call after this long.
retry CampaignRetry Retry policy per call result.
amd CampaignAmd Answering-machine detection.
disclosure CampaignDisclosure The AI and recording disclosure played at the start of each call.
first_message string Overrides the assistant’s first message ({{variables}} allowed); empty: the assistant’s.
script string Extra instructions for this campaign ({{variables}} allowed).
dispositions string[] Outcomes the assistant can record.
opt_out_dtmf_key string | null The key that opts a contact out; null: the organisation’s.
pause_reason string | null Why the campaign paused itself (for example, the national registry can’t check it).
stats CampaignStats Contact counts per status and the calls in progress.
created_at string An ISO-8601 timestamp in UTC.
updated_at string An ISO-8601 timestamp in UTC.
started_at string | null —
completed_at string | null —
import { createClient, createResources } from "@morevoice/sdk";
const mv = createResources({
client: createClient({ baseUrl: "https://api.morevoice.ai/v1", auth: process.env.MOREVOICE_API_KEY }),
});
const campaign = await mv.campaigns.pause("cmp_ojFwMD7YNTROjaTP0i3ZFb", {});
console.log(campaign);

Check whether a campaign can start.

mv.campaigns.preflight(id: CampaignsPreflightData["path"]["id"], options?: RequestOptions): Promise<CampaignsPreflightResponse>

GET /campaigns/{id}/preflight · API reference

Name Type Required Description
id string yes A campaign ID (cmp_…).
options.headers["MoreVoice-Version"] string no The API version to use for this request. Defaults to the version the API key is pinned to.
options RequestOptions no idempotencyKey, extra headers and an abort signal: see retries and idempotency.

CampaignPreflight:

Field Type Description
object "campaign_preflight" Always campaign_preflight.
campaign_id string A campaign ID (prefix cmp_).
ok boolean No errors: the campaign can start.
errors string[] What blocks the start (missing assistant or connection, no contacts, no marketing consent, no registry, …).
warnings string[] What the dialer will skip or delay (contacts without consent, outside calling hours now, …).
dialable integer Contacts the dialer may call.
window_open boolean Calling is allowed right now (calling hours, Shabbat, holidays).
next_window_at string | null When calling is next allowed; null if never in the next 3 weeks.
import { createClient, createResources } from "@morevoice/sdk";
const mv = createResources({
client: createClient({ baseUrl: "https://api.morevoice.ai/v1", auth: process.env.MOREVOICE_API_KEY }),
});
const campaignPreflight = await mv.campaigns.preflight("cmp_ojFwMD7YNTROjaTP0i3ZFb");
console.log(campaignPreflight);

Resume a paused campaign. Runs the pre-flight checks again and resumes dialling.

mv.campaigns.resume(id: CampaignsResumeData["path"]["id"], body?: CampaignsResumeData["body"], options?: RequestOptions): Promise<CampaignsResumeResponse>

POST /campaigns/{id}/resume · API reference

Name Type Required Description
id string yes A campaign ID (cmp_…).
options.headers["MoreVoice-Version"] string no The API version to use for this request. Defaults to the version the API key is pinned to.
options.headers["Idempotency-Key"] string no A unique key (for example a UUID) that makes this request safe to retry: for 24 hours, a retry with the same key and parameters returns the first response instead of acting twice.
options RequestOptions no idempotencyKey, extra headers and an abort signal: see retries and idempotency.

Campaign:

Field Type Description
id string A campaign ID (prefix cmp_).
object "campaign" Always campaign.
livemode boolean true in live mode, false in test mode.
name string —
state "draft" | "scheduled" | "running" | "paused" | "completed" | "cancelled" draft → running ⇄ paused → completed | cancelled (scheduled: waits for schedule.start_at).
purpose "marketing" | "service" | "survey" marketing needs recorded consent with evidence (§30A) and a national-registry check for Israeli numbers.
assistant_id string | null asst_… ID.
connection_id string | null The SIP connection it dials through; null: the default one.
caller_id string | null The number presented to contacts; null: the connection’s default.
priority integer 1–10; higher is served first when campaigns compete for lines.
max_concurrent integer Simultaneous calls this campaign may hold.
calls_per_second integer New calls per second; 0: only the connection limits it.
schedule CampaignSchedule When the campaign dials.
ring_timeout_seconds integer Hang up an unanswered call after this long.
retry CampaignRetry Retry policy per call result.
amd CampaignAmd Answering-machine detection.
disclosure CampaignDisclosure The AI and recording disclosure played at the start of each call.
first_message string Overrides the assistant’s first message ({{variables}} allowed); empty: the assistant’s.
script string Extra instructions for this campaign ({{variables}} allowed).
dispositions string[] Outcomes the assistant can record.
opt_out_dtmf_key string | null The key that opts a contact out; null: the organisation’s.
pause_reason string | null Why the campaign paused itself (for example, the national registry can’t check it).
stats CampaignStats Contact counts per status and the calls in progress.
created_at string An ISO-8601 timestamp in UTC.
updated_at string An ISO-8601 timestamp in UTC.
started_at string | null —
completed_at string | null —
import { createClient, createResources } from "@morevoice/sdk";
const mv = createResources({
client: createClient({ baseUrl: "https://api.morevoice.ai/v1", auth: process.env.MOREVOICE_API_KEY }),
});
const campaign = await mv.campaigns.resume("cmp_ojFwMD7YNTROjaTP0i3ZFb", {});
console.log(campaign);

Retrieve a campaign.

mv.campaigns.retrieve(id: CampaignsRetrieveData["path"]["id"], options?: RequestOptions): Promise<CampaignsRetrieveResponse>

GET /campaigns/{id} · API reference

Name Type Required Description
id string yes A campaign ID (cmp_…).
options.headers["MoreVoice-Version"] string no The API version to use for this request. Defaults to the version the API key is pinned to.
options RequestOptions no idempotencyKey, extra headers and an abort signal: see retries and idempotency.

Campaign:

Field Type Description
id string A campaign ID (prefix cmp_).
object "campaign" Always campaign.
livemode boolean true in live mode, false in test mode.
name string —
state "draft" | "scheduled" | "running" | "paused" | "completed" | "cancelled" draft → running ⇄ paused → completed | cancelled (scheduled: waits for schedule.start_at).
purpose "marketing" | "service" | "survey" marketing needs recorded consent with evidence (§30A) and a national-registry check for Israeli numbers.
assistant_id string | null asst_… ID.
connection_id string | null The SIP connection it dials through; null: the default one.
caller_id string | null The number presented to contacts; null: the connection’s default.
priority integer 1–10; higher is served first when campaigns compete for lines.
max_concurrent integer Simultaneous calls this campaign may hold.
calls_per_second integer New calls per second; 0: only the connection limits it.
schedule CampaignSchedule When the campaign dials.
ring_timeout_seconds integer Hang up an unanswered call after this long.
retry CampaignRetry Retry policy per call result.
amd CampaignAmd Answering-machine detection.
disclosure CampaignDisclosure The AI and recording disclosure played at the start of each call.
first_message string Overrides the assistant’s first message ({{variables}} allowed); empty: the assistant’s.
script string Extra instructions for this campaign ({{variables}} allowed).
dispositions string[] Outcomes the assistant can record.
opt_out_dtmf_key string | null The key that opts a contact out; null: the organisation’s.
pause_reason string | null Why the campaign paused itself (for example, the national registry can’t check it).
stats CampaignStats Contact counts per status and the calls in progress.
created_at string An ISO-8601 timestamp in UTC.
updated_at string An ISO-8601 timestamp in UTC.
started_at string | null —
completed_at string | null —
import { createClient, createResources } from "@morevoice/sdk";
const mv = createResources({
client: createClient({ baseUrl: "https://api.morevoice.ai/v1", auth: process.env.MOREVOICE_API_KEY }),
});
const campaign = await mv.campaigns.retrieve("cmp_ojFwMD7YNTROjaTP0i3ZFb");
console.log(campaign);

Start a campaign. Runs the dashboard’s pre-flight checks and starts dialling (or schedules the start). A failed check answers 409 preflight_failed with the list. Once running, every call is still checked against the do-not-call list, consent, the national registry, the calling hours and Shabbat; a marketing campaign the registry can’t check pauses itself (pause_reason).

mv.campaigns.start(id: CampaignsStartData["path"]["id"], body?: CampaignsStartData["body"], options?: RequestOptions): Promise<CampaignsStartResponse>

POST /campaigns/{id}/start · API reference

Name Type Required Description
id string yes A campaign ID (cmp_…).
body.start_at string | null no Start later: the campaign is scheduled and starts dialling at this time.
options.headers["MoreVoice-Version"] string no The API version to use for this request. Defaults to the version the API key is pinned to.
options.headers["Idempotency-Key"] string no A unique key (for example a UUID) that makes this request safe to retry: for 24 hours, a retry with the same key and parameters returns the first response instead of acting twice.
options RequestOptions no idempotencyKey, extra headers and an abort signal: see retries and idempotency.

Campaign:

Field Type Description
id string A campaign ID (prefix cmp_).
object "campaign" Always campaign.
livemode boolean true in live mode, false in test mode.
name string —
state "draft" | "scheduled" | "running" | "paused" | "completed" | "cancelled" draft → running ⇄ paused → completed | cancelled (scheduled: waits for schedule.start_at).
purpose "marketing" | "service" | "survey" marketing needs recorded consent with evidence (§30A) and a national-registry check for Israeli numbers.
assistant_id string | null asst_… ID.
connection_id string | null The SIP connection it dials through; null: the default one.
caller_id string | null The number presented to contacts; null: the connection’s default.
priority integer 1–10; higher is served first when campaigns compete for lines.
max_concurrent integer Simultaneous calls this campaign may hold.
calls_per_second integer New calls per second; 0: only the connection limits it.
schedule CampaignSchedule When the campaign dials.
ring_timeout_seconds integer Hang up an unanswered call after this long.
retry CampaignRetry Retry policy per call result.
amd CampaignAmd Answering-machine detection.
disclosure CampaignDisclosure The AI and recording disclosure played at the start of each call.
first_message string Overrides the assistant’s first message ({{variables}} allowed); empty: the assistant’s.
script string Extra instructions for this campaign ({{variables}} allowed).
dispositions string[] Outcomes the assistant can record.
opt_out_dtmf_key string | null The key that opts a contact out; null: the organisation’s.
pause_reason string | null Why the campaign paused itself (for example, the national registry can’t check it).
stats CampaignStats Contact counts per status and the calls in progress.
created_at string An ISO-8601 timestamp in UTC.
updated_at string An ISO-8601 timestamp in UTC.
started_at string | null —
completed_at string | null —
import { createClient, createResources } from "@morevoice/sdk";
const mv = createResources({
client: createClient({ baseUrl: "https://api.morevoice.ai/v1", auth: process.env.MOREVOICE_API_KEY }),
});
const campaign = await mv.campaigns.start("cmp_ojFwMD7YNTROjaTP0i3ZFb", {});
console.log(campaign);

Retrieve a campaign’s results.

mv.campaigns.stats(id: CampaignsStatsData["path"]["id"], options?: RequestOptions): Promise<CampaignsStatsResponse>

GET /campaigns/{id}/stats · API reference

Name Type Required Description
id string yes A campaign ID (cmp_…).
options.headers["MoreVoice-Version"] string no The API version to use for this request. Defaults to the version the API key is pinned to.
options RequestOptions no idempotencyKey, extra headers and an abort signal: see retries and idempotency.

CampaignResults:

Field Type Description
object "campaign_stats" Always campaign_stats.
campaign_id string A campaign ID (prefix cmp_).
livemode boolean true in live mode, false in test mode.
contacts CampaignStats Contact counts per status and the calls in progress.
attempts object —
outcomes Record<string, integer> Contacts per recorded disposition (interested, not-interested, …).
skip_reasons Record<string, integer> Contacts the compliance checks or a user took out, per reason (dnc_import, registry, no_consent, …).
import { createClient, createResources } from "@morevoice/sdk";
const mv = createResources({
client: createClient({ baseUrl: "https://api.morevoice.ai/v1", auth: process.env.MOREVOICE_API_KEY }),
});
const campaignResults = await mv.campaigns.stats("cmp_ojFwMD7YNTROjaTP0i3ZFb");
console.log(campaignResults);

Update a campaign. Changes the fields you send and keeps the rest. A completed or cancelled campaign can’t change; pause a running one before changing its purpose.

mv.campaigns.update(id: CampaignsUpdateData["path"]["id"], body?: CampaignsUpdateData["body"], options?: RequestOptions): Promise<CampaignsUpdateResponse>

PATCH /campaigns/{id} · API reference

Name Type Required Description
id string yes A campaign ID (cmp_…).
body.amd object no
body.assistant_id string | null no asst_… ID.
body.caller_id string | null no
body.calls_per_second integer no
body.connection_id string | null no conn_… ID.
body.disclosure object no
body.dispositions string[] no
body.first_message string no Overrides the assistant’s first message. {{variables}} come from the contacts’ variables, name and phone.
body.max_concurrent integer no
body.name string no
body.opt_out_dtmf_key string | null no
body.priority integer no
body.purpose "marketing" | "service" | "survey" no Required on create: marketing, service or survey. It decides the compliance checks.
body.retry object no
body.ring_timeout_seconds integer no
body.schedule object no
body.script string no Extra instructions for the assistant. {{variables}} come from the contacts’ variables, name and phone.
options.headers["MoreVoice-Version"] string no The API version to use for this request. Defaults to the version the API key is pinned to.
options RequestOptions no idempotencyKey, extra headers and an abort signal: see retries and idempotency.

Campaign:

Field Type Description
id string A campaign ID (prefix cmp_).
object "campaign" Always campaign.
livemode boolean true in live mode, false in test mode.
name string —
state "draft" | "scheduled" | "running" | "paused" | "completed" | "cancelled" draft → running ⇄ paused → completed | cancelled (scheduled: waits for schedule.start_at).
purpose "marketing" | "service" | "survey" marketing needs recorded consent with evidence (§30A) and a national-registry check for Israeli numbers.
assistant_id string | null asst_… ID.
connection_id string | null The SIP connection it dials through; null: the default one.
caller_id string | null The number presented to contacts; null: the connection’s default.
priority integer 1–10; higher is served first when campaigns compete for lines.
max_concurrent integer Simultaneous calls this campaign may hold.
calls_per_second integer New calls per second; 0: only the connection limits it.
schedule CampaignSchedule When the campaign dials.
ring_timeout_seconds integer Hang up an unanswered call after this long.
retry CampaignRetry Retry policy per call result.
amd CampaignAmd Answering-machine detection.
disclosure CampaignDisclosure The AI and recording disclosure played at the start of each call.
first_message string Overrides the assistant’s first message ({{variables}} allowed); empty: the assistant’s.
script string Extra instructions for this campaign ({{variables}} allowed).
dispositions string[] Outcomes the assistant can record.
opt_out_dtmf_key string | null The key that opts a contact out; null: the organisation’s.
pause_reason string | null Why the campaign paused itself (for example, the national registry can’t check it).
stats CampaignStats Contact counts per status and the calls in progress.
created_at string An ISO-8601 timestamp in UTC.
updated_at string An ISO-8601 timestamp in UTC.
started_at string | null —
completed_at string | null —
import { createClient, createResources } from "@morevoice/sdk";
const mv = createResources({
client: createClient({ baseUrl: "https://api.morevoice.ai/v1", auth: process.env.MOREVOICE_API_KEY }),
});
const campaign = await mv.campaigns.update("cmp_ojFwMD7YNTROjaTP0i3ZFb", {
max_concurrent: 20,
schedule: {
end_at: "2026-11-30T18:00:00+02:00",
},
});
console.log(campaign);