> ## Documentation Index
> Fetch the complete documentation index at: https://developers.phrase.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Upload raw file bytes to Google Drive (streaming, phase 2)

> Phase 2 of the streaming upload flow. The caller PUTs raw bytes to this endpoint after
initializing a streaming upload via `POST /google-drive/v1/sync/upload-raw-file` with
`X-Upload-Mode: STREAM`.

The `{streamId}` path segment and `X-Stream-Token` header value both come from the
phase-1 response (`uploadUrl` already embeds the `streamId`; `X-Stream-Token` is the
`streamToken` field). The token is single-use and expires at `expiresAt`. The body must
be the raw file bytes; total size must not exceed the `maxBytes` returned by phase 1.

On success, the endpoint returns `204 No Content`.




## OpenAPI

````yaml /openapi/phrase-connectors.json put /google-drive/v1/sync/upload-raw-file/stream/{streamId}
openapi: 3.0.1
info:
  title: Connectors API
  description: >
    The Connectors API (Bifrost) is the public gateway between Phrase clients
    and the

    individual content connectors (Google Drive, Contentful, Tridion,
    Optimizely, ...).

    Every endpoint follows the same request/response contract — this page
    documents the

    shared pieces. Per-connector pages below show the connector-specific request
    bodies.


    ---


    ## Gateway prefix


    When calling Bifrost through the public Phrase gateway, **prefix every path
    with `/connectors`**:


    ```

    https://<phrase-host>/connectors/<connector>/v1/<operation>

    ```


    Internal callers (service-to-service inside the Phrase cluster) call Bifrost
    directly

    and omit the `/connectors` prefix. The OpenAPI paths below show the
    *internal* form.


    ---


    ## Authentication


    All endpoints require an IDM-issued JWT in the `Authorization` header:


    ```

    Authorization: Bearer <JWT>

    ```


    Bifrost decodes the token, resolves the caller's TMS account via IDM
    Discovery, and

    exchanges the JWT for a short-lived TMS access token transparently. Callers
    do not

    handle TMS tokens directly.


    ---


    ## Connector identity & credentials


    Every request body carries a **`connectorUuid`** that references a connector
    instance

    configured in TMS. Bifrost loads the connector's stored credentials and uses
    them to

    talk to the underlying system — callers never handle connector credentials
    directly.


    New connectors are created in TMS — e.g. for Google Drive:

    `https://<tms-host>/tms/connectors/create?connectorType=GOOGLE_DRIVE2`.


    ---


    ## Synchronous vs asynchronous variants


    Most operations expose two variants:


    | Path prefix | Behavior |

    |---|---|

    | `/sync/...`  | Blocks until the operation completes. Best for small
    payloads / interactive flows. |

    | `/async/...` | Returns immediately with `{ requestId, webHookUrl }`.
    Bifrost POSTs the result to `X-Webhook` when ready, or you can poll. Use for
    large payloads and long-running work. |


    For async endpoints, the `X-Webhook` header is **required** — Bifrost will
    POST the

    result there once the connector finishes processing.


    ---


    ## Common headers


    | Header | Direction | Purpose |

    |---|---|---|

    | `Authorization` | request | `Bearer <JWT>` — required on every endpoint. |

    | `X-ActionId` | request + response | Correlation id propagated through
    Phrase logs. Generated by Bifrost when omitted; always returned on the
    response. |

    | `X-Webhook` | request | Required on `/async/...` endpoints. URL that
    receives the result. |

    | `X-ResponseType` | request | `ID` (default) — JSON with `storageId`.
    `OBJECT` — raw binary stream (`application/octet-stream`). Use `ID` for
    files > 1 MB. |

    | `X-Upload-Mode` | request | `STORAGE` (default) — upload bytes already in
    file storage. `STREAM` — initialize a streaming upload session; the response
    carries `uploadUrl` + `X-Stream-Token` for the phase-2 PUT. Currently
    supported by Google Drive only. |

    | `X-Stream-Token` | request | Required on phase-2 streaming upload PUTs.
    Value returned by phase-1. |


    ---


    ## Raw vs XLIFF operations


    Most connectors expose two content shapes:


    - **Raw** (`download-raw-file`, `upload-raw-file`) — the connector's native
    content,
      unmodified. Use when you want the original asset.
    - **XLIFF** (`download-xliff-file`, `upload-xliff-file`) — the same content
    converted
      to/from XLIFF 2.0 ready for translation. The connector applies its segmentation
      and serialization rules.

    `convert-to-xliff` / `convert-to-raw` are the standalone conversion variants
    that

    operate on already-stored files referenced by `storageId`.


    ---


    ## Error model


    Errors come back in two envelopes depending on the endpoint:


    - **Operations that report partial success** (upload, convert) return `200
    OK` with:
      ```json
      { "success": false, "errors": [{ "code": "404", "message": "Content was not found." }] }
      ```
    - **Hard failures** return a 4xx/5xx with an `ErrorResponse` body. HTTP
    status maps
      to the Bifrost error taxonomy:

      | Status | Error type | Typical cause |
      |---|---|---|
      | 401, 403 | `auth_error` | Missing/invalid JWT, IDM identity unresolved, connector credential rejected upstream. |
      | 429 | `rate_limited` | Caller or upstream rate limit hit. |
      | 400 | `processing_error` | Bad request body, validation failure, unsupported configuration. |
      | 4xx (other) | `processing_error` | Connector returned a client error. |
      | 5xx | `upstream_error` | Connector or downstream Phrase service failed. |
      | timeout | `timeout` | Upstream did not respond in time. |
      | deserialization | `deserialization` | Connector returned a malformed response. |
      | other | `unknown` | Unclassified. |

      `X-ActionId` is returned on every error response — quote it when reporting issues.

    ---


    ## Streaming uploads (two-phase)


    For connectors that support `X-Upload-Mode: STREAM` (currently Google
    Drive):


    1. **Phase 1** — `POST /<connector>/v1/sync/upload-raw-file` with
       `X-Upload-Mode: STREAM` and a body that includes `name`, `size`, and a `FOLDER`
       path. The response is:
       ```json
       {
         "uploadUrl": "/<connector>/v1/sync/upload-raw-file/stream/<streamId>",
         "streamToken": "<token>",
         "expiresAt": "2026-01-29T13:48:01Z",
         "maxBytes": 240113628
       }
       ```
       `uploadUrl` is relative — prepend the gateway host (and `/connectors` prefix when
       calling through the public gateway).
    2. **Phase 2** — `PUT <host><uploadUrl>` with the raw bytes,
       `X-Stream-Token: <token>`, and a `Content-Type` matching the file. `Content-Length`
       must equal the declared `size`.

    Streams expire at `expiresAt`. Large transfers may need increased
    client-side timeouts.
  version: '1.0'
