---
title: GetObject · S3 API
description: Reads an object.
doc_version: 0.1.0-preview
last_updated: 2026-09-14
---

# GetObject

`GET /{bucket}/{key}`

Reads an object.

Returns the bytes of the object with its stored headers. Send a Range header to read part of the object.

- Role: Viewer or higher.
- Support: partial.
- Auth: AWS Signature Version 4 with your API key. See [S3 API](/api/s3.md).
- Supports versionId, conditions, and one byte range. Multiple ranges return 501. A public-read bucket needs no signature.
- An unsigned GET works on a bucket with the public-read permission.
- A presigned URL works. See [Authentication & keys](/guides/authentication).
- Storage ignores `partNumber` and the `response-*` query parameters, such as `response-content-type`.

## Example request

```http
GET /support-tickets/a.json HTTP/1.1
Host: wspq7ws2np5l8z4.storage.beta.graphon.sh
x-amz-date: 20261007T093000Z
x-amz-content-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Authorization: AWS4-HMAC-SHA256 Credential=<ACCESS_KEY_ID>/20261007/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=<SIGNATURE>
```

## Path parameters

- `bucket` (string, required): The bucket name.
- `key` (string, required): The object key. Keep each `/` as it is. Percent-encode the other reserved characters.

## Query parameters

- `versionId` (string, optional): Read this version. Without it, storage reads the current version.

## Headers

- `Range` (string, optional): One byte range, for example `bytes=0-1023`. More than one range returns `501 NotImplemented`.
- `If-Match` (string, optional): Return the object only when its ETag matches. Otherwise, storage returns `412 PreconditionFailed`.
- `If-None-Match` (string, optional): Return `304 Not Modified` when the ETag matches. Use it to revalidate a cached copy.
- `If-Modified-Since` (string, optional): An HTTP date. Return `304 Not Modified` when the object did not change after it. Storage ignores it when you send If-None-Match.
- `If-Unmodified-Since` (string, optional): An HTTP date. Return `412 PreconditionFailed` when the object changed after it. Storage ignores it when you send If-Match.
- `x-amz-expected-bucket-owner` (string, optional): The workspace ID that must own the bucket. Another owner returns `403 AccessDenied`.

## Responses

### 200 · OK

The whole object.

Response headers:

- `ETag` (string, optional): The entity tag of the object, in double quotes.
- `Content-Type` (string, optional): The media type that the write stored.
- `Content-Length` (integer, optional): The size of the object in bytes.
- `Last-Modified` (string, optional): When the version was written, as an HTTP date.
- `Accept-Ranges` (string, optional): Always `bytes`.
- `x-amz-version-id` (string, optional): The version ID of the object. Storage gives every write a version ID.
- `Cache-Control, Content-Disposition, Content-Encoding, Content-Language` (string, optional): Each header that the write stored. When the object has a Content-Encoding, Cache-Control also has `no-transform`, so the bytes arrive as stored.
- `x-amz-checksum-*` (string, optional): Each checksum that the write stored, such as `x-amz-checksum-sha256`.

```http
HTTP/1.1 200 OK
ETag: "9b2cf535f27731c974343645a3985328"
Content-Type: application/json
Content-Length: 34
Last-Modified: Wed, 07 Oct 2026 09:30:00 GMT
Accept-Ranges: bytes
x-amz-version-id: ver_5f0c8a8e3d2b4c1e9a7f6b5d4c3b2a19
x-amz-request-id: 4F8A2C7D1E6B4093A5C2D8E1F7B3A960

{"ticket": 4182, "status": "open"}
```

### 206 · Partial Content

The bytes in the Range. The response has no checksum headers, because they describe the whole object.

Response headers:

- `Content-Range` (string, optional): The range in the body and the full size, for example `bytes 0-9/1024`.
- `Content-Length` (integer, optional): The size of the range in bytes.
- `ETag` (string, optional): The entity tag of the object, in double quotes.
- `x-amz-version-id` (string, optional): The version ID of the object. Storage gives every write a version ID.

