Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Direct S3 Access to EarthScope miniSEED data

EarthScope miniSEED data can be read directly from S3. There are two buckets depending on which network you need:

DataNetworksS3 location
AWS Open Data ProgramAK, II, IU, N4, PB, TA, UU, UWs3://earthscope-geophysical-data
EarthScope RepositoryAll other networkss3://earthscope-mseed-v2-4fdodyzpsz8u8uyi3pa9qsw9oid1suse2a-s3alias

Data in both buckets use the same object key layout: miniseed/NETWORK/YEAR/DAYOFYEAR/STATION.NETWORK.YEAR.DAYOFYEAR

Prerequisites

  • An EarthScope account: https://www.earthscope.org/user

  • Account approved for S3 direct access

  • Retrieving data from the Repository bucket must occur within AWS us-east-2

    • Retrieving data from Open Data Program is allowed everywhere

from earthscope_sdk import EarthScopeClient

client = EarthScopeClient()

Well-behaved Clients

When calling the credentials API from long-running jobs or bulk downloads, follow these rules:

  1. Reuse the EarthScopeClient instance.

    Create one client and keep it for the lifetime of the process. A new client per request discards the SDK’s in-memory credential cache and forces unnecessary OAuth and token-exchange traffic.

  2. Reuse credentials for the whole S3 prefix until they expire (or are near expiration).

    Credentials from client.user.get_aws_credentials(...) (or a boto session built from them) authorize every object under that network — or network+year — prefix. Do not request new credentials for each object.

  3. Do not retry unretriable errors (400, 403, 404). Those are verdicts on the request, not transient failures:

    • 400 Bad Request — the request itself is invalid.

      A common case is asking for a temporary network without a year. Temporary FDSN codes are reused across experiments, so EarthScope must authorize at the network+year level.

    • 403 Forbidden — your account does not have access to that network or network+year.

    • 404 Not Found — the FDSN network code (or network+year) you requested was not found.

Obtaining Credentials

Request credentials without network for Open Data Program bucket access and Repository listing. See API documentation.

boto3 is the AWS SDK for Python. The earthscope-sdk’s client.user.get_boto3_session(...) wraps the credentials endpoint and returns a refreshable boto3 session.

session = client.user.get_boto3_session(role="s3-miniseed-v2")
s3_client = session.client("s3")

ODP_BUCKET = "earthscope-geophysical-data"
REPO_BUCKET = "earthscope-mseed-v2-4fdodyzpsz8u8uyi3pa9qsw9oid1suse2a-s3alias"
PREFIX = "miniseed/"

Read AWS Open Data Program (ODP) networks

Networks AK, II, IU, N4, PB, TA, UU, UW are published through the AWS Open Data Program as Sponsored Open Data on AWS. Read them from the bucket earthscope-geophysical-data.

list_resp = s3_client.list_objects_v2(
    Bucket=ODP_BUCKET,
    Prefix=PREFIX,
    Delimiter="/",
)
odp_networks = [c["Prefix"].split("/", 1)[1] for c in list_resp["CommonPrefixes"]]
print(odp_networks)

object_key = "miniseed/TA/2004/365/A04A.TA.2004.365"

response = s3_client.get_object(Bucket=ODP_BUCKET, Key=object_key)
data = response["Body"].read()
print(f"Downloaded {len(data)} bytes from s3://{ODP_BUCKET}/{object_key}")
['AK/', 'II/', 'IU/', 'N4/', 'PB/', 'TA/', 'UU/', 'UW/']
Downloaded 2740224 bytes from s3://earthscope-geophysical-data/miniseed/TA/2004/365/A04A.TA.2004.365

Repository direct access

