curl --request POST \
--url https://app.sideshift.app/api/oauth/v1/companies/invite-team \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"copyMembers": [
"<string>"
],
"emailInvites": [
{
"email": "jsmith@example.com",
"permissions": {},
"emailPreferences": {}
}
],
"propagateToAgency": true,
"subaccountOnly": true
}
'import requests
url = "https://app.sideshift.app/api/oauth/v1/companies/invite-team"
payload = {
"copyMembers": ["<string>"],
"emailInvites": [
{
"email": "jsmith@example.com",
"permissions": {},
"emailPreferences": {}
}
],
"propagateToAgency": True,
"subaccountOnly": 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({
copyMembers: ['<string>'],
emailInvites: [{email: 'jsmith@example.com', permissions: {}, emailPreferences: {}}],
propagateToAgency: true,
subaccountOnly: true
})
};
fetch('https://app.sideshift.app/api/oauth/v1/companies/invite-team', 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/companies/invite-team",
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([
'copyMembers' => [
'<string>'
],
'emailInvites' => [
[
'email' => 'jsmith@example.com',
'permissions' => [
],
'emailPreferences' => [
]
]
],
'propagateToAgency' => true,
'subaccountOnly' => 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/companies/invite-team"
payload := strings.NewReader("{\n \"copyMembers\": [\n \"<string>\"\n ],\n \"emailInvites\": [\n {\n \"email\": \"jsmith@example.com\",\n \"permissions\": {},\n \"emailPreferences\": {}\n }\n ],\n \"propagateToAgency\": true,\n \"subaccountOnly\": true\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/companies/invite-team")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"copyMembers\": [\n \"<string>\"\n ],\n \"emailInvites\": [\n {\n \"email\": \"jsmith@example.com\",\n \"permissions\": {},\n \"emailPreferences\": {}\n }\n ],\n \"propagateToAgency\": true,\n \"subaccountOnly\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.sideshift.app/api/oauth/v1/companies/invite-team")
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 \"copyMembers\": [\n \"<string>\"\n ],\n \"emailInvites\": [\n {\n \"email\": \"jsmith@example.com\",\n \"permissions\": {},\n \"emailPreferences\": {}\n }\n ],\n \"propagateToAgency\": true,\n \"subaccountOnly\": true\n}"
response = http.request(request)
puts response.read_body{
"data": {
"success": true,
"copiedCount": 123,
"invitedCount": 123,
"failedInvites": [
{
"email": "<string>",
"reason": "<string>",
"errorCode": "<string>",
"inviteLink": "<string>"
}
],
"skippedStudents": [
"<string>"
],
"message": "<string>"
}
}{
"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_..."
}
}Invite team members
copy members / send team invites for a company. Requires the settings:write scope.
curl --request POST \
--url https://app.sideshift.app/api/oauth/v1/companies/invite-team \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"copyMembers": [
"<string>"
],
"emailInvites": [
{
"email": "jsmith@example.com",
"permissions": {},
"emailPreferences": {}
}
],
"propagateToAgency": true,
"subaccountOnly": true
}
'import requests
url = "https://app.sideshift.app/api/oauth/v1/companies/invite-team"
payload = {
"copyMembers": ["<string>"],
"emailInvites": [
{
"email": "jsmith@example.com",
"permissions": {},
"emailPreferences": {}
}
],
"propagateToAgency": True,
"subaccountOnly": 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({
copyMembers: ['<string>'],
emailInvites: [{email: 'jsmith@example.com', permissions: {}, emailPreferences: {}}],
propagateToAgency: true,
subaccountOnly: true
})
};
fetch('https://app.sideshift.app/api/oauth/v1/companies/invite-team', 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/companies/invite-team",
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([
'copyMembers' => [
'<string>'
],
'emailInvites' => [
[
'email' => 'jsmith@example.com',
'permissions' => [
],
'emailPreferences' => [
]
]
],
'propagateToAgency' => true,
'subaccountOnly' => 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/companies/invite-team"
payload := strings.NewReader("{\n \"copyMembers\": [\n \"<string>\"\n ],\n \"emailInvites\": [\n {\n \"email\": \"jsmith@example.com\",\n \"permissions\": {},\n \"emailPreferences\": {}\n }\n ],\n \"propagateToAgency\": true,\n \"subaccountOnly\": true\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/companies/invite-team")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"copyMembers\": [\n \"<string>\"\n ],\n \"emailInvites\": [\n {\n \"email\": \"jsmith@example.com\",\n \"permissions\": {},\n \"emailPreferences\": {}\n }\n ],\n \"propagateToAgency\": true,\n \"subaccountOnly\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.sideshift.app/api/oauth/v1/companies/invite-team")
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 \"copyMembers\": [\n \"<string>\"\n ],\n \"emailInvites\": [\n {\n \"email\": \"jsmith@example.com\",\n \"permissions\": {},\n \"emailPreferences\": {}\n }\n ],\n \"propagateToAgency\": true,\n \"subaccountOnly\": true\n}"
response = http.request(request)
puts response.read_body{
"data": {
"success": true,
"copiedCount": 123,
"invitedCount": 123,
"failedInvites": [
{
"email": "<string>",
"reason": "<string>",
"errorCode": "<string>",
"inviteLink": "<string>"
}
],
"skippedStudents": [
"<string>"
],
"message": "<string>"
}
}{
"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
Invite team members by email and/or copy existing members into the token tenant's company. The company is always the token's company (any companyId in the body is ignored).
User IDs of existing users to copy as members (only agencies may copy members).
Email invitations to send.
Show child attributes
Show child attributes
Propagate members to all agency companies.
Restrict added access to this subaccount only.
Response
Invitation results: counts copied/invited, any failed email invites, and skipped student/creator accounts.
Result of an invite-team operation.
Show child attributes
Show child attributes