This page describes how to make a resumable upload request in the Street View
Publish API. This protocol allows you to resume an upload operation after a
communication failure interrupts the flow of data. Use this option if:

- You are uploading large files.
- The likelihood of network interruption or some other transmission failure is high (for example, if you are uploading a file from a mobile app).

Resumable uploads can also reduce your bandwidth usage when there is a network
failure, because you don't have to restart large file uploads from the
beginning.

If you are sending small files over a reliable network connection, you can use
a simple upload instead.

## Initiating a resumable upload session

After you have obtained an `uploadUrl`, you can initiate a resumable
upload session:

1. Create a `POST` request to the `uploadUrl`.
2. Add the following HTTP headers:

   - `X-Goog-Upload-Protocol`: Set to `resumable`.
   - `X-Goog-Upload-Header-Content-Length`: Set to the total number of bytes of the file data, which will be transferred in subsequent requests.
   - `X-Goog-Upload-Header-Content-Type`: Set to the MIME type of the file data.
   - `X-Goog-Upload-Command`: Set to `start`.
3. Send the request.

### Example: Initiating a resumable upload session

The following example shows how to initiate a resumable session to upload a new
file. In this case, the file is an image and the total number of bytes in the
file is 4200000. Note that the body of the request is empty; therefore, the
`Content-Length` header is set to 0.

    POST https://streetviewpublish.googleapis.com/media/user/123456789/photo/01234 HTTP/1.1
    Authorization: Bearer [YOUR_AUTH_TOKEN]
    Content-Length: 0
    X-Goog-Upload-Protocol: resumable
    X-Goog-Upload-Header-Content-Length: 4200000
    X-Goog-Upload-Header-Content-Type: image/jpeg
    X-Goog-Upload-Command: start

[Saving the resumable session URL](https://developers.google.com/streetview/publish/resumable-uploads#saving-resumable-session) describes how
to handle the response for the request to initiate the resumable upload session.

## Saving the resumable session URL

For the request sent to initiate a resumable upload session, the server will
reply with a `200 OK` HTTP status code, including the following header:

- `X-Goog-Upload-URL`: A unique URL that must be used to complete the upload through all of the remaining requests.

> [!NOTE]
> **Note:** A resumable session URL expires after 7 days.

Copy and save the resumable ression URL so that you can use it for subsequent
requests.

### Example: Saving the resumable session URL

The following example shows a response that includes a resumable session URL and
a size granularity requirement.

    HTTP/1.1 200 OK
    X-Goog-Upload-URL: https://streetviewpublish.googleapis.com/media/user/123456789/photo/01234?upload_id=AEnB2U&upload_protocol=resumable

## Uploading the file

There are two ways to upload a file with a resumable session:

1. **In a single request.** This approach is usually best, because it requires fewer requests and thus has better performance.
2. **In multiple chunks.** Use this approach if:
   - You need to reduce the amount of data transferred in any single request. You might need to do this when there is a fixed time limit for individual requests.
   - You need to provide a customized indicator showing the upload progress.
   - You need to know when it is safe to discard data.

### Single Request

To upload the file in a single request:

1. Create a `POST` request to the resumable session URL.
2. Add the file's data to the request body.
3. Add the following HTTP headers:

   - `Content-Length`: Set to the number of bytes in the file.
   - `X-Goog-Upload-Command`: Set to `upload, finalize`.
4. Send the request.

If the upload request is interrupted or you receive a `5xx` response, follow
the procedure in [Resuming an interrupted upload](https://developers.google.com/streetview/publish/resumable-uploads#resume-upload).

### Multiple Chunks

To upload the file in multiple chunks:

1. Create a `POST` request to the resumable session URL.
2. Add the chunk's data to the request body. Create chunks in multiples of 2 MiB (mebibytes), except for the final chunk that completes the upload. Keep the chunk size as large as possible so that the upload is efficient.
3. Add the following HTTP headers:

   - `Content-Length`: Set to the number of bytes in the chunk.
   - `X-Goog-Upload-Command`: Set to `upload`. For the last chunk, set to `upload, finalize`.
   - `X-Goog-Upload-Offset`: Set to the offset at which the bytes should be written. Note that the bytes must be uploaded serially.
4. Send the request. If the upload request is interrupted or you receive a
   `5xx` response, follow the procedure in
   [Resuming an interrupted upload](https://developers.google.com/streetview/publish/resumable-uploads#resume-upload).

5. Repeat steps 1 through 4 for each remaining chunk in the file.

### Example: Uploading the file

### Single Request

The following example shows a resumable request to upload an entire
4,200,000-byte JPEG file in a single request, using the resumable session
URL obtained in the previous step:

```
POST https://streetviewpublish.googleapis.com/media/user/123456789/photo/01234?upload_id=AEnB2U&upload_protocol=resumable HTTP/1.1
Content-Length: 4200000
X-Goog-Upload-Command: upload, finalize
X-Goog-Upload-Offset: 0

[BYTES 0-4199999]
```

If the request succeeds, you receive a `200 OK` HTTP status code.

### Multiple Chunks

The following example shows a resumable request to upload a 4,200,000-byte
JPEG file in multiple chunks, using the resumable session URL and the size
granularity obtained in the previous step. This example uses a chunk size of
2097000 bytes, which is a multiple of 2 MiB (mebibytes).

First chunk:

```
POST https://streetviewpublish.googleapis.com/media/user/123456789/photo/01234?upload_id=AEnB2U&upload_protocol=resumable HTTP/1.1
Content-Length: 2097000
X-Goog-Upload-Command: upload
X-Goog-Upload-Offset: 0

[BYTES 0-2096999]
```

<br />

Second chunk:

```
POST https://streetviewpublish.googleapis.com/media/user/123456789/photo/01234?upload_id=AEnB2U&upload_protocol=resumable HTTP/1.1
Content-Length: 2097000
X-Goog-Upload-Command: upload
X-Goog-Upload-Offset: 2097000

[BYTES 2097000-4193999]
```

<br />

Last chunk:

```
POST https://streetviewpublish.googleapis.com/media/user/123456789/photo/01234?upload_id=AEnB2U&upload_protocol=resumable HTTP/1.1
Content-Length: 6000
X-Goog-Upload-Command: upload, finalize
X-Goog-Upload-Offset: 4194000

[BYTES 4194000-4200000]
```

<br />

## Resuming an interrupted upload

If the upload request is interrupted or if you receive a non-`200` HTTP status
code, query the server to find out how much of the upload succeeded:

1. Create a `POST` request to the resumable session URL.
2. Set the `X-Goog-Upload-Command` to `query`.
3. Send the request.

The server will respond with a `200 OK` HTTP status code and the current size of the
upload:

    HTTP/1.1 200 OK
    X-Goog-Upload-Status: active
    X-Goog-Upload-Size-Received: 100

You can then resume uploading at this offset. You must resume at the offset
provided by the server unless you send a combined upload and finalize command,
in which case you can also resume at offset 0.

If the `X-Goog-Upload-Status` header in the HTTP response of your query command
is present and the value is not `active`, then the upload has already been
terminated.