The Spektif API follows RESTful architecture standards, offering clear and consistent resource-based endpoints. All requests and responses are transmitted in JSON format, leveraging standard HTTP verbs, status codes, and authentication protocols to enable secure, efficient, and scalable integrations.

API Base URL

Please note that Spektif does not provide a sandbox or test environment. All API requests are processed in the live environment, so ensure that all request data and parameters are accurate before making any calls.

string
https://devcrm.spektif.id/external-api

All requests to the Spektif API require authentication. Each API request must include a valid client-id and client-secret to the request header, which can be obtained from your Spektif Dashboard under Developer Tools.

In addition to credentials, Spektif enforces IP-based security. You must register and enable your server’s public IP address in the IP Whitelist section of the dashboard. Requests originating from non-whitelisted IP addresses will be automatically rejected.

Both valid API credentials and an approved IP address are mandatory. Without completing these two steps, authentication will fail and API access will not be granted.

All responses from the Spektif API are returned in JSON format. Each response follows a consistent structure and includes a status indicator, message, and relevant data payload when applicable. Standard HTTP status codes are used to represent the outcome of each request.

Sample Success Response

JSON
{
"status": "success",
"remark": "contact_list",
"message":[
    "Contact list fetched successfully"
],
"data": {
   ...you get all data here
    }
}
                    

Error Sample Response

JSON
{
    "remark": "Unauthorized",
    "status": "error",
    "message": [
        "The client secret is required"
    ]
}
                    
JSON
 {
    "remark": "Unauthorized",
    "status": "error",
    "message": [
        "Access to this API endpoint is restricted to IP addresses that have been explicitly whitelisted.",
        "In order to access this API endpoint, please add your IP address (::1) to the white list from the user dashboard."
    ]
}
                    
php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://devcrm.spektif.id/external-api/contact/list',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => array(
    'client-id: YOUR-CLIENT-ID',
    'client-secret: YOUR-CLIENT-SECRET',
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;

 
                                
                        
Query Parameters

Query parameters that allow you to customize the API response.

