Skip to content

Campaigns helpers

Helpers exported by @morevoice/sdk from src/lib/campaigns.ts.

Exported from @morevoice/sdk (source: packages/sdk-ts/src/lib/campaigns.ts).

interface

Rejected rows by reason (WS05 W2-09). Reasons are open: newer servers may add some. [W2 merge] The implemented API reports dnc, invalid and duplicate (contacts without consent are imported and counted in without_consent).

interface RejectedReasons {
dnc: number;
invalid: number;
duplicate: number;
[reason: string]: number;
}
interface

The asynchronous import job (GET /v1/imports/{id}). The facade’s imports.retrieve returns the full generated type.

interface ContactImport {
id: string;
object?: "import";
campaign_id?: string;
status: "pending" | "processing" | "succeeded" | "completed" | "failed" | (string & {});
imported: number;
rejected: number;
rejected_reasons: RejectedReasons;
errors_url?: string | null;
error?: { code: string; message: string } | null;
[field: string]: unknown;
}
type

What importCsv accepts as the file.

type CsvSource =
| Blob
| ArrayBuffer
| ArrayBufferView
| ReadableStream<Uint8Array>
| AsyncIterable<Uint8Array | string>
/** A file path (Node only). */
| string;
interface
interface ImportCsvOptions {
/** Contact field → column header, e.g. `{ phone: "Mobile", first_name: "Name" }`. Omitted: the server guesses. */
mapping?: Record<string, string>;
/** Country for numbers without a country code (default IL). */
default_country?: string;
/** Where the §30A marketing consent was collected (consent provenance). */
consent_source?: string;
/** The file name sent with the upload (default: the path's or File's name, else contacts.csv); `.xlsx` marks a spreadsheet. */
filename?: string;
/** Check every row's phone number before uploading (needs the optional peer libphonenumber-js). */
validate?: boolean;
/** Retrying importCsv with the same key never imports twice (default: a fresh key per call). */
idempotencyKey?: string;
signal?: AbortSignal;
/** Give up waiting for the import after this long (default 30 minutes). The import itself continues on the server. */
timeoutMs?: number;
/** First polling interval (default 1000 ms), ×1.5 per poll up to 10 s. */
pollIntervalMs?: number;
/** Called with every state of the import job. */
onProgress?: (job: ContactImport) => void;
}
interface
interface ImportCsvResult<I extends ContactImport = ContactImport> {
/** `imp_…` */
id: string;
status: I["status"];
imported: number;
rejected: number;
rejected_reasons: RejectedReasons;
/** A CSV of the rejected rows with their reasons (short-lived), when there are any. */
errors_url: string | null;
/** The final import object, as the API returned it. */
import: I;
/** The client-side check, with `validate: true`. */
validation?: CsvValidationReport;
}
interface

One multipart upload, ready to send.

interface UploadBody {
/** FormData (fetch sets the boundary) or a streamed multipart body. */
body: FormData | ReadableStream<Uint8Array>;
/** The Content-Type to send; null lets fetch set it (FormData). */
contentType: string | null;
/** A streamed body: needs `duplex: "half"` and cannot be retried. */
streaming: boolean;
}
interface

What importCsv needs from the client.

interface ImportDeps<I extends ContactImport> {
upload(campaignId: string, upload: UploadBody, options: { idempotencyKey: string; signal: AbortSignal }): Promise<I>;
retrieve(importId: string, options: { signal: AbortSignal }): Promise<I>;
/** Upload retries for re-readable sources (the client's maxRetries). */
maxRetries: number;
}
constant
const DEFAULT_IMPORT_TIMEOUT_MS;
function

The upload’s file Content-Type, from its name.

function contentTypeFor(filename: string): string;
function

Form fields besides the file, in a stable order.

function importFields(options: ImportCsvOptions): [string, string][];
function

A streamed multipart/form-data body: the fields, then the file part fed from file, then the closing boundary.

function multipartStream(fields: [string, string][], file: { filename: string; contentType: string; chunks: AsyncIterable<Uint8Array> }, boundary: string): ReadableStream<Uint8Array>;
function

Upload a contact file to a campaign and wait for the import job. See the file header.

function importCsv<I extends ContactImport>(deps: ImportDeps<I>, campaignId: string, source: CsvSource, options: ImportCsvOptions = {}): Promise<ImportCsvResult<I>>;