Guide & Integration

Download Guide (.md)

Pak Sender sends SMS, voice calls and emails to your customers — OTP codes, invoices, daily payment reports, thank-you messages, loyalty points, offers and new-stock alerts. Everything can be done by hand on the website or automatically from your own software through the API.

FeatureManual (website page)Automatic (API)
SMS / voice OTP / voice callSend MessagePOST /messages/send-sms, /messages/send-voice-otp, /messages/send-voice-call
One SMS to many numbersBulk CampaignsPOST /messages/send-bulk-sms
Email campaignsEmail Marketing—
Invoice / receipt / statementInvoice via Email / SMSPOST /invoices
Many people, own amountsBulk InvoicesPOST /invoices/bulk
Daily payments → reportDaily Entries & ReportsPOST /entries, /entries/report
Repeat daily / weekly / monthlyInvoice form → Schedule / repeatPOST /invoice-schedules
Thank-you, points, order updatesAutomations (+ Send test)POST /events
Sales, offers, new stockOffers & BroadcastsPOST /broadcasts
Customer list & tagsCustomer ContactsPOST /contacts

Account setup (once)

1
Register & verify your email. Email marketing works immediately.
2
Submit KYC (CNIC / business documents). After approval SMS, voice, bulk and API are unlocked. Until then these pages show a lock.
3
Add balance from Payments. One PKR balance pays for SMS, voice and email.
4
For email: Email Marketing → SMTP Settings → add your mailbox (Gmail app password, Hostinger, Zoho…). Emails are sent from your own address; the API refers to it by its SMTP username. Hitting daily limits? Add several mailboxes and pass them all — "smtp": ["a@shop.com","b@shop.com"] (or select several on the website). Each email goes through the account with the most sends left today, full accounts are skipped and a failed send is retried on the next one.
5
For automation: API Keys → create a key and paste it into your software. Keep it secret — it can spend your balance.
Schedules, recurring invoices, delayed automations and broadcasts run on our servers — nothing has to stay open on your side.

Who receives what?

We only send to numbers / emails that you give us. This table shows where the recipient comes from in each feature:

You use…It goes to…
Send Message / Bulk CampaignThe number(s) you type or upload
Invoice (web or POST /invoices)The customer_phone (SMS) or customer_email (email) on that invoice
Bulk invoicesEach row / document's own phone or email — rows with the same person are merged into one document
Daily entries reportThe phone / email saved with that customer's entries (customer_ref)
Recurring invoiceThe customer on the schedule (or the one your source_url returns each time)
Automation, audience event_customerThe customer sent with the event
Automation / broadcast, audience allAll your Customer Contacts
Automation / broadcast, audience tagOnly contacts with that tag (vip, wholesale, lahore…)
Contacts who unsubscribe (link in email, or sms_opt_out / email_opt_out) are skipped automatically by automations and broadcasts. Only message people who expect to hear from you.

Manual: SMS, voice & email

Send Message — choose SMS, Voice OTP or Voice Call, enter the number(s) and text, see the cost preview, press Send. Urdu is supported (Unicode, 70 characters per part). Bulk Campaigns — upload a CSV of numbers. Email Marketing — contacts, lists, templates and campaigns with open / click tracking.

Manual: invoices & receipts

1
Open Invoice via Email or Invoice via SMS.
2
Pick the document type — Invoice, Receipt or Statement / Report.
3
Enter the customer, then one line per product / payment (date, description, qty, price). Tax and discount are optional.
4
Choose a template (Load) — the live preview shows exactly what the customer receives.
5
Send now, or Schedule / repeat (see recurring). Every invoice is saved in All Invoices with print / PDF.

Templates live in Invoice Templates. You can also import any Email Marketing template and add placeholders such as {{customer_name}}, {{items_table}}, {{total}}.

Manual: bulk invoices / reports

Bulk Invoices → choose SMS or email and the document type → paste rows:

Ali Khan, 03001234567, 2026-09-28, Payment received, 70
Ali Khan, 03001234567, 2026-09-29, Payment received, 80
Sara,     03002222222, 2026-09-29, Voucher #12, 1500

Ali gets one statement with both dates (total 150), Sara gets her own. The result of every person is shown after sending.

Manual: daily entries & reports

Use this when a customer has many small payments / vouchers during the day or month.