```http
HTTP/1.1 206 Partial Content
ETag: "9b2cf535f27731c974343645a3985328"
Content-Type: application/json
Content-Length: 10
Last-Modified: Wed, 07 Oct 2026 09:30:00 GMT
Accept-Ranges: bytes
x-amz-version-id: ver_5f0c8a8e3d2b4c1e9a7f6b5d4c3b2a19
Content-Range: bytes 0-9/34
x-amz-request-id: 4F8A2C7D1E6B4093A5C2D8E1F7B3A960

{"ticket":
```

### 304 · Not Modified

If-None-Match or If-Modified-Since matched. The response has no body.

Response headers:

- `ETag` (string, optional): The entity tag of the object, in double quotes.
- `x-amz-version-id` (string, optional): The version ID of the object. Storage gives every write a version ID.

```http
HTTP/1.1 304 Not Modified
ETag: "9b2cf535f27731c974343645a3985328"
Last-Modified: Wed, 07 Oct 2026 09:30:00 GMT
x-amz-version-id: ver_5f0c8a8e3d2b4c1e9a7f6b5d4c3b2a19
x-amz-request-id: 4F8A2C7D1E6B4093A5C2D8E1F7B3A960
```

## Errors

Any request can also get the common errors on [S3 API](/api/s3.md).

### 404 · `NoSuchKey`

The bucket has no object at this key, or no version with this versionId.

Check the key and the versionId.

### 404 · `NoSuchBucket`

No bucket has this name, or the bucket was deleted.

Check the bucket name. ListBuckets shows the buckets of the workspace.

### 403 · `AccessDenied`

The key does not have the Viewer role, or an unsigned request asked for a bucket that is not public-read.

Use a key of the workspace that owns the bucket, with the role above.

### 405 · `MethodNotAllowed`

The versionId names a delete marker, which has no bytes.

Use the versionId of a version that holds data. ListObjectVersions shows each one.

### 412 · `PreconditionFailed`

If-Match or If-Unmodified-Since did not hold.

Read the object again to get its current ETag, then decide whether to retry.

### 416 · `InvalidRange`

The range starts after the end of the object.

Read the size with HeadObject, then ask for a range inside it.

### 501 · `NotImplemented`

The Range header asks for more than one range.

Ask for one range in each request.

## Other request languages

### aws CLI

```bash
# The graphon profile from the S3 API overview.
export AWS_PROFILE=graphon

aws s3 cp s3://support-tickets/a.json ./a.json
```

### Python (boto3)

```python
# Replace wspq7ws2np5l8z4 with your workspace ID.
import os

import boto3
from botocore.config import Config

api_key = os.environ["GRAPHON_API_KEY"]
access_key_id = api_key.split("_", 1)[1].split(".")[0]

s3 = boto3.client(
    "s3",
    endpoint_url="https://wspq7ws2np5l8z4.storage.beta.graphon.sh",
    region_name="us-east-1",
    aws_access_key_id=access_key_id,
    aws_secret_access_key=api_key,
    config=Config(signature_version="s3v4", s3={"addressing_style": "path"}),
)

response = s3.get_object(
    Bucket="support-tickets",
    Key="a.json",
)
print(response["Body"].read())
```

### JavaScript (AWS SDK)

```javascript
// Replace wspq7ws2np5l8z4 with your workspace ID.
import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';

const apiKey = process.env.GRAPHON_API_KEY;
if (!apiKey) throw new Error('Set GRAPHON_API_KEY.');
const accessKeyId = apiKey.split('_')[1].split('.')[0];

const s3 = new S3Client({
  endpoint: 'https://wspq7ws2np5l8z4.storage.beta.graphon.sh',
  region: 'us-east-1',
  forcePathStyle: true,
  credentials: { accessKeyId, secretAccessKey: apiKey },
});

const response = await s3.send(new GetObjectCommand({
  Bucket: 'support-tickets',
  Key: 'a.json',
}));
console.log(await response.Body?.transformToString());
```

## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