servers:
  - url: https://eu.phrase.com/connectors
    description: The API server for EU data center.
  - url: https://us.phrase.com/connectors
    description: The API server for US data center.
security:
  - bearerAuth: []
tags:
  - name: Files
    description: Upload and download files via Phrase file storage.
  - name: GitHub
    description: GitHub connector. Supports raw download/upload and batch uploads.
  - name: Braze
    description: Braze multilingual content connector.
  - name: Contentful
    description: >-
      Contentful headless CMS connector. Supports raw and XLIFF download/upload,
      listing entries, and standalone XLIFF conversion. Requires a
      `connectorUuid` and a `configuration` block on every request.
  - name: Google Drive
    description: >-
      Google Drive connector. Supports raw download/upload (JSON `storageId` or
      streamed binary via `X-ResponseType: OBJECT`) plus the two-phase streaming
      upload (`X-Upload-Mode: STREAM` → `X-Stream-Token`).
  - name: Connectors
    description: >-
      Cross-connector discovery and metadata: list available connector types,
      retrieve schemas, and inspect supported operations.
  - name: Tridion Docs
    description: SDL Tridion CMS connector.
  - name: GitHub
    description: Perform operations using the GitHub connector.
  - name: Optimizely
    description: Optimizely CMS / experimentation connector.
