An account required before you can login. if you haven't have one, please register first.

You can login here.

Fill with account details as written in whatsapp message when you register. Country code is optional. if you are not using it, a full account number is required

If you forgot your password, you can always reset password.

You can register an account here.

Fill your whatsapp number and name then click register.

You will get a whatsapp message about your account and password and redirected to login page.

Webhook make responding incoming message using custom data possible.

Special note : any autoreply feature won't work if you are using webhook.

<?php
header('Content-Type: application/json; charset=utf-8');

$json = file_get_contents('php://input');
$data = json_decode($json, true);
$device = $data['device'];
$sender = $data['sender'];
$message = $data['message'];
$text= $data['text']; //button text
$member= $data['member']; //group member who send the message
$name = $data['name'];
$location = $data['location'];
$pollname= $data['pollname'];
$choices= $data['choices'];

//data below will only received by device with all feature package
//start
$url =  $data['url'];
$filename =  $data['filename'];
$extension=  $data['extension'];
//end

function sendFonnte($target, $data) {
	$curl = curl_init();

	curl_setopt_array($curl, array(
	  CURLOPT_URL => "https://api.fonnte.com/send",
	  CURLOPT_RETURNTRANSFER => true,
	  CURLOPT_ENCODING => "",
	  CURLOPT_MAXREDIRS => 10,
	  CURLOPT_TIMEOUT => 0,
	  CURLOPT_FOLLOWLOCATION => true,
	  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
	  CURLOPT_CUSTOMREQUEST => "POST",
	  CURLOPT_POSTFIELDS => array(
	    	'target' => $target,
	    	'message' => $data['message'],
	    	'url' => $data['url'],
	    	'filename' => $data['filename'],
	    ),
	  CURLOPT_HTTPHEADER => array(
	    "Authorization: TOKEN"
	  ),
	));

	$response = curl_exec($curl);

	curl_close($curl);

	return $response;
}

if ( $message == "test" ) {
	$reply = [
		"message" => "working great!",
	];
} elseif ( $message == "image" ) {
	$reply = [
		"message" => "image message",
		"url" => "https://filesamples.com/samples/image/jpg/sample_640%C3%97426.jpg",
	];
} elseif ( $message == "audio" ) {
	$reply = [
	        "message" => "audio message",
		"url" => "https://filesamples.com/samples/audio/mp3/sample3.mp3",
		"filename" => "music",
	];
} elseif ( $message == "video" ) {
	$reply = [
		"message" => "video message",
		"url" => "https://filesamples.com/samples/video/mp4/sample_640x360.mp4",
	];
} elseif ( $message == "file" ) {
	$reply = [
		"message" => "file message",
		"url" => "https://filesamples.com/samples/document/docx/sample3.docx",
		"filename" => "document",
	];
} else {
	$reply = [
		"message" => "Sorry, i don't understand. Please use one of the following keyword :
		    
Test
Audio
Video
Image
File",
];
}

sendFonnte($sender, $reply);

Available parameter

Replying using attachment is only available on devices with a package of super, advanced or ultra.

You can put your webhook URL on your device->edit.

You have to set auto read to On.

if you leave it off, your webhook won't work!

This API has been deprecated. use webhook get status instead.

This is message ID you get when you send a message through API or fonnte's message history

Code for check message status through API