1
Daily Entries & Reports → add entries (customer ID, name, mobile/email, date, description, amount) — one by one or paste many.
2
The page shows every customer with new (unreported) entries and their total.
3
Press SMS / Email to send that customer's statement now, or Send all reports now.
4
Or press Auto → every day / week / month / N days, first send time, until date. Each run sends only the new entries; if there are none, nothing is sent or charged.

Manual: recurring invoices

On the invoice form choose Schedule / repeat: one time on a date, every day, week, month or N days; first send date & time (Pakistan time); stop on a date or after N invoices. Manage them in Recurring Invoices — send now, pause, resume, cancel.

Manual: automations, offers & contacts

Automations — "when EVENT happens → send". Start from an example (thank-you after order, loyalty points, order shipped, review request after 1 day, sale for everyone, new stock for a tag), adjust the text and press Send test to try it on your own number. Events normally come from your software (next section).

Offers & Broadcasts — write the offer, choose all contacts or a tag, send now or at a date & time. Customer Contacts — add / import customers and tags; contacts are also created automatically from every event.

Automatic: API basics

  • Base URL: https://paksender.com/api/v1
  • Header: Authorization: Bearer YOUR_API_KEY (or X-API-Key) and Content-Type: application/json
  • Every response: {"status":"success","message":"…","data":{…}} or {"status":"error","message":"…","error_code":"…"}
  • Common error codes: AUTH_ERROR (401), VALIDATION_ERROR (422), INSUFFICIENT_BALANCE (402), KYC_REQUIRED / FEATURE_DISABLED (403), NOT_FOUND (404)
  • Send your own reference (external_ref, external_id) — it comes back in responses and webhooks, and makes retries safe.

A tiny PHP helper used by the recipes below:

<?php
const API_BASE = 'https://paksender.com/api/v1';
const API_KEY  = 'YOUR_API_KEY';


function api_call(string $method, string $path, array $body = []): array
{
    $ch = curl_init(API_BASE . $path);
    curl_setopt_array($ch, [
        CURLOPT_CUSTOMREQUEST  => $method,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 30,
        CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . API_KEY, 'Content-Type: application/json', 'Accept: application/json'],
        CURLOPT_POSTFIELDS     => $body ? json_encode($body) : null,
    ]);
    $res = json_decode(curl_exec($ch), true) ?: ['status' => 'error', 'message' => curl_error($ch)];
    curl_close($ch);
    return $res;
}

Recipe: OTP by SMS or voice

$code = random_int(100000, 999999);          // store it with an expiry on your side
api_call('POST', '/messages/send-sms', [
    'receiver_number' => '+923001234567',
    'message'         => "Your login code is $code. Valid for 5 minutes.",
]);
// voice call that reads the code:  POST /messages/send-voice-otp  {"receiver_number":"+923001234567","message":"482913"}

Recipe: one SMS to many numbers (bulk SMS)

Website: Bulk Campaigns → name, text, paste numbers (one per line) or upload a CSV → Send. API: up to 10,000 numbers per request — same text, or a personal text per number:

// same text for everyone
$r = api_call('POST', '/messages/send-bulk-sms', [
    'campaign_name' => 'Eid greetings',
    'receivers'     => ['+923001111111', '03002222222', '+923003333333'],   // or "0300…,0301…"
    'message'       => 'Eid Mubarak from Your Shop!',
]);
$campaignId = $r['data']['campaign']['id'];

// a different text per number (bills, balances, results…)
api_call('POST', '/messages/send-bulk-sms', ['messages' => [
    ['to' => '+923001111111', 'message' => 'Ali, your bill is Rs 1,200'],
    ['to' => '+923002222222', 'message' => 'Sara, your bill is Rs 950'],
]]);

// progress
api_call('GET', '/messages/bulk/' . $campaignId);   // status, sent, failed, errors

Campaigns are sent in the background in batches of 50 (usually within a couple of minutes). The balance is checked up front; each SMS is charged when it is sent. Need names, tags and unsubscribe handling? Use Offers & Broadcasts instead.

Recipe: invoice or receipt when an order is paid

