curl --request POST \
--url https://app.sideshift.app/api/oauth/v1/contracts/{id}/handles \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"platform": "instagram",
"handle": "@janecreator"
}
'import requests
url = "https://app.sideshift.app/api/oauth/v1/contracts/{id}/handles"
payload = {
"platform": "instagram",
"handle": "@janecreator"
}
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({platform: 'instagram', handle: '@janecreator'})
};
fetch('https://app.sideshift.app/api/oauth/v1/contracts/{id}/handles', 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/contracts/{id}/handles",
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([
'platform' => 'instagram',
'handle' => '@janecreator'
]),
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/contracts/{id}/handles"
payload := strings.NewReader("{\n \"platform\": \"instagram\",\n \"handle\": \"@janecreator\"\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/contracts/{id}/handles")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"platform\": \"instagram\",\n \"handle\": \"@janecreator\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.sideshift.app/api/oauth/v1/contracts/{id}/handles")
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 \"platform\": \"instagram\",\n \"handle\": \"@janecreator\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"contractId": "<string>",
"platform": "<string>",
"added": true
}
}{
"error": {
"code": "invalid_request",
"message": "name is required",
"requestId": "req_..."
}
}{
"error": {
"code": "unauthorized",
"message": "Missing bearer access token",
"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_..."
}
}Add a social account to a contract
Add a social account to a creator’s live contract, the same as “Edit handles” in the SideShift dashboard. The account is tracked from the next scrape, and its posts count toward the creator’s pay. The creator does not need to approve it. The account is added to every live contract the creator has in the same campaign. Works on active, expired and completed contracts. A pending contract is refused: creators submit their own handles when they accept, and you approve those as applications. Ghost handle contracts, and campaigns that track no handles, are also refused. If the contract already tracks the account, nothing changes and added is false. Sandbox credentials cannot call this endpoint. Requires the contracts:write scope.
curl --request POST \
--url https://app.sideshift.app/api/oauth/v1/contracts/{id}/handles \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"platform": "instagram",
"handle": "@janecreator"
}
'import requests
url = "https://app.sideshift.app/api/oauth/v1/contracts/{id}/handles"
payload = {
"platform": "instagram",
"handle": "@janecreator"
}
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({platform: 'instagram', handle: '@janecreator'})
};
fetch('https://app.sideshift.app/api/oauth/v1/contracts/{id}/handles', 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/contracts/{id}/handles",
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([
'platform' => 'instagram',
'handle' => '@janecreator'
]),
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/contracts/{id}/handles"
payload := strings.NewReader("{\n \"platform\": \"instagram\",\n \"handle\": \"@janecreator\"\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/contracts/{id}/handles")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"platform\": \"instagram\",\n \"handle\": \"@janecreator\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.sideshift.app/api/oauth/v1/contracts/{id}/handles")
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 \"platform\": \"instagram\",\n \"handle\": \"@janecreator\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"contractId": "<string>",
"platform": "<string>",
"added": true
}
}{
"error": {
"code": "invalid_request",
"message": "name is required",
"requestId": "req_..."
}
}{
"error": {
"code": "unauthorized",
"message": "Missing bearer access token",
"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_..."
}
}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.
Path Parameters
The contract id.
Body
The social account to add to the contract.
Response
The account is on the contract.
Show child attributes
Show child attributes