<?php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://api.fonnte.com/status',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_POSTFIELDS => array('id' => '2'),
  CURLOPT_HTTPHEADER => array(
    'Authorization: TOKEN'
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;

Available parameter

If you prefer to see on postman, see here.

TOKEN must be filled by your own token. See how to get token.

Ideally you should check after a period of time, ex : 5 minutes, to make sure your message is already processed, especially when you are sending multiple targets with long delay

You might find the status is

You cannot check multiple ID, use loop if you need to check multiple id.

Response

successfull response

{
    "id": 2,
    "message_status": "sent",
    "status": true
}

- id required : require the id

{
    "reason": "id required",
    "status": false
}

- token invalid : token is not valid

{
    "reason": "id required",
    "status": false
}

Check if a number is registered on whatsapp.

<?php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://api.fonnte.com/validate',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_POSTFIELDS => array(
'target' => '08123456789,08987654321',
'countryCode' => '62'
),
  CURLOPT_HTTPHEADER => array(
    'Authorization: TOKEN'
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;

Available parameter

If you prefer to see on postman, see here.

Multiple numbers check can be done using comma.

TOKEN must be filled by your own token. See how to get token.

You cannot check more than 500 number at a time.

Run this API simultaneously will break previous check.

Response

Successfull response

{
    "not_registered": [],
    "registered": [],
    "status": true
}

The registered and not registered number(s) will be listed in array

- Target required : target is empty

{
    "reason": "target required",
    "status": false
}

- Target invalid : target is not valid

{
    "reason": "target invalid",
    "status": false
}

- Token invalid : token is not valid

{
    "reason": "token invalid",
    "status": false
}

- Device disconnected : device must connect to use this API

{
    "reason": "device disconnected",
    "status": false
}

This API make scanning device outside fonnte possible.

<?php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://api.fonnte.com/qr',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_POSTFIELDS => array(
    'type' => 'qr',
    'whatsapp' => '628123456789'
  ),
  CURLOPT_HTTPHEADER => array(
    'Authorization: TOKEN'
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;

If you prefer to see on postman, see here.

TOKEN must be filled by your own token. See how to get token.

If your device is not connected to fonnte yet, you'll get this response

{
"status": true,
"url": "iVBORw0KGgoAAAANSUhEUgAAARQAAAEUCAYAA..."
}

Then you can use the url from the response to show in image tag src.

<img src="data:image/png;base64,<?= $qr?>">	

For example using php curl :

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://api.fonnte.com/qr',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_POSTFIELDS => array(
    'type' => 'qr',
    'whatsapp' => '628123456789'
  ),
  CURLOPT_HTTPHEADER => array(
    'Authorization: TOKEN'
  ),
));

$response = curl_exec($curl);

curl_close($curl);
$res = json_decode($response, true);
if (isset($res['url'])) {
  $qr = $res['url'];
?>
  <img src="data:image/png;base64,<?= $qr ?>">
<?php
} else if (isset($res['code'])) {
  echo $res["code"];
} else {
  echo $res["reason"];
} ?>

Available parameter

If your device is already connected, the response is

{
    "reason": "device already connect",
    "status": false
}

If somehow your token is invalid

{
    "reason": "token invalid",
    "status": false
}

Basic code for sending message through API

<?php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://api.fonnte.com/send',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_POSTFIELDS => array(
'target' => '08123456789|Fonnte|Admin,08123456789|Lili|User',
'message' => 'test message to {name} as {var1}',
'url' => 'https://md.fonnte.com/images/wa-logo.png',
'filename' => 'filename',
'schedule' => 0,
'typing' => false,
'delay' => '2',
'countryCode' => '62',
'file' => new CURLFile("localfile.jpg"),
'location' => '-7.983908, 112.621391',
'followup' => 0,
),
  CURLOPT_HTTPHEADER => array(
    'Authorization: TOKEN'
  ),
));

$response = curl_exec($curl);
if (curl_errno($curl)) {
  $error_msg = curl_error($curl);
}
curl_close($curl);

if (isset($error_msg)) {
 echo $error_msg;
}
echo $response;

You can see on postman see example on how to send whatsapp message with API PHP

Available parameter

NOTE :

TOKEN must be filled by your own token. See how to get token.

TOKEN can be multiple, separate with comma, ex: xxxxxx,yyyyyy.

Multiple TOKEN will work as rotator, every target will be sent by random device based on listed token.

Multiple TOKEN can only be used under an account.

You cannot list multiple TOKEN where the device is not belong to the same account

Sending multiple numbers can be done by adding comma. ex: 6282xxxxxx,6285xxxxxxxx,6283xxxxxxxxx.

Sending variable supported on API.

Filename only works on file and audio type.

Consider the file limitation rules when sending an attachment.

Parameter Explanation

target (string)

target is a parameter for the recipients of the whatsapp message.

target may contains 3 value:

  1. whatsapp number
  2. group id
  3. rotator id

the value may consist of one or combination of all type.

the value must be string!

you cannot set the value as an int/number.

there is no limit on how many target's value.

the value is comma separated.

working example : 'target' => '081xxxx' or 'target' => '081xxxx,082xxxx,083xxxx,123xxxx@g.us'

