# Connect source to your AWS account

Connects an AWS account to an existing `aws` source, so we can enumerate your AWS resources and manage CloudWatch log group subscriptions.

This is the API equivalent of the **Connect your AWS account** step in the source's Ingest tab.

Create the source first with [Create a source](https://betterstack.com/docs/logs/api/create-a-source/) and `"platform": "aws"`, deploy the CloudFormation stack as described in [AWS CloudFormation](https://betterstack.com/docs/logs/aws-cloudformation/), then send the stack's `IntegrationRoleArn` and `ExternalId` outputs back with the request below.

[info]
#### Where do the credentials come from?
The CloudFormation stack creates the IAM role Better Stack assumes. In the AWS console, go to **CloudFormation → Stacks → betterstack → Outputs** and copy `IntegrationRoleArn` and `ExternalId`.
[/info]

[endpoint]
base_url = "https://telemetry.betterstack.com"
path = "/api/v1/sources/{source_id}"
method = "PATCH"

[[path_param]]
name = "id"
description = "ID of the `aws` source you want to connect the account to"
required = true
type = "string"

[[body_param]]
name = "aws_role_arn"
description = """
The `IntegrationRoleArn` output of the Better Stack CloudFormation stack.  \nMust be sent together with `aws_external_id`.
"""
required = false
type = "string"

[[body_param]]
name = "aws_external_id"
description = """
The `ExternalId` output of the Better Stack CloudFormation stack, used for the STS assume-role trust.  \nMust be sent together with `aws_role_arn`.
"""
required = false
type = "string"

[[body_param]]
name = "aws_account_id"
description = "The ID of an AWS account you have already connected. Send this instead of `aws_role_arn` and `aws_external_id` to link the source to that account."
required = false
type = "string"

[[header]]
name = "Authorization"
description = "Bearer `$TOKEN`"
required = true
type = "string"
[/endpoint]

[responses]
[[response]]
status = 200
description = '''The AWS account was connected. The credentials are write-only and are never returned, so the response is the plain source object.'''
body = '''{
    "data": {
        "id": "95",
        "type": "source",
        "attributes": {
            "source_group_id": 572,
            "team_id": 123,
            "team_name": "Test team",
            "name": "AWS production",
            "platform": "aws",
            "table_name": "aws_production",
            "token": "FczKcxEhjEDE58dBX7XaeX1q",
            "ingesting_paused": false,
            "ingesting_host": "s95.eu-nbg-2.betterstackdata.com",
            "created_at": "2026-05-27T12:30:41.695Z",
            "updated_at": "2026-06-11T14:00:50.756Z",
            "logs_retention": 7,
            "metrics_retention": 14,
            "data_region": "eu-nbg-2"
        }
    }
}'''

[[response]]
status = 404
description = '''Your team has no source with the given ID'''
body = '''{
    "errors": "Resource with provided ID was not found"
}'''

[[response]]
status = 422
description = '''Only one of the two credentials was sent'''
body = '''{
    "errors": "Both Role ARN and External ID are required.",
    "invalid_attributes": []
}'''

[[response]]
status = 422
description = '''Better Stack could not assume the role with the given credentials'''
body = '''{
    "errors": "AWS credentials validation failed: User is not authorized to perform: sts:AssumeRole",
    "invalid_attributes": []
}'''
[/responses]

#### Example cURL

```shell
[label Connect an AWS account]
curl --request PATCH \
  --url https://telemetry.betterstack.com/api/v1/sources/95 \
  --header "Authorization: Bearer $TOKEN" \
  --header "Content-Type: application/json" \
  --data '{
    "aws_role_arn": "arn:aws:iam::123456789012:role/BetterStackIntegrationRole",
    "aws_external_id": "0f8a1c2e-4b7d-4f10-9a55-2c1d3e4f5a6b"
  }'
```

Resource discovery starts right after the account is connected. Log groups and metrics appear in the source's Ingest tab within a few minutes.