api_call('POST', '/invoices', [
    'channel'        => 'email',                 // or 'sms' + customer_phone
    'doc_type'       => 'receipt',               // invoice | receipt | statement
    'smtp'           => 'billing@yourshop.com',  // your SMTP username
    'customer_name'  => $order->name,
    'customer_email' => $order->email,
    'items'          => array_map(fn($i) => ['product' => $i->name, 'qty' => $i->qty, 'price' => $i->price], $order->items),
    'discount'       => $order->discount,
    'external_ref'   => 'ORDER-' . $order->id,
    'callback_url'   => 'https://yourshop.com/webhooks/invoices',   // optional
]);

Many customers at once (e.g. today's receipts): POST /invoices/bulk with "documents": [ {…}, {…} ] — up to 100 per call.

Recipe: monthly billing (fees, rent, internet, membership)

Create the schedule once when the customer subscribes — we send every month until the end date:

$r = api_call('POST', '/invoice-schedules', [
    'channel'        => 'sms',
    'customer_name'  => 'Ali Khan',
    'customer_phone' => '+923001234567',
    'items'          => [['product' => 'Monthly fee', 'price' => 3500]],
    'frequency'      => 'monthly',               // once | daily | weekly | monthly | custom (+ interval_days)
    'start_at'       => '2026-10-01 10:00',      // Pakistan time
    'end_at'         => '2027-06-30 23:59',      // or 'max_runs' => 9
    'external_ref'   => 'STUDENT-88',
]);
$scheduleId = $r['data']['schedule']['id'];     // save it

// later: PATCH /invoice-schedules/{id}  {"status":"paused"} | {"status":"active"} | {"status":"cancelled"}

Amount changes every month? Add source_url — we fetch the current customer / lines from your system right before each send (see Webhooks & live data).

Recipe: daily report from your POS / ledger

Push every payment, voucher or sale as it happens, then let a schedule send one statement per customer every night:

// 1) whenever a payment / voucher is recorded in your software
api_call('POST', '/entries', ['entries' => [[
    'customer_ref'   => 'CUST-12',               // your customer ID
    'customer_name'  => 'Ali Traders',
    'customer_phone' => '+923001234567',
    'date'           => date('Y-m-d'),
    'description'    => 'Payment received',
    'amount'         => 70,
    'external_id'    => 'PAY-9001',              // same id again = ignored (safe retry)
]]]);

// 2) once per customer: automatic report every day at 9 PM until year end
api_call('POST', '/invoice-schedules', [
    'channel' => 'sms', 'use_entries' => true, 'customer_ref' => 'CUST-12',
    'customer_name' => 'Ali Traders', 'customer_phone' => '+923001234567',
    'frequency' => 'daily', 'start_at' => '2026-09-29 21:00', 'end_at' => '2026-12-31 23:59',
]);

// …or send whenever you want:  POST /entries/report  {"channel":"sms","customer_ref":"CUST-12"}  /  {"channel":"sms","all":true}

The customer receives, for example: "Ali Traders: Statement (27 Sep – 29 Sep) · 27 Sep Payment = PKR 70.00 · 28 Sep Payment = PKR 80.00 · Total: PKR 150.00". Reported entries are never sent twice.

Recipe: thank-you + loyalty points

1) Create the automation once (website → Automations, or POST /automations) with event order.completed and text like "Thank you {{first_name}}! Order #{{order_id}}. You earned {{points}} points." 2) From your software, on every order:

api_call('POST', '/events', [
    'event'    => 'order.completed',
    'customer' => ['external_id' => 'C-12', 'name' => 'Ali Khan', 'phone' => '+923001234567', 'tags' => ['vip']],
    'data'     => ['order_id' => '1042', 'amount' => '2,500', 'points' => 25, 'total_points' => 340],
]);

Use any event names you like (points.earned, order.shipped, birthday, payment.due…) — every active automation with that name runs. Several automations can share one event (e.g. SMS now + review request after 1 day).

Recipe: sale, offer or new stock

api_call('POST', '/broadcasts', [
    'name'         => 'New stock — winter jackets',
    'channel'      => 'sms',                     // sms | email | both
    'audience'     => 'tag', 'audience_tag' => 'vip',   // or 'audience' => 'all'
    'sms_body'     => '{{business_name}}: {{product}} now in stock! {{link}}',
    'data'         => ['product' => 'Winter jackets', 'link' => 'https://yourshop.com/jackets'],
    'send_at'      => '2026-11-01 10:00',        // empty = now
]);

Keep your contact list in sync with POST /contacts (up to 1000 per call, matched by external_id / phone / email; tags are merged).