externalDocs:
  description: Tutorial-style integration guides (Phrase Confluence, INT space)
  url: https://phrase.atlassian.net/wiki/spaces/INT
paths:
  /google-drive/v1/sync/upload-raw-file/stream/{streamId}:
    put:
      tags:
        - Google Drive
      summary: Upload raw file bytes to Google Drive (streaming, phase 2)
      description: >
        Phase 2 of the streaming upload flow. The caller PUTs raw bytes to this
        endpoint after

        initializing a streaming upload via `POST
        /google-drive/v1/sync/upload-raw-file` with

        `X-Upload-Mode: STREAM`.


        The `{streamId}` path segment and `X-Stream-Token` header value both
        come from the

        phase-1 response (`uploadUrl` already embeds the `streamId`;
        `X-Stream-Token` is the

        `streamToken` field). The token is single-use and expires at
        `expiresAt`. The body must

        be the raw file bytes; total size must not exceed the `maxBytes`
        returned by phase 1.


        On success, the endpoint returns `204 No Content`.
      operationId: uploadStream
      parameters:
        - name: streamId
          in: path
          description: >-
            Stream identifier from the phase-1 response. Embedded in the
            `uploadUrl` returned by `POST /sync/upload-raw-file` with
            `X-Upload-Mode: STREAM`.
          required: true
          schema:
            type: string
          example: 550e8400-e29b-41d4-a716-446655440000
        - name: X-Stream-Token
          in: header
          description: >
            Required on the phase-2 PUT of a streaming upload (`X-Upload-Mode:
            STREAM`). The value is the `streamToken` returned by the phase-1
            initialize call. Mismatched or expired tokens are rejected with 401.
          required: true
          schema:
            type: string
          example: abc-123-token
        - name: Content-Type
          in: header
          description: >-
            MIME type of the bytes being uploaded. Defaults to
            `application/octet-stream` if omitted; set this to the file's true
            content type when known.
          required: false
          schema:
            type: string
            default: application/octet-stream
        - name: Content-Length
          in: header
          description: >-
            Size of the uploaded payload in bytes. Must not exceed `maxBytes`
            from phase 1.
          required: false
          schema:
            type: integer
            format: int64
      requestBody:
        description: >-
          Raw bytes of the file to upload. The body is streamed unmodified to
          Google Drive.
        content:
          application/octet-stream:
            schema:
              type: string
              format: binary
        required: true
      responses:
        '204':
          description: Success — bytes accepted and forwarded to Google Drive.
        '401':
          description: Unauthorized — invalid or missing `X-Stream-Token`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden — token does not match the stream session.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '410':
          description: Gone — token or stream session has expired (after `expiresAt`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '413':
          description: >-
            Payload Too Large — `Content-Length` exceeds the `maxBytes` allowed
            by phase 1.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '501':
          description: Not Implemented — no upload provider is registered for this stream.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          description: >-
            Bad Gateway — the connector failed to write the bytes to Google
            Drive.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
components:
  schemas:
    ErrorResponse:
      type: object
      properties:
        problemDetail:
          $ref: '#/components/schemas/ProblemDetail'
    ProblemDetail:
      type: object
      properties:
        type:
          type: string
          format: uri
        title:
          type: string
        status:
          type: integer
          format: int32
        detail:
          type: string
        instance:
          type: string
          format: uri
        properties:
          type: object
          additionalProperties:
            type: object
  securitySchemes:
    bearerAuth:
      type: http
      description: >-
        IDM-issued JWT. Obtain via the IDM authentication flow and pass as:
        Bearer <token>
      scheme: bearer
      bearerFormat: JWT

````