curl --request POST \
--url https://app.sideshift.app/api/oauth/v1/team/members \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"userId": "<string>",
"email": "jsmith@example.com",
"inviteId": "<string>",
"permissions": {
"applicants": true,
"payouts": true,
"sendPayments": true,
"approvePayments": true,
"messages": true,
"posts": true,
"analytics": true,
"creatorDatabase": true,
"campaigns": true,
"signContracts": true,
"withdrawals": true
}
}
'import requests
url = "https://app.sideshift.app/api/oauth/v1/team/members"
payload = {
"userId": "<string>",
"email": "jsmith@example.com",
"inviteId": "<string>",
"permissions": {
"applicants": True,
"payouts": True,
"sendPayments": True,
"approvePayments": True,
"messages": True,
"posts": True,
"analytics": True,
"creatorDatabase": True,
"campaigns": True,
"signContracts": True,
"withdrawals": True
}
}
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({
userId: '<string>',
email: 'jsmith@example.com',
inviteId: '<string>',
permissions: {
applicants: true,
payouts: true,
sendPayments: true,
approvePayments: true,
messages: true,
posts: true,
analytics: true,
creatorDatabase: true,
campaigns: true,
signContracts: true,
withdrawals: true
}
})
};
fetch('https://app.sideshift.app/api/oauth/v1/team/members', 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/team/members",
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([
'userId' => '<string>',
'email' => 'jsmith@example.com',
'inviteId' => '<string>',
'permissions' => [
'applicants' => true,
'payouts' => true,
'sendPayments' => true,
'approvePayments' => true,
'messages' => true,
'posts' => true,
'analytics' => true,
'creatorDatabase' => true,
'campaigns' => true,
'signContracts' => true,
'withdrawals' => true
]
]),
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/team/members"
payload := strings.NewReader("{\n \"userId\": \"<string>\",\n \"email\": \"jsmith@example.com\",\n \"inviteId\": \"<string>\",\n \"permissions\": {\n \"applicants\": true,\n \"payouts\": true,\n \"sendPayments\": true,\n \"approvePayments\": true,\n \"messages\": true,\n \"posts\": true,\n \"analytics\": true,\n \"creatorDatabase\": true,\n \"campaigns\": true,\n \"signContracts\": true,\n \"withdrawals\": true\n }\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/team/members")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"userId\": \"<string>\",\n \"email\": \"jsmith@example.com\",\n \"inviteId\": \"<string>\",\n \"permissions\": {\n \"applicants\": true,\n \"payouts\": true,\n \"sendPayments\": true,\n \"approvePayments\": true,\n \"messages\": true,\n \"posts\": true,\n \"analytics\": true,\n \"creatorDatabase\": true,\n \"campaigns\": true,\n \"signContracts\": true,\n \"withdrawals\": true\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.sideshift.app/api/oauth/v1/team/members")
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 \"userId\": \"<string>\",\n \"email\": \"jsmith@example.com\",\n \"inviteId\": \"<string>\",\n \"permissions\": {\n \"applicants\": true,\n \"payouts\": true,\n \"sendPayments\": true,\n \"approvePayments\": true,\n \"messages\": true,\n \"posts\": true,\n \"analytics\": true,\n \"creatorDatabase\": true,\n \"campaigns\": true,\n \"signContracts\": true,\n \"withdrawals\": true\n }\n}"
response = http.request(request)
puts response.read_body{
"data": {
"success": true
}
}{
"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 team member
add a user to the company’s team. Requires the team:write scope.
curl --request POST \
--url https://app.sideshift.app/api/oauth/v1/team/members \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"userId": "<string>",
"email": "jsmith@example.com",
"inviteId": "<string>",
"permissions": {
"applicants": true,
"payouts": true,
"sendPayments": true,
"approvePayments": true,
"messages": true,
"posts": true,
"analytics": true,
"creatorDatabase": true,
"campaigns": true,
"signContracts": true,
"withdrawals": true
}
}
'import requests
url = "https://app.sideshift.app/api/oauth/v1/team/members"
payload = {
"userId": "<string>",
"email": "jsmith@example.com",
"inviteId": "<string>",
"permissions": {
"applicants": True,
"payouts": True,
"sendPayments": True,
"approvePayments": True,
"messages": True,
"posts": True,
"analytics": True,
"creatorDatabase": True,
"campaigns": True,
"signContracts": True,
"withdrawals": True
}
}
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({
userId: '<string>',
email: 'jsmith@example.com',
inviteId: '<string>',
permissions: {
applicants: true,
payouts: true,
sendPayments: true,
approvePayments: true,
messages: true,
posts: true,
analytics: true,
creatorDatabase: true,
campaigns: true,
signContracts: true,
withdrawals: true
}
})
};
fetch('https://app.sideshift.app/api/oauth/v1/team/members', 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/team/members",
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([
'userId' => '<string>',
'email' => 'jsmith@example.com',
'inviteId' => '<string>',
'permissions' => [
'applicants' => true,
'payouts' => true,
'sendPayments' => true,
'approvePayments' => true,
'messages' => true,
'posts' => true,
'analytics' => true,
'creatorDatabase' => true,
'campaigns' => true,
'signContracts' => true,
'withdrawals' => true
]
]),
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/team/members"
payload := strings.NewReader("{\n \"userId\": \"<string>\",\n \"email\": \"jsmith@example.com\",\n \"inviteId\": \"<string>\",\n \"permissions\": {\n \"applicants\": true,\n \"payouts\": true,\n \"sendPayments\": true,\n \"approvePayments\": true,\n \"messages\": true,\n \"posts\": true,\n \"analytics\": true,\n \"creatorDatabase\": true,\n \"campaigns\": true,\n \"signContracts\": true,\n \"withdrawals\": true\n }\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/team/members")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"userId\": \"<string>\",\n \"email\": \"jsmith@example.com\",\n \"inviteId\": \"<string>\",\n \"permissions\": {\n \"applicants\": true,\n \"payouts\": true,\n \"sendPayments\": true,\n \"approvePayments\": true,\n \"messages\": true,\n \"posts\": true,\n \"analytics\": true,\n \"creatorDatabase\": true,\n \"campaigns\": true,\n \"signContracts\": true,\n \"withdrawals\": true\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.sideshift.app/api/oauth/v1/team/members")
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 \"userId\": \"<string>\",\n \"email\": \"jsmith@example.com\",\n \"inviteId\": \"<string>\",\n \"permissions\": {\n \"applicants\": true,\n \"payouts\": true,\n \"sendPayments\": true,\n \"approvePayments\": true,\n \"messages\": true,\n \"posts\": true,\n \"analytics\": true,\n \"creatorDatabase\": true,\n \"campaigns\": true,\n \"signContracts\": true,\n \"withdrawals\": true\n }\n}"
response = http.request(request)
puts response.read_body{
"data": {
"success": true
}
}{
"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.
Body
Add a user to the company's team. companyId is injected from the token tenant and must NOT be supplied. Required (validated in the use-case): userId, email. Source: lib/api/team/add-member.usecase.ts + add_team_member call.body. The route zod (AddMemberInput) is .passthrough(). When role is Admin/Owner the platform forces full permissions.
User id of the member to add.
1Email address of the user to add.
Role to grant (defaults to Employee).
Owner, Admin, Employee Invite id when joining via self-registration (required when userId equals the caller's own id).
Per-member permission flags, as accepted. Every key is optional: anything omitted defaults to true, so sending {} grants the full set rather than none. Unrecognised keys are ignored rather than rejected. Role wins over this object - granting Owner forces every flag on, and granting Admin forces every flag on except withdrawals, which is honoured as sent.
Show child attributes
Show child attributes
Per-member email-notification preferences. Source: lib/team-email-preferences.ts TEAM_EMAIL_PREFERENCE_KEYS + normalizeTeamEmailPreferences (always returns the closed key set).
Show child attributes
Show child attributes
Response
Add-member success ({ success: true }).
Add-member result. Source: addTeamMember returns { success: true } (lib/api/team/add-member.usecase.ts).
Show child attributes
Show child attributes