not working example : 'target' => 081xxxx

message (string)

Message is a parameter to fill the message to be sent to the recipient.

this message accept emoji as well.

message value may not exceed 60.000 characters.

please take cautions that any emoji/some character encoding (chinese/japanese/korean/arabian/etc) may contains several characters.

any characters that not supported in UTF-8 may not be sent correctly or even cause error.

message also working as a caption for the file/image if you define url/file.

url (string)

note : this parameter only available on super/advanced/ultra plan.

url is a parameter to send an attachment to the recipient.

the url must be a public url.

you cannot using localhost/private ip url.

the url must be the actual file, not a webpage that contains the file.

working example : https://fonnte.com/image.png

not working example : https://fonnte.com/somepagewithimage or some url like s3 files.

the url also must follow our file limitation.

filename (string)

filename is a parameter to define the file name that received by recipient.

this filename only working on non image or video.

image and video does not contains filename.

example : 'filename' => 'myfile.pdf'

schedule (int)

schedule is a parameter to send the message later on scheduled time.

the value of this parameter is a unix timestamp.

if you have string time like 12 august 2024 or 2024-07-15T15:22 or else, you must convert it to unix timestamp.

please beware, you might forgot about timezone. do mind timezone in the conversion.

example in php : strtotime('2025-01-09T20:46:00+0700') will convert to 1736430360.

you may check the unix timestamp result on epochconverter.com.

Screenshot 86

as you can see in the image above, the time is correct as stated in the conversion.

delay (string)

delay is a parameter to add delay on sending the message.

the value of the delay must be a string!

the reason is because the delay value may be fixed or between two values.

delay also only working on multiple target.

will not work on single target.

first target will always immediately sent, no matter how much the delay is set.

working example : 'delay' => '5' or 'delay' => '5-100'

not working example : 'delay' => 5

if you set the value 5, it means it will delay for 5 seconds before proceeding the next target.

if you set the value 5-10, it means it will delay for between 5 to 100 seconds before proceeding the next target.

it may 5/8/30/66/96 seconds. the system will automatically set this delay.

if you add delay as an int/number, you'll get status : false.

countryCode (string)

countryCode is a parameter to define which country of your recipient is.

the value of the countryCode must be a string!

by default it's 62.

you may not explicitly define the countryCode value.

this countryCode is replacing the first 0 (if any) from a target number or adding the countryCode if not exist.

but if you need to send it outside indonesia, you are mandatory to set this countryCode.

working example : 'countryCode' => '60', 'target' => '60111111111'

not working example : 'countryCode' => 60, 'target' => '60111111111'

if countryCode is not set, the target will be 6260111111111, which is invalid number.

if somehow you want to bypass any of this filter, you can set : 'countryCode' => '0', 'target' => '60111111111'.

this will disable fonnte's filter and you must set the target full with countryCode.

working example : 'countryCode' => '0', 'target' => '628123456789,60111111111'

not working example : 'countryCode' => '0', 'target' => '08123456789,60111111111'

by bypassing fonnte's filter, you can easily set the target value with multiple country number.

location (string)

location is a parameter to send location to the recipient.

the format is latitude,longitude.

example : 'location' => '-7.983908, 112.621391'

typing (bool)

typing is a parameter to add typing indicator in the whatsapp while sending the message.

this is beneficial when you want to make the message look like typed.

example : 'typing' => true

choices (string)

choices is a parameter to add choices on a poll message.

the value must consist of minimum 2 and maximum 12 item.

the value is separated by comma.

example : 'choices' => 'satu,dua,tiga'

select (string)

select is a parameter to set the poll setting to allow only one vote or multiple vote

the value must be 'single' or 'multiple'.

the default value is single.

example : 'select' => 'single'

pollname (string)

pollname is the name of the poll to identify the poll

example : 'pollname' => 'pollku'

file (binary)

note : this parameter only available on super/advanced/ultra plan.

file is a parameter that allows you to send the file directly from your localhost/form upload.

this parameter is super handy if you are running under private ip/localhost.

this is the opposite of url parameter, you don't have to upload the file to public.

example : 'file' => 'new CURLFile("localfile.png")'

the file location must correct relative to your file, otherwise you will get error : operation aborted by callback.

