curl --request POST \
--url https://app.sideshift.app/api/oauth/v1/applicants/message \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"applicantId": "<string>",
"jobId": "<string>",
"message": "<string>",
"includeJobLink": true,
"interviewLink": "<string>"
}
'import requests
url = "https://app.sideshift.app/api/oauth/v1/applicants/message"
payload = {
"applicantId": "<string>",
"jobId": "<string>",
"message": "<string>",
"includeJobLink": True,
"interviewLink": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
applicantId: '<string>',
jobId: '<string>',
message: '<string>',
includeJobLink: true,
interviewLink: '<string>'
})
};
fetch('https://app.sideshift.app/api/oauth/v1/applicants/message', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.sideshift.app/api/oauth/v1/applicants/message",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'applicantId' => '<string>',
'jobId' => '<string>',
'message' => '<string>',
'includeJobLink' => true,
'interviewLink' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.sideshift.app/api/oauth/v1/applicants/message"
payload := strings.NewReader("{\n \"applicantId\": \"<string>\",\n \"jobId\": \"<string>\",\n \"message\": \"<string>\",\n \"includeJobLink\": true,\n \"interviewLink\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.sideshift.app/api/oauth/v1/applicants/message")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"applicantId\": \"<string>\",\n \"jobId\": \"<string>\",\n \"message\": \"<string>\",\n \"includeJobLink\": true,\n \"interviewLink\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.sideshift.app/api/oauth/v1/applicants/message")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"applicantId\": \"<string>\",\n \"jobId\": \"<string>\",\n \"message\": \"<string>\",\n \"includeJobLink\": true,\n \"interviewLink\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"success": true,
"supportChannelId": "<string>",
"messageIds": [
"<string>"
]
}
}{
"error": {
"code": "invalid_request",
"message": "name is required",
"requestId": "req_..."
}
}{
"error": {
"code": "unauthorized",
"message": "Missing bearer access token",
"requestId": "req_..."
}
}{
"error": {
"code": "subscription_required",
"message": "The company does not have an active subscription",
"requestId": "req_..."
}
}{
"error": {
"code": "insufficient_scope",
"message": "Requires scope 'campaigns:write'",
"requestId": "req_..."
}
}{
"error": {
"code": "not_found",
"message": "Resource not found",
"requestId": "req_..."
}
}{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded",
"requestId": "req_..."
}
}{
"error": {
"code": "upstream_error",
"message": "Upstream messaging provider error",
"requestId": "req_..."
}
}Send a new message to an applicant
Run the complete applicant-chat flow: resolve or create the applicant’s support channel, optionally send a job or interview widget, send the exact message, update SideShift messaging state, and notify the creator. The applicant and job are confined to the token tenant. This action sends real external messages, is unavailable to sandbox tokens, and honors Idempotency-Key.
curl --request POST \
--url https://app.sideshift.app/api/oauth/v1/applicants/message \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"applicantId": "<string>",
"jobId": "<string>",
"message": "<string>",
"includeJobLink": true,
"interviewLink": "<string>"
}
'import requests
url = "https://app.sideshift.app/api/oauth/v1/applicants/message"
payload = {
"applicantId": "<string>",
"jobId": "<string>",
"message": "<string>",
"includeJobLink": True,
"interviewLink": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
applicantId: '<string>',
jobId: '<string>',
message: '<string>',
includeJobLink: true,
interviewLink: '<string>'
})
};
fetch('https://app.sideshift.app/api/oauth/v1/applicants/message', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.sideshift.app/api/oauth/v1/applicants/message",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'applicantId' => '<string>',
'jobId' => '<string>',
'message' => '<string>',
'includeJobLink' => true,
'interviewLink' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.sideshift.app/api/oauth/v1/applicants/message"
payload := strings.NewReader("{\n \"applicantId\": \"<string>\",\n \"jobId\": \"<string>\",\n \"message\": \"<string>\",\n \"includeJobLink\": true,\n \"interviewLink\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.sideshift.app/api/oauth/v1/applicants/message")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"applicantId\": \"<string>\",\n \"jobId\": \"<string>\",\n \"message\": \"<string>\",\n \"includeJobLink\": true,\n \"interviewLink\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.sideshift.app/api/oauth/v1/applicants/message")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"applicantId\": \"<string>\",\n \"jobId\": \"<string>\",\n \"message\": \"<string>\",\n \"includeJobLink\": true,\n \"interviewLink\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"success": true,
"supportChannelId": "<string>",
"messageIds": [
"<string>"
]
}
}{
"error": {
"code": "invalid_request",
"message": "name is required",
"requestId": "req_..."
}
}{
"error": {
"code": "unauthorized",
"message": "Missing bearer access token",
"requestId": "req_..."
}
}{
"error": {
"code": "subscription_required",
"message": "The company does not have an active subscription",
"requestId": "req_..."
}
}{
"error": {
"code": "insufficient_scope",
"message": "Requires scope 'campaigns:write'",
"requestId": "req_..."
}
}{
"error": {
"code": "not_found",
"message": "Resource not found",
"requestId": "req_..."
}
}{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded",
"requestId": "req_..."
}
}{
"error": {
"code": "upstream_error",
"message": "Upstream messaging provider error",
"requestId": "req_..."
}
}Authorizations
OAuth 2.1 authorization code + PKCE (S256). Tokens are tenant-bound (company_id) and scoped. Discover endpoints via /.well-known/oauth-authorization-server.
Headers
Client-chosen key; replaying the same key + body returns the original response, a different body returns 409.
Body
Applicant user ID returned by the applicant-list endpoints.
1 - 160Job the creator applied to.
1 - 160Exact message text to send.
1 - 10000Send the SideShift job widget before the text message.
Optional approved http(s) interview or calendar URL.
2048Response
The applicant message flow completed.
Show child attributes
Show child attributes