For networks not published to the Open Data Program, request credentials with an explicit FDSN network — for example network="FDSN:UO". Credentials for permanent networks authorize GetObject to objects under miniseed/<NETWORK>/*.

NETWORK = "FDSN:UO"

repo_session = client.user.get_boto3_session(
    role="s3-miniseed-v2",
    network=NETWORK,
)
repo_s3 = repo_session.client("s3")

Temporary networks

Temporary FDSN networks reuse classical 2-character FDSN network codes so credentials must be scoped to a specific network-year prefix: miniseed/<NETWORK>/<YEAR>/*.

When requesting credentials for a temporary FDSN network (i.e. it starts with digits 0-9 or letters X, Y or Z), you must include year in the credential request:

repo_session = client.user.get_boto3_session(
    role="s3-miniseed-v2",
    network="FDSN:1E",
    year=2024,
)

Repository data is exposed via an S3 Access Point (S3AP). The access point alias is used in place of the bucket name in all S3 operations.

Credentials allow listing the entire miniseed/ prefix on the access point, including all network “subdirectories”. All networks appear in listings but cannot be downloaded unless your credentials were issued for that network (and year, if applicable).

list_resp = repo_s3.list_objects_v2(
    Bucket=REPO_BUCKET,
    Prefix=PREFIX,
    Delimiter="/",
)
nets = [c["Prefix"].split("/", 1)[1] for c in list_resp["CommonPrefixes"]]
print(nets)
['12/', '14/', '16/', '17/', '1A/', '1B/', '1C/', '1D/', '1E/', '1F/', '1G/', '1H/', '1J/', '1K/', '1L/', '1M/', '1O/', '1P/', '1Q/', '1R/', '1T/', '1U/', '1V/', '1W/', '1Z/', '22/', '24/', '28/', '29/', '2A/', '2B/', '2C/', '2D/', '2E/', '2F/', '2G/', '2H/', '2I/', '2J/', '2K/', '2L/', '2M/', '2O/', '2P/', '2Q/', '2T/', '2U/', '2V/', '34/', '3A/', '3B/', '3C/', '3D/', '3E/', '3F/', '3H/', '3J/', '3K/', '3L/', '3R/', '3U/', '3W/', '3Y/', '4A/', '4B/', '4E/', '4F/', '4H/', '4I/', '4J/', '4K/', '4N/', '4O/', '4P/', '4Q/', '4R/', '4S/', '4T/', '4U/', '4Y/', '4Z/', '5A/', '5B/', '5C/', '5E/', '5F/', '5G/', '5H/', '5I/', '5J/', '5K/', '5L/', '5O/', '5P/', '5Q/', '5S/', '5W/', '5X/', '6A/', '6B/', '6C/', '6D/', '6E/', '6F/', '6G/', '6H/', '6I/', '6J/', '6K/', '6L/', '6M/', '6N/', '6O/', '6P/', '6Q/', '6R/', '6W/', '7A/', '7B/', '7C/', '7D/', '7E/', '7F/', '7G/', '7I/', '7J/', '7K/', '7L/', '7O/', '7P/', '7Q/', '7S/', '7T/', '7U/', '8A/', '8B/', '8E/', '8F/', '8G/', '8H/', '8I/', '8J/', '8L/', '8M/', '8P/', '8Q/', '8S/', '8U/', '8W/', '9A/', '9B/', '9C/', '9D/', '9F/', '9G/', '9H/', '9K/', '9L/', '9M/', '9P/', '9R/', 'A0/', 'A2/', 'A7/', 'AB/', 'AC/', 'AE/', 'AF/', 'AG/', 'AI/', 'AK/', 'AL/', 'AM/', 'AO/', 'AP/', 'AR/', 'AS/', 'AT/', 'AU/', 'AV/', 'AX/', 'AY/', 'AZ/', 'B6/', 'BC/', 'BE/', 'BF/', 'BI/', 'BK/', 'BL/', 'BV/', 'BX/', 'C/', 'C0/', 'C1/', 'C8/', 'CA/', 'CB/', 'CC/', 'CD/', 'CH/', 'CI/', 'CK/', 'CM/', 'CN/', 'CO/', 'CS/', 'CT/', 'CU/', 'CW/', 'CY/', 'CZ/', 'DA/', 'DE/', 'DK/', 'DR/', 'DT/', 'DU/', 'DW/', 'EC/', 'EI/', 'EM/', 'EO/', 'EP/', 'ER/', 'ET/', 'FA/', 'G/', 'GB/', 'GD/', 'GE/', 'GF/', 'GG/', 'GH/', 'GI/', 'GM/', 'GO/', 'GR/', 'GS/', 'GT/', 'GY/', 'H2/', 'HG/', 'HK/', 'HL/', 'HT/', 'HV/', 'HW/', 'HZ/', 'I0/', 'IC/', 'ID/', 'IE/', 'II/', 'IL/', 'IM/', 'IN/', 'IO/', 'IP/', 'IU/', 'IV/', 'IW/', 'JM/', 'JP/', 'JW/', 'K5/', 'KC/', 'KG/', 'KN/', 'KO/', 'KP/', 'KR/', 'KS/', 'KW/', 'KY/', 'KZ/', 'LB/', 'LD/', 'LH/', 'LI/', 'LM/', 'LO/', 'LX/', 'M8/', 'MB/', 'MC/', 'MG/', 'MH/', 'MI/', 'MM/', 'MN/', 'MP/', 'MR/', 'MS/', 'MU/', 'MX/', 'MY/', 'MZ/', 'N0/', 'N4/', 'NA/', 'NB/', 'NC/', 'NE/', 'NI/', 'NJ/', 'NK/', 'NL/', 'NM/', 'NN/', 'NO/', 'NP/', 'NQ/', 'NR/', 'NT/', 'NU/', 'NV/', 'NW/', 'NX/', 'NY/', 'NZ/', 'O2/', 'OC/', 'OE/', 'OH/', 'OI/', 'OK/', 'ON/', 'OO/', 'OQ/', 'OV/', 'OW/', 'OX/', 'OZ/', 'PA/', 'PB/', 'PE/', 'PI/', 'PL/', 'PM/', 'PN/', 'PO/', 'PQ/', 'PR/', 'PS/', 'PT/', 'PY/', 'QC/', 'QN/', 'QZ/', 'RC/', 'RE/', 'RI/', 'RM/', 'RO/', 'RS/', 'RU/', 'RV/', 'S1/', 'S8/', 'SB/', 'SC/', 'SE/', 'SF/', 'SG/', 'SH/', 'SN/', 'SP/', 'SR/', 'SS/', 'SV/', 'SY/', 'TA/', 'TC/', 'TD/', 'TF/', 'TJ/', 'TM/', 'TO/', 'TR/', 'TT/', 'TW/', 'TX/', 'TZ/', 'UF/', 'UH/', 'UI/', 'UK/', 'UM/', 'UO/', 'US/', 'UT/', 'UU/', 'UW/', 'VD/', 'VE/', 'VU/', 'WA/', 'WC/', 'WF/', 'WI/', 'WM/', 'WU/', 'WW/', 'WY/', 'X1/', 'X2/', 'X3/', 'X4/', 'X5/', 'X6/', 'X7/', 'X8/', 'X9/', 'XA/', 'XB/', 'XC/', 'XD/', 'XE/', 'XF/', 'XG/', 'XH/', 'XI/', 'XJ/', 'XK/', 'XL/', 'XM/', 'XN/', 'XO/', 'XP/', 'XQ/', 'XR/', 'XS/', 'XT/', 'XU/', 'XV/', 'XW/', 'XX/', 'XY/', 'XZ/', 'Y1/', 'Y2/', 'Y3/', 'Y4/', 'Y5/', 'Y6/', 'Y7/', 'Y8/', 'Y9/', 'YA/', 'YB/', 'YC/', 'YD/', 'YE/', 'YF/', 'YG/', 'YH/', 'YI/', 'YJ/', 'YK/', 'YL/', 'YM/', 'YN/', 'YO/', 'YP/', 'YQ/', 'YR/', 'YS/', 'YT/', 'YU/', 'YV/', 'YW/', 'YX/', 'YY/', 'YZ/', 'Z1/', 'Z2/', 'Z3/', 'Z4/', 'Z5/', 'Z6/', 'Z7/', 'Z8/', 'Z9/', 'ZA/', 'ZB/', 'ZC/', 'ZD/', 'ZE/', 'ZF/', 'ZG/', 'ZH/', 'ZI/', 'ZJ/', 'ZK/', 'ZL/', 'ZM/', 'ZN/', 'ZO/', 'ZP/', 'ZQ/', 'ZR/', 'ZS/', 'ZT/', 'ZU/', 'ZV/', 'ZW/', 'ZX/', 'ZY/', 'ZZ/']

Objects under the FDSN network (and year) associated with your credentials download successfully — including unrestricted data and restricted data you have access to.

The cell below lists one object under the requested network and reads it. Adjust the year/day prefix if needed for your network.

network_code = NETWORK.split(":", 1)[1]
list_prefix = f"{PREFIX}{network_code}/2024/300/"

list_resp = repo_s3.list_objects_v2(Bucket=REPO_BUCKET, Prefix=list_prefix, MaxKeys=1)
object_key = list_resp["Contents"][0]["Key"]

response = repo_s3.get_object(Bucket=REPO_BUCKET, Key=object_key)
data = response["Body"].read()
print(f"Downloaded {len(data)} bytes from s3://{REPO_BUCKET}/{object_key}")
Downloaded 57044480 bytes from s3://earthscope-mseed-v2-4fdodyzpsz8u8uyi3pa9qsw9oid1suse2a-s3alias/miniseed/UO/2024/300/ADEL.UO.2024.300#2

Access denied outside your FDSN network scope

Credentials are scoped to the requested FDSN network (and year for temporary networks). Downloading an object outside that scope returns a standard S3 AccessDenied error.

try:
    repo_s3.get_object(
        Bucket=REPO_BUCKET,
        Key=f"{PREFIX}1E/2024/089/BCH1A.1E.2024.089#2",
    )
    raise RuntimeError("Should not reach this line")
except Exception as e:
    print("Expected failure for an object outside the credential's scope:")
    print(e)
Expected failure for an object outside the credential's scope:
An error occurred (AccessDenied) when calling the GetObject operation: User: arn:aws:sts::457219964709:assumed-role/earthscope-idm-mseed-v2/euid=Z29vZ2xlLW9hdXRoMnwxMTg0MDM1MDYxNTQ5NDI4NDI1ODM is not authorized to perform: s3:GetObject on resource: "arn:aws:s3:us-east-2:457219964709:accesspoint/earthscope-mseed-v2/object/miniseed/1E/2024/089/BCH1A.1E.2024.089#2" because no session policy allows the s3:GetObject action

Additional credential retrieval methods

Above, we demonstrate using the AWS boto3 python SDK for classical synchronous python programming. The following sections demonstrate how to retrieve temporary AWS credentials for additional use cases.

Asynchronous python with aioboto3

The aioboto3 library wraps boto3 in async interfaces for running code in an event loop.

The AsyncEarthScopeClient provides a method to retrieve a refreshable aioboto3 session.

from earthscope_sdk import AsyncEarthScopeClient

async_client = AsyncEarthScopeClient()

session = await async_client.user.get_aioboto3_session(
    role="s3-miniseed-v2",
    network=NETWORK,
)

async with session.client("s3") as async_s3:
    response = await async_s3.get_object(Bucket=REPO_BUCKET, Key=object_key)
    async with response["Body"] as stream:
        data = await stream.read()
        print(f"Downloaded {len(data)} bytes from s3://{REPO_BUCKET}/{object_key}")
Downloaded 57044480 bytes from s3://earthscope-mseed-v2-4fdodyzpsz8u8uyi3pa9qsw9oid1suse2a-s3alias/miniseed/UO/2024/300/ADEL.UO.2024.300#2

Non-boto use-cases

The methods EarthScopeClient.user.get_boto3_session(...) and AsyncEarthScopeClient.user.get_aioboto3_session(...) are convenience methods that return boto sessions that transparently handle credential expiration and refresh on your behalf.

However, there are many non-boto libraries for interacting with S3 that need credentials as well. To work with your library of choice using EarthScope direct access, you can retrieve AWS credentials directly.

creds = client.user.get_aws_credentials(
    role="s3-miniseed-v2",
    network=NETWORK,
)

# pass credentials to your library of choice
print(creds.expiration)
print(creds.aws_access_key_id)
print(creds.aws_secret_access_key)  # use creds.aws_secret_access_key.get_secret_value() to access the plaintext key
print(creds.aws_session_token)      # use creds.aws_session_token.get_secret_value() to access the plaintext session token
2026-08-26 21:45:23+00:00
ASIAWU5DO74SQVW7DUAK
**********
**********

Use the Open Data Program without an EarthScope account

Data in the Open Data Program is freely readable without authentication using an unsigned S3 client or the AWS CLI with --no-sign-request. That path does not attribute usage to your EarthScope user ID.

See Sponsored Open Data on AWS for details.