Skip to content

Commit c0d486c

Browse files
api-clients-generation-pipeline[bot]ci.datadog-api-spec
andauthored
Add documentation for /api/v2/team/sync (#829)
Co-authored-by: ci.datadog-api-spec <[email protected]>
1 parent e844d55 commit c0d486c

18 files changed

+975
-47
lines changed

.generated-info

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
2-
"spec_repo_commit": "b434599",
3-
"generated": "2025-08-13 22:20:40.351"
2+
"spec_repo_commit": "c38287b",
3+
"generated": "2025-08-15 18:58:44.539"
44
}

.generator/schemas/v2/openapi.yaml

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42824,6 +42824,68 @@ components:
4282442824
urgency:
4282542825
$ref: '#/components/schemas/Urgency'
4282642826
type: object
42827+
TeamSyncAttributes:
42828+
description: Team sync attributes.
42829+
properties:
42830+
source:
42831+
$ref: '#/components/schemas/TeamSyncAttributesSource'
42832+
type:
42833+
$ref: '#/components/schemas/TeamSyncAttributesType'
42834+
required:
42835+
- source
42836+
- type
42837+
type: object
42838+
TeamSyncAttributesSource:
42839+
description: The external source platform for team synchronization. Only "github"
42840+
is supported.
42841+
enum:
42842+
- github
42843+
example: github
42844+
type: string
42845+
x-enum-varnames:
42846+
- GITHUB
42847+
TeamSyncAttributesType:
42848+
description: The type of synchronization operation. Only "link" is supported,
42849+
which links existing teams by matching names.
42850+
enum:
42851+
- link
42852+
example: link
42853+
type: string
42854+
x-enum-varnames:
42855+
- LINK
42856+
TeamSyncBulkType:
42857+
description: Team sync bulk type.
42858+
enum:
42859+
- team_sync_bulk
42860+
example: team_sync_bulk
42861+
type: string
42862+
x-enum-varnames:
42863+
- TEAM_SYNC_BULK
42864+
TeamSyncData:
42865+
description: Team sync data.
42866+
properties:
42867+
attributes:
42868+
$ref: '#/components/schemas/TeamSyncAttributes'
42869+
type:
42870+
$ref: '#/components/schemas/TeamSyncBulkType'
42871+
required:
42872+
- attributes
42873+
- type
42874+
type: object
42875+
TeamSyncRequest:
42876+
description: Team sync request.
42877+
example:
42878+
data:
42879+
attributes:
42880+
source: github
42881+
type: link
42882+
type: team_sync_bulk
42883+
properties:
42884+
data:
42885+
$ref: '#/components/schemas/TeamSyncData'
42886+
required:
42887+
- data
42888+
type: object
4282742889
TeamTarget:
4282842890
description: Represents a team target for an escalation policy step, including
4282942891
the team's ID and resource type.
@@ -65913,6 +65975,71 @@ paths:
6591365975
permissions:
6591465976
- teams_read
6591565977
- teams_manage
65978+
/api/v2/team/sync:
65979+
post:
65980+
description: 'This endpoint attempts to link your existing Datadog teams with
65981+
GitHub teams by matching their names.
65982+
65983+
It evaluates all current Datadog teams and compares them against teams in
65984+
the GitHub organization
65985+
65986+
connected to your Datadog account, based on Datadog Team handle and GitHub
65987+
Team slug
65988+
65989+
(lowercased and kebab-cased).
65990+
65991+
65992+
This operation is read-only on the GitHub side, no teams will be modified
65993+
or created.
65994+
65995+
65996+
[A GitHub organization must be connected to your Datadog account](https://docs.datadoghq.com/integrations/github/),
65997+
65998+
and the GitHub App integrated with Datadog must have the `Members Read` permission.
65999+
Matching is performed by comparing the Datadog team handle to the GitHub team
66000+
slug
66001+
66002+
using a normalized exact match; case is ignored and spaces are removed. No
66003+
modifications are made
66004+
66005+
to teams in GitHub. This will not create new Teams in Datadog.'
66006+
operationId: SyncTeams
66007+
requestBody:
66008+
content:
66009+
application/json:
66010+
schema:
66011+
$ref: '#/components/schemas/TeamSyncRequest'
66012+
required: true
66013+
responses:
66014+
'200':
66015+
description: OK
66016+
'403':
66017+
$ref: '#/components/responses/ForbiddenResponse'
66018+
'429':
66019+
$ref: '#/components/responses/TooManyRequestsResponse'
66020+
'500':
66021+
content:
66022+
application/json:
66023+
schema:
66024+
$ref: '#/components/schemas/APIErrorResponse'
66025+
description: Internal Server Error - Unexpected error during linking.
66026+
security:
66027+
- apiKeyAuth: []
66028+
appKeyAuth: []
66029+
- AuthZ:
66030+
- teams_manage
66031+
summary: Link Teams with GitHub Teams
66032+
tags:
66033+
- Teams
66034+
x-codegen-request-body-name: body
66035+
x-permission:
66036+
operator: AND
66037+
permissions:
66038+
- teams_manage
66039+
x-unstable: '**Note**: This endpoint is in Preview. To request access, fill
66040+
out this [form](https://www.datadoghq.com/product-preview/github-integration-for-teams/).
66041+
66042+
If you have any feedback, contact [Datadog support](https://docs.datadoghq.com/help/).'
6591666043
/api/v2/team/{super_team_id}/member_teams:
6591766044
get:
6591866045
description: Get all member teams.

examples/v2_teams_SyncTeams.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Link Teams with GitHub Teams returns "OK" response
2+
use datadog_api_client::datadog;
3+
use datadog_api_client::datadogV2::api_teams::TeamsAPI;
4+
use datadog_api_client::datadogV2::model::TeamSyncAttributes;
5+
use datadog_api_client::datadogV2::model::TeamSyncAttributesSource;
6+
use datadog_api_client::datadogV2::model::TeamSyncAttributesType;
7+
use datadog_api_client::datadogV2::model::TeamSyncBulkType;
8+
use datadog_api_client::datadogV2::model::TeamSyncData;
9+
use datadog_api_client::datadogV2::model::TeamSyncRequest;
10+
11+
#[tokio::main]
12+
async fn main() {
13+
let body = TeamSyncRequest::new(TeamSyncData::new(
14+
TeamSyncAttributes::new(
15+
TeamSyncAttributesSource::GITHUB,
16+
TeamSyncAttributesType::LINK,
17+
),
18+
TeamSyncBulkType::TEAM_SYNC_BULK,
19+
));
20+
let mut configuration = datadog::Configuration::new();
21+
configuration.set_unstable_operation_enabled("v2.SyncTeams", true);
22+
let api = TeamsAPI::with_config(configuration);
23+
let resp = api.sync_teams(body).await;
24+
if let Ok(value) = resp {
25+
println!("{:#?}", value);
26+
} else {
27+
println!("{:#?}", resp.unwrap_err());
28+
}
29+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Sync teams returns "OK" response
2+
use datadog_api_client::datadog;
3+
use datadog_api_client::datadogV2::api_teams::TeamsAPI;
4+
use datadog_api_client::datadogV2::model::TeamSyncAttributes;
5+
use datadog_api_client::datadogV2::model::TeamSyncAttributesSource;
6+
use datadog_api_client::datadogV2::model::TeamSyncAttributesType;
7+
use datadog_api_client::datadogV2::model::TeamSyncBulkType;
8+
use datadog_api_client::datadogV2::model::TeamSyncData;
9+
use datadog_api_client::datadogV2::model::TeamSyncRequest;
10+
11+
#[tokio::main]
12+
async fn main() {
13+
let body = TeamSyncRequest::new(TeamSyncData::new(
14+
TeamSyncAttributes::new(
15+
TeamSyncAttributesSource::GITHUB,
16+
TeamSyncAttributesType::LINK,
17+
),
18+
TeamSyncBulkType::TEAM_SYNC_BULK,
19+
));
20+
let mut configuration = datadog::Configuration::new();
21+
configuration.set_unstable_operation_enabled("v2.SyncTeams", true);
22+
let api = TeamsAPI::with_config(configuration);
23+
let resp = api.sync_teams(body).await;
24+
if let Ok(value) = resp {
25+
println!("{:#?}", value);
26+
} else {
27+
println!("{:#?}", resp.unwrap_err());
28+
}
29+
}

src/datadog/configuration.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ impl Default for Configuration {
213213
("v2.add_member_team".to_owned(), false),
214214
("v2.list_member_teams".to_owned(), false),
215215
("v2.remove_member_team".to_owned(), false),
216+
("v2.sync_teams".to_owned(), false),
216217
("v2.create_incident_team".to_owned(), false),
217218
("v2.delete_incident_team".to_owned(), false),
218219
("v2.get_incident_team".to_owned(), false),

src/datadogV2/api/api_teams.rs

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,14 @@ pub enum RemoveMemberTeamError {
266266
UnknownValue(serde_json::Value),
267267
}
268268

269+
/// SyncTeamsError is a struct for typed errors of method [`TeamsAPI::sync_teams`]
270+
#[derive(Debug, Clone, Serialize, Deserialize)]
271+
#[serde(untagged)]
272+
pub enum SyncTeamsError {
273+
APIErrorResponse(crate::datadogV2::model::APIErrorResponse),
274+
UnknownValue(serde_json::Value),
275+
}
276+
269277
/// UpdateTeamError is a struct for typed errors of method [`TeamsAPI::update_team`]
270278
#[derive(Debug, Clone, Serialize, Deserialize)]
271279
#[serde(untagged)]
@@ -2408,6 +2416,166 @@ impl TeamsAPI {
24082416
}
24092417
}
24102418

2419+
/// This endpoint attempts to link your existing Datadog teams with GitHub teams by matching their names.
2420+
/// It evaluates all current Datadog teams and compares them against teams in the GitHub organization
2421+
/// connected to your Datadog account, based on Datadog Team handle and GitHub Team slug
2422+
/// (lowercased and kebab-cased).
2423+
///
2424+
/// This operation is read-only on the GitHub side, no teams will be modified or created.
2425+
///
2426+
/// [A GitHub organization must be connected to your Datadog account](<https://docs.datadoghq.com/integrations/github/>),
2427+
/// and the GitHub App integrated with Datadog must have the `Members Read` permission. Matching is performed by comparing the Datadog team handle to the GitHub team slug
2428+
/// using a normalized exact match; case is ignored and spaces are removed. No modifications are made
2429+
/// to teams in GitHub. This will not create new Teams in Datadog.
2430+
pub async fn sync_teams(
2431+
&self,
2432+
body: crate::datadogV2::model::TeamSyncRequest,
2433+
) -> Result<(), datadog::Error<SyncTeamsError>> {
2434+
match self.sync_teams_with_http_info(body).await {
2435+
Ok(_) => Ok(()),
2436+
Err(err) => Err(err),
2437+
}
2438+
}
2439+
2440+
/// This endpoint attempts to link your existing Datadog teams with GitHub teams by matching their names.
2441+
/// It evaluates all current Datadog teams and compares them against teams in the GitHub organization
2442+
/// connected to your Datadog account, based on Datadog Team handle and GitHub Team slug
2443+
/// (lowercased and kebab-cased).
2444+
///
2445+
/// This operation is read-only on the GitHub side, no teams will be modified or created.
2446+
///
2447+
/// [A GitHub organization must be connected to your Datadog account](<https://docs.datadoghq.com/integrations/github/>),
2448+
/// and the GitHub App integrated with Datadog must have the `Members Read` permission. Matching is performed by comparing the Datadog team handle to the GitHub team slug
2449+
/// using a normalized exact match; case is ignored and spaces are removed. No modifications are made
2450+
/// to teams in GitHub. This will not create new Teams in Datadog.
2451+
pub async fn sync_teams_with_http_info(
2452+
&self,
2453+
body: crate::datadogV2::model::TeamSyncRequest,
2454+
) -> Result<datadog::ResponseContent<()>, datadog::Error<SyncTeamsError>> {
2455+
let local_configuration = &self.config;
2456+
let operation_id = "v2.sync_teams";
2457+
if local_configuration.is_unstable_operation_enabled(operation_id) {
2458+
warn!("Using unstable operation {operation_id}");
2459+
} else {
2460+
let local_error = datadog::UnstableOperationDisabledError {
2461+
msg: "Operation 'v2.sync_teams' is not enabled".to_string(),
2462+
};
2463+
return Err(datadog::Error::UnstableOperationDisabledError(local_error));
2464+
}
2465+
2466+
let local_client = &self.client;
2467+
2468+
let local_uri_str = format!(
2469+
"{}/api/v2/team/sync",
2470+
local_configuration.get_operation_host(operation_id)
2471+
);
2472+
let mut local_req_builder =
2473+
local_client.request(reqwest::Method::POST, local_uri_str.as_str());
2474+
2475+
// build headers
2476+
let mut headers = HeaderMap::new();
2477+
headers.insert("Content-Type", HeaderValue::from_static("application/json"));
2478+
headers.insert("Accept", HeaderValue::from_static("*/*"));
2479+
2480+
// build user agent
2481+
match HeaderValue::from_str(local_configuration.user_agent.as_str()) {
2482+
Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent),
2483+
Err(e) => {
2484+
log::warn!("Failed to parse user agent header: {e}, falling back to default");
2485+
headers.insert(
2486+
reqwest::header::USER_AGENT,
2487+
HeaderValue::from_static(datadog::DEFAULT_USER_AGENT.as_str()),
2488+
)
2489+
}
2490+
};
2491+
2492+
// build auth
2493+
if let Some(local_key) = local_configuration.auth_keys.get("apiKeyAuth") {
2494+
headers.insert(
2495+
"DD-API-KEY",
2496+
HeaderValue::from_str(local_key.key.as_str())
2497+
.expect("failed to parse DD-API-KEY header"),
2498+
);
2499+
};
2500+
if let Some(local_key) = local_configuration.auth_keys.get("appKeyAuth") {
2501+
headers.insert(
2502+
"DD-APPLICATION-KEY",
2503+
HeaderValue::from_str(local_key.key.as_str())
2504+
.expect("failed to parse DD-APPLICATION-KEY header"),
2505+
);
2506+
};
2507+
2508+
// build body parameters
2509+
let output = Vec::new();
2510+
let mut ser = serde_json::Serializer::with_formatter(output, datadog::DDFormatter);
2511+
if body.serialize(&mut ser).is_ok() {
2512+
if let Some(content_encoding) = headers.get("Content-Encoding") {
2513+
match content_encoding.to_str().unwrap_or_default() {
2514+
"gzip" => {
2515+
let mut enc = GzEncoder::new(Vec::new(), Compression::default());
2516+
let _ = enc.write_all(ser.into_inner().as_slice());
2517+
match enc.finish() {
2518+
Ok(buf) => {
2519+
local_req_builder = local_req_builder.body(buf);
2520+
}
2521+
Err(e) => return Err(datadog::Error::Io(e)),
2522+
}
2523+
}
2524+
"deflate" => {
2525+
let mut enc = ZlibEncoder::new(Vec::new(), Compression::default());
2526+
let _ = enc.write_all(ser.into_inner().as_slice());
2527+
match enc.finish() {
2528+
Ok(buf) => {
2529+
local_req_builder = local_req_builder.body(buf);
2530+
}
2531+
Err(e) => return Err(datadog::Error::Io(e)),
2532+
}
2533+
}
2534+
"zstd1" => {
2535+
let mut enc = zstd::stream::Encoder::new(Vec::new(), 0).unwrap();
2536+
let _ = enc.write_all(ser.into_inner().as_slice());
2537+
match enc.finish() {
2538+
Ok(buf) => {
2539+
local_req_builder = local_req_builder.body(buf);
2540+
}
2541+
Err(e) => return Err(datadog::Error::Io(e)),
2542+
}
2543+
}
2544+
_ => {
2545+
local_req_builder = local_req_builder.body(ser.into_inner());
2546+
}
2547+
}
2548+
} else {
2549+
local_req_builder = local_req_builder.body(ser.into_inner());
2550+
}
2551+
}
2552+
2553+
local_req_builder = local_req_builder.headers(headers);
2554+
let local_req = local_req_builder.build()?;
2555+
log::debug!("request content: {:?}", local_req.body());
2556+
let local_resp = local_client.execute(local_req).await?;
2557+
2558+
let local_status = local_resp.status();
2559+
let local_content = local_resp.text().await?;
2560+
log::debug!("response content: {}", local_content);
2561+
2562+
if !local_status.is_client_error() && !local_status.is_server_error() {
2563+
Ok(datadog::ResponseContent {
2564+
status: local_status,
2565+
content: local_content,
2566+
entity: None,
2567+
})
2568+
} else {
2569+
let local_entity: Option<SyncTeamsError> = serde_json::from_str(&local_content).ok();
2570+
let local_error = datadog::ResponseContent {
2571+
status: local_status,
2572+
content: local_content,
2573+
entity: local_entity,
2574+
};
2575+
Err(datadog::Error::ResponseError(local_error))
2576+
}
2577+
}
2578+
24112579
/// Update a team using the team's `id`.
24122580
/// If the `team_links` relationship is present, the associated links are updated to be in the order they appear in the array, and any existing team links not present are removed.
24132581
pub async fn update_team(

0 commit comments

Comments
 (0)