Broadcast to any list of numbers

No contacts saved? Send straight to a list — on the website choose Send to → These numbers / emails and paste one per line, or via API:

api_call('POST', '/broadcasts', [
    'name'       => 'Eid offer',
    'channel'    => 'sms',
    'audience'   => 'numbers',
    'recipients' => ['+923001111111', '03002222222', ['phone' => '+923003333333', 'name' => 'Sara', 'data' => ['code' => 'SARA20']]],
    'sms_body'   => 'Eid Mubarak {{first_name}}! Use code {{code}} for 20% off.',
    'data'       => ['code' => 'EID20'],       // default for everyone, per-recipient "data" overrides
    'save_tag'   => 'eid-2026',                // optional: keep them as contacts with this tag
]);

WooCommerce / WordPress example

Add to your theme's functions.php (or a small plugin) together with the helper above:

add_action('woocommerce_order_status_completed', function ($order_id) {
    $o = wc_get_order($order_id);
    api_call('POST', '/events', [
        'event'    => 'order.completed',
        'customer' => [
            'external_id' => 'WC-' . $o->get_customer_id(),
            'name'        => $o->get_formatted_billing_full_name(),
            'phone'       => $o->get_billing_phone(),
            'email'       => $o->get_billing_email(),
        ],
        'data' => ['order_id' => $o->get_order_number(), 'amount' => $o->get_total(), 'points' => floor($o->get_total() / 100)],
    ]);
});

Webhooks & live data

Webhook (we → you): pass callback_url on an invoice or schedule; after every send we POST invoice.sent / invoice.failed with the full invoice and an HMAC signature. Your secret is on the Recurring Invoices page.

$raw = file_get_contents('php://input');
if (!hash_equals(hash_hmac('sha256', $raw, 'YOUR_WEBHOOK_SECRET'), $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '')) {
    http_response_code(401); exit;
}
$event = json_decode($raw, true);          // $event['invoice']['external_ref'], ['status'], ['total'] …
http_response_code(200);

Live data (we ← you): give a schedule a source_url. Right before each send we GET it and use what you return:

// https://yourapp.com/sms/invoice-data?schedule_id=…&external_ref=STUDENT-88
echo json_encode([
    'customer_name' => 'Ali Khan',
    'items'         => [['product' => 'October fee', 'price' => 3500], ['product' => 'Late fine', 'price' => 200]],
    'due_date'      => '2026-10-10',
    'skip'          => false,          // true = nothing to bill this time (no message, no charge)
]);

How it works inside

Your software / our websiteAPI check (key, KYC, balance)Message built from template + your dataSent now or queuedBalance chargedLogged + webhook
  • Instant: single invoices, events with a few recipients and API SMS are sent within the same request.
  • Queued: broadcasts, big automations, delayed messages, recurring invoices and daily reports are processed every minute by our scheduler.
  • Never twice: each message / schedule run is claimed once; entries are marked when reported; repeated external_ids are ignored.
  • History: All Invoices, Recurring Invoices, Message History and Message Activity show every message with its status and error.

Charges & limits

SMSPer part — 160 characters (70 for Urdu); long texts use several parts
EmailPer email, through your own SMTP (your provider's daily limits apply)
Invoices, reports, automations, broadcastsSame as the SMS / email they send — no extra fee
Skipped messagesFree (no entries, opted-out contact, no phone / email)
Limits per callBulk SMS 10,000 numbers · bulk invoices 100 · entries 500 · contacts 1000 · bulk web page 200 recipients

Troubleshooting

KYC_REQUIRED / SMS page locked
Your KYC is not approved yet — email still works.
"SMTP not found or not active"
Add / activate an SMTP in Email Marketing → SMTP Settings and pass its username as smtp.
INSUFFICIENT_BALANCE
Top up; scheduled items retry on their next run.
Event returns automations: 0
No active automation uses that exact event name — check spelling and that it is switched on.
Report "nothing sent"
That customer has no new entries since the last report (correct behaviour — nothing is charged).
CONTENT_BLOCKED / "Message blocked"
The text contains prohibited content (gambling / betting promotion, scams, blocked links). Nothing was sent or charged — change the text.
A message shows "Skipped"
The contact unsubscribed, or has no phone / email for that channel.
Create a free account to get your API key and the full API reference.
Chat with us!