connectOnly (bool)

connectOnly is a parameter to control the sending behaviour.

the default is true.

it means when the device is disconnected, the request will be denied and return status : false.

if you set it to false, then even on disconnected device, the request is saved and will be processed when the device is connected.

example : 'connectOnly' => false

Data (string)

data is a parameter to combine all request as one request.

this is like wrapper for all available parameter on send API.

by using regular parameter, you can already send to multiple target, add delay, etc.

but there are some limitations like :

using parameter data, all problem above will be solved.

the only drawback is you can't use parameter file.

when you use this parameter, every parameter data type must match to the requirement.

otherwise, the request will return status : false.

example : 'data' => '[{"target": "08123456789", "message": "1"},{"target": "08123456789", "message": "2","delay":"2"},{"target": "08123456789", "message": "3","delay":"1"]'

you will need to json_encode it before sending to fonnte.

don't be locked in single target, you can use all feature of a parameter.

so you can also set target to multiple.

the example will run : send message 1 immediately -> wait 2 seconds -> send message 2 -> wait 1 second ->send message 3.

as addition, data parameter also eliminates the need for variables : 081|fonnte since you can manually insert each of them in a message parameter.

sequence (bool)

sequence is a parameter to control the message sending behaviour.

by default, it's false.

fonnte's behaviour is not respecting the order of request.

for example : 'target' => '081xxxx,082xxxx','delay'=>'0'

this may result 082 to be sent first instead of 081.

this may not a big deal, but it will be when the order's matter.

case example : you need to send several messages to a recipient, but the order must correct. you need to split the messages to several chat to shorten the length and more human writting.

these messages must set in correct order.

it was not possible previously using fonnte.

with sequence, it's now possible!

example : 'sequence' => true

sequence work both on regular ways or using data parameter.

note : sequence prevent any future action (delay, schedule, followup) and the message will be sent without delay.

preview (bool)

by default, fonnte parse any link in the message and open it to get preview data.

example : test dari postman https://fonnte.com will produce message as shown in image below.

Screenshot 167

but sometime it's not desired and in some occasion, the link is confirmation link that should be open only by the receiver of the message.

you can now disable it and just send the message without fonnte parsing it just by using preview => false.

Response

successfull run response example

{
    "detail": "success! message in queue",
    "id": [
        "15362"
    ],
    "process": "processing",
    "status": true,
    "target": [
        "6282227097005"
    ]
}

There are 3 detail on successfull run API

  1. Success! message in queue : will be processed immediately
  2. Success! message will be sent on scheduled time : will be processed on scheduled time
  3. Success! message pending due to server issue, will be sent later : there is something wrong with the server, but your message will be sent shortly after the server run again.

On 3rd detail, it may happen if server is restarting, server is not responding, server is down, trouble on the network and so on.

It's not your fault, but ours.

Again, your message is saved and will be sent shortly after the server run again.

Failed run response always return status : false

- Invalid token : if the token is invalid

{
    "Status": false,
    "reason": "token invalid"
}

- Devices must belong to an account : you cannot list token under different account

{
    "Status": false,
    "reason": "devices must belong to an account"
}

- Input invalid : if any of the value is invalid

{
    "reason": "input invalid",
    "status": false
}

- Url invalid : if url provided invalid

{
    "reason": "url invalid",
    "status": false
}

- Url unreachable : if url not responding

{
    "reason": "url unreachable",
    "status": false
}

- File format not supported : use supported format

{
    "reason": "file format not supported",
    "status": false
}

- File size must under 4MB : file cannot exceed 4MB

{
    "reason": "file size must under 4MB",
    "status": false
}

- Target invalid : target is not a valid number

{
    "reason": "target invalid",
    "status": false
}

- JSON format invalid : invalid JSON format, check your json format

{
    "reason": "JSON format invalid",
    "status": false
}

- Insufficient quota : requested message count > remaining quota. The message(s) will not be saved

{
    "reason": "insufficient quota",
    "status": false
}

To begin using fonnte's API, you have to use Token (API key).

You can get this token on device menu on device list.

You can just click and the token copied to your clipboard.

note : Token must be stored securely. With only a token, anyone can send messages using your WhatsApp.

Made with in Indonesia