> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anycrm.anyreach.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Initiate an Upload

> Step 1 of the two-step upload flow.

Creates the files metadata row and returns a presigned PUT URL.
The browser must PUT the file bytes directly to upload_url.
On success the frontend should call onUploadComplete with the file_id.

<Note>New to files? See the [Files & Folders guide](/concepts/files-and-folders) for the upload model and how attachments work. This page is the field-level technical reference.</Note>

Step 1 of the upload flow. Creates the `files` row with `status: "pending"` and returns a presigned `PUT` URL valid for 15 minutes. The caller uploads the raw bytes directly to `upload_url`, then calls [Confirm an Upload](/api-reference/files/confirm-upload), which verifies the object landed and flips the row to `status: "uploaded"`.

[Get a Download URL](/api-reference/files/download-url) and [Get Extracted Text Content](/api-reference/files/text-content) reject a still-`pending` file with `409`. [Generate an AI Description](/api-reference/files/generate-description) does **not** — it never checks `status`, and on a pending file the missing S3 object is swallowed during text extraction, so it returns `200` with a description derived from the filename alone and persists it. Confirm the upload before asking for a description.

The presigned upload URL is signed against the exact `content_type` you send here. If the client's `PUT` request uses a different `Content-Type` header than what was passed to this call, S3 rejects the request with a signature mismatch — the header must match exactly, not be inferred by the HTTP client.

Attachments are a many-to-many join, not a field on the file (see [Attach a File to an Entity](/api-reference/files/attach)). Setting `entity_type` and `entity_id` here creates the first attachment inline as part of this same call — but setting only one of the pair is a silent no-op, no attachment is created and no error is raised.

### Auth

Requires a CRM manage [scope](/authentication#scopes) and an active organization on the token. Any `*:manage` scope qualifies — in practice `contacts:manage`, `deals:manage`, `companies:manage`, or `activities:manage`.

### Response

| Field        | Type            | Description                                                              |
| ------------ | --------------- | ------------------------------------------------------------------------ |
| `upload_url` | `string`        | Presigned S3 `PUT` URL, expires in 900 seconds.                          |
| `key`        | `string`        | The S3 object key the client must `PUT` to. Same value as `file.s3_key`. |
| `file_id`    | `string` (uuid) | The new file's id.                                                       |
| `file`       | object          | The full created `files` row (`status: "pending"`).                      |

### Errors

| Status            | Cause                                                                |
| ----------------- | -------------------------------------------------------------------- |
| `404 Not Found`   | `folder_id` doesn't exist (or isn't in this org / is archived).      |
| `502 Bad Gateway` | Could not generate the presigned URL, or the database insert failed. |


## OpenAPI

````yaml POST /files/upload-init
openapi: 3.1.0
info:
  title: anycrm-api
  version: 0.0.1
servers: []
security: []
tags:
  - name: Customer Intelligence
    description: >-
      Company research and ICP-fit scoring — create a research run, track its
      progress, and read back scored companies as leads.
  - name: Outreach
    description: >-
      The cold-email management console — domains, mailboxes, and campaigns — as
      a thin control plane over the SalesForge stack.
  - name: AnyCard
    description: >-
      Authenticated CRUD for AnyCard, the org's digital business-card /
      lead-capture product.
  - name: AnyCard Events
    description: >-
      Event-attribution analytics for AnyCard — which captured leads converted,
      broken down by source, owner, and deal.
  - name: AnyCard Share Links
    description: >-
      Unauthenticated endpoints reached by anyone who scans a QR code or opens a
      shared AnyCard link.
  - name: AI
    description: >-
      A streaming (SSE) AI chat endpoint with account-commit actions it can take
      on the caller's behalf.
  - name: Analytics Assistant
    description: >-
      The natural-language analytics assistant — a guarded text-to-SQL loop
      (SSE) that answers ad-hoc questions over the org's CRM data as a
      least-privilege, read-only database role.
  - name: Account Readiness
    description: >-
      Account Readiness Profiles — AI-scored signals on whether an account is
      ready for outreach or expansion, computed via a Temporal workflow.
  - name: Integrations
    description: >-
      Pipedream Connect — issuing connect tokens and managing the org's
      connected third-party accounts.
  - name: Feedback
    description: >-
      User-submitted platform feedback (bug reports, feature requests) — global,
      not scoped to one organization.
  - name: Public Media
    description: >-
      Unauthenticated image reads for publicly-embeddable assets (card photos,
      inline email images) — allowlisted by key shape; everything else in the
      storage bucket stays private.
  - name: Service Health
    description: Service liveness.
paths:
  /files/upload-init:
    post:
      tags:
        - Files
      summary: Upload Init
      description: |-
        Step 1 of the two-step upload flow.

        Creates the files metadata row and returns a presigned PUT URL.
        The browser must PUT the file bytes directly to upload_url.
        On success the frontend should call onUploadComplete with the file_id.
      operationId: upload_init_files_upload_init_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UploadInitRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                additionalProperties: true
                type: object
                title: Response Upload Init Files Upload Init Post
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      security:
        - HTTPBearer: []
components:
  schemas:
    UploadInitRequest:
      properties:
        filename:
          type: string
          title: Filename
          description: Original filename; sanitized and embedded in the generated S3 key.
        content_type:
          type: string
          title: Content Type
          description: >-
            MIME type stored on the file row and set as the presigned PUT's
            Content-Type.
          default: application/octet-stream
        size_bytes:
          anyOf:
            - type: integer
            - type: 'null'
          title: Size Bytes
          description: >-
            Client-reported size in bytes; stored as-is, not verified against
            the uploaded object.
        folder_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Folder Id
          description: Destination folder id; omit to upload to the Files root.
        tags:
          items:
            type: string
          type: array
          title: Tags
          description: Tag strings to store on the file row.
          default: []
        description:
          anyOf:
            - type: string
            - type: 'null'
          title: Description
          description: >-
            Optional one-line description; can also be filled in later via
            generate-description.
        entity_type:
          anyOf:
            - type: string
            - type: 'null'
          title: Entity Type
          description: >-
            If set together with entity_id, attaches the file to this CRM entity
            as part of the same call.
        entity_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Entity Id
          description: >-
            If set together with entity_type, attaches the file to this CRM
            entity as part of the same call.
      type: object
      required:
        - filename
      title: UploadInitRequest
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
      type: object
      required:
        - loc
        - msg
        - type
      title: ValidationError
  securitySchemes:
    HTTPBearer:
      type: http
      scheme: bearer

````