Nama Deskripsi Wajib Default
page Specifies the page number to retrieve. Tidak 1
paginate Defines the number of items returned per page. Tidak 20
search Searches for contacts by firstname, lastname or mobile number. Tidak -
php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://devcrm.spektif.id/external-api/contact/store',
  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',
  // mobile_code no longer required; a full number will be parsed automatically
  CURLOPT_POSTFIELDS => array('firstname' => 'John','lastname' => 'Doe','mobile' => '081988123456'),
  CURLOPT_HTTPHEADER => array(
    'client-id: YOUR-CLIENT-ID',
    'client-secret: YOUR-CLIENT-SECRET',
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;

Required Fields

The following fields are required to create a new contact in the system.

Nama Wajib Default
firstname Ya -
lastname Ya -
mobile Ya -
mobile Ya -
city Tidak -
state Tidak -
post_code Tidak -
address Tidak -
profile_image Tidak -
php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://devcrm.spektif.id/external-api/contact/update/{contactId}',
  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',
  // mobile_code is no longer required; pass a full phone number and it will be parsed
  CURLOPT_POSTFIELDS => array('firstname' => 'John','lastname' => 'Doe','mobile' => '081988123456'),
  CURLOPT_HTTPHEADER => array(
    'client-id: YOUR-CLIENT-ID',
    'client-secret: YOUR-CLIENT-SECRET',
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;

Required Fields

The following fields are required to create a new contact in the system.

Nama Wajib Default
firstname Ya -
lastname Ya -
mobile Ya -
city Tidak -
state Tidak -
post_code Tidak -
address Tidak -
profile_image Tidak -
php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://devcrm.spektif.id/external-api/contact/delete/{contactId}',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'DELETE',
  CURLOPT_POSTFIELDS => array('firstname' => 'John','lastname' => 'Doe','mobile_code' => '880','mobile' => '01988'),
  CURLOPT_HTTPHEADER => array(
    'client-id: YOUR-CLIENT-ID',
    'client-secret: YOUR-CLIENT-SECRET',
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;

php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://devcrm.spektif.id/external-api/inbox/conversation-list',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => array(
    'client-id: YOUR-CLIENT-ID',
    'client-secret: YOUR-CLIENT-SECRET',
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;

Query Parameters

Nama Deskripsi Default
status Filter conversations by status. Use below value for the filter conversation via status. Done = 1; Pending = 2; Important = 3; Unread = 4; Semua
page Specifies the page number to retrieve. 1
paginate Defines the number of items returned per page. 20
php

$curl = curl_init();
curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://devcrm.spektif.id/external-api/inbox/change-conversation-status/2',
  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('status' => '1'),
  CURLOPT_HTTPHEADER => array(
    'client-id: YOUR-CLIENT-ID',
    'client-secret: YOUR-CLIENT-SECRET',
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;

URL Parameters

Parameter Tipe Deskripsi
conversation_id integer Unique ID of the conversation

Request Body

Field Tipe Wajib
status integer YEs
php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://devcrm.spektif.id/external-api/inbox/conversation-details/2',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_POSTFIELDS => array('status' => '1'),
  CURLOPT_HTTPHEADER => array(
    'client-id: YOUR-CLIENT-ID',
    'client-secret: YOUR-CLIENT-SECRET',
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;

URL Parameters

Parameter Tipe Deskripsi
conversation_id integer Unique ID of the conversation
php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://devcrm.spektif.id/external-api/inbox/send-message',
  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',
  // mobile_code no longer required; provide full number and it will be parsed automatically
  CURLOPT_POSTFIELDS => array('mobile' => '081234567890','message' => 'Hello world'),
  CURLOPT_HTTPHEADER => array(
    'client-id: YOUR-CLIENT-ID',
    'client-secret: YOUR-CLIENT-SECRET',
  ),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;

Request Body

Field Tipe Wajib Deskripsi
mobile string yes A full mobile number. Country code will be detected automatically; include leading zero or international prefix.
from_number string conditional A valid WhatsApp Business phone number registered on your account and in the Meta dashboard is required. If no ID is provided, the message will be sent using your default registered WhatsApp account.
message string Conditional Text message body. Required if no media, location, or interactive data is provided
image file No Image file (jpg, jpeg, png – max 5MB)
document file No Document file (pdf, doc, docx – max 100MB)
video file No Video file (mp4 – max 16MB)
audio file No Audio file – max 16MB
latitude decimal Conditional Latitude for location message
longitude decimal Conditional Longitude for location message
cta_url_id integer No CTA URL ID for interactive button messages
interactive_list_id integer No Interactive list ID

Notes

At least one message type must be provided.

Interactive messages require an active plan.

Blocked contacts cannot send or receive messages.

php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://devcrm.spektif.id/external-api/inbox/send-template-message',
  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',
  // mobile_code not required anymore; submit a single full number instead
  CURLOPT_POSTFIELDS => array('mobile' => '081234567890','template_id' => 'your template id'),
  CURLOPT_HTTPHEADER => array(
    'client-id: YOUR-CLIENT-ID',
    'client-secret: YOUR-CLIENT-SECRET',
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;

Request Body

Field Tipe Wajib Deskripsi
mobile string yes A full mobile number. Country code will be detected automatically; include leading zero or international prefix.
from_number string conditional A valid WhatsApp Business phone number registered on your account and in the Meta dashboard is required. If no ID is provided, the message will be sent using your default registered WhatsApp account.
template_id string Yes The WhatsApp template ID (whatsapp_template_id) from Meta. You can get this from the template-list endpoint.

Notes

Only approved WhatsApp templates can be sent.

Template messages are typically used for business-initiated conversations.

Blocked contacts cannot receive template messages.

WhatsApp account must be connected before sending messages.

php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://devcrm.spektif.id/external-api/inbox/template-list',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => array(
    'client-id: YOUR-CLIENT-ID',
    'client-secret: YOUR-CLIENT-SECRET',
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;
php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://devcrm.spektif.id/external-api/otp/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(
    // mobile_code is not required; a single mobile number will be parsed automatically
    'mobile' => '81234567890',
    'from_number' => '628001234567'
  ),
  CURLOPT_HTTPHEADER => array(
    'client-id: YOUR-CLIENT-ID',
    'client-secret: YOUR-CLIENT-SECRET',
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;

Request Parameters
Nama Wajib Deskripsi
mobile Ya Full destination mobile number. Country code will be auto-detected from first digits or leading zero.
from_number Ya Your WhatsApp Business phone number that will send the OTP (must be registered and configured)
Success Response
{
    "remark": "otp_sent",
    "status": "success",
    "message": ["OTP sent successfully"],
    "data": {
        "reference_id": "otp_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "expires_in": 300
    }
}
Rate Limit Response (429)
{
    "remark": "rate_limit_exceeded",
    "status": "error",
    "message": ["Too many OTP requests. Please wait 10 minutes before trying again."],
    "data": {
        "retry_after": 542
    }
}
php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://devcrm.spektif.id/external-api/otp/verify',
  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(
    'reference_id' => 'otp_a1b2c3d4-e5f6-7890-abcd-ef1234567890',
    'otp_code' => '123456'
  ),
  CURLOPT_HTTPHEADER => array(
    'client-id: YOUR-CLIENT-ID',
    'client-secret: YOUR-CLIENT-SECRET',
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;

Request Parameters
Nama Wajib Deskripsi
reference_id Ya The reference ID returned from the Send OTP endpoint
otp_code Ya The OTP code entered by the user
Success Response
{
    "remark": "otp_verified",
    "status": "success",
    "message": ["OTP verified successfully."],
    "data": {
        "reference_id": "otp_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "verified_at": "2026-03-02T10:30:00+07:00"
    }
}
Error Response (Invalid Code)
{
    "remark": "invalid_code",
    "status": "error",
    "message": ["Invalid OTP code."],
    "data": {
        "remaining_attempts": 3
    }
}
Error Response (Expired)
{
    "remark": "expired",
    "status": "error",
    "message": ["This OTP has expired. Please request a new one."]
}
php

$curl = curl_init();

$referenceId = 'otp_a1b2c3d4-e5f6-7890-abcd-ef1234567890';

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://devcrm.spektif.id/external-api/otp/status?reference_id=' . $referenceId,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => array(
    'client-id: YOUR-CLIENT-ID',
    'client-secret: YOUR-CLIENT-SECRET',
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;

Query Parameters
Nama Wajib Deskripsi
reference_id Ya The reference ID of the OTP request
Success Response
{
    "remark": "otp_status",
    "status": "success",
    "message": ["OTP status retrieved."],
    "data": {
        "reference_id": "otp_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "destination_number": "6281234567890",
        "status": "sent",
        "sent_at": "2026-03-02T10:25:00+07:00",
        "verified_at": null,
        "expires_at": "2026-03-02T10:30:00+07:00",
        "verify_attempts": 0,
        "created_at": "2026-03-02T10:25:00+07:00"
    }
}
Status Values
Status Deskripsi
pending OTP created but not yet sent to WhatsApp
sent OTP has been sent via WhatsApp API
delivered OTP message has been delivered to the recipient
verified OTP has been successfully verified
expired OTP has expired and can no longer be used
failed OTP sending failed or max verification attempts exceeded
php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://devcrm.spektif.id/external-api/otp/resend',
  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(
    'reference_id' => 'otp_a1b2c3d4-e5f6-7890-abcd-ef1234567890'
  ),
  CURLOPT_HTTPHEADER => array(
    'client-id: YOUR-CLIENT-ID',
    'client-secret: YOUR-CLIENT-SECRET',
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;

Request Parameters
Nama Wajib Deskripsi
reference_id Ya The reference ID of the original OTP request to resend
Success Response
{
    "remark": "otp_resent",
    "status": "success",
    "message": ["OTP sent successfully"],
    "data": {
        "reference_id": "otp_new-uuid-generated-here",
        "expires_in": 300
    }
}
Important Notes
  • The previous OTP associated with the reference_id will be expired.
  • A new reference_id is returned that must be used for verification.
  • Rate limiting applies — too many resends will trigger a cooldown.
php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://devcrm.spektif.id/external-api/otp/history?page=1&per_page=15&status=verified',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => array(
    'client-id: YOUR-CLIENT-ID',
    'client-secret: YOUR-CLIENT-SECRET',
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;

Query Parameters
Nama Wajib Deskripsi
page Tidak Page number for pagination (default: 1)
per_page Tidak Number of results per page (default: 15, max: 100)
from_number Tidak Filter by WhatsApp sender number
destination_number Tidak Filter by destination phone number
status Tidak Filter by status: pending, sent, delivered, verified, expired, failed
Success Response
{
    "remark": "otp_history",
    "status": "success",
    "message": ["OTP history retrieved."],
    "data": {
        "data": [
            {
                "reference_id": "otp_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
                "destination_number": "6281234567890",
                "status": "verified",
                "verify_attempts": 1,
                "sent_at": "2026-03-02T10:25:00+07:00",
                "verified_at": "2026-03-02T10:26:30+07:00",
                "expires_at": "2026-03-02T10:30:00+07:00",
                "created_at": "2026-03-02T10:25:00+07:00"
            }
        ],
        "pagination": {
            "current_page": 1,
            "last_page": 5,
            "per_page": 15,
            "total": 67
        }
    }
}