May 30, 2025 by simo

https://youtu.be/JGCQi0AOeew

If you have used the Notion API before May 2025 and needed to upload files, you found out you couldn't upload files directly; you could only link to externally hosted files (e.g., Google Drive, Dropbox, or similar file storage service).

Now, the Notion API also supports direct (and indirect) file uploads. This means you can upload files to Notion properties or blocks via the API without needing an external hosting service. It can be useful for automated workflows that involve file generation and storage. For example, automatically generating and attaching invoices to your dedicated Notion database, or uploading contract files to Notion, and all the other possible use cases you can imagine. This post explains everything you need to know about the Notion File Upload API.

General principles

There are two types of file uploads via the Notion API:

  1. Direct Uploads — file uploads to Notion-managed storage (multi-part/form data)
  2. Indirect Uploads — file uploads of externally hosted files into a Notion workspace (i.e., upload from a file url)

Uploaded files can be attached to file, image, pdf, audio, and video block types. You can also set a file_upload on a page’s cover or icon, or in files properties in pages under a database.

Downloading a file you’ve uploaded. Aside from making the file available in the Notion app, attaching a File Upload to a page also allows you to retrieve the page in the API to get a temporary URL to access the file. After the expiry_time shown in the response (generally 1 hour), the page (or block, or database) must be fetched again to generate a new URL.

Notion doesn’t provide any permanent download links for files you’ve uploaded.

— source: documentation

There are three steps (three API calls) to upload a file to Notion via the API:

  1. Create a file upload: This generates a file upload ID, which you will use in the following step to upload the file to Notion. Use the mode body parameter to define if it’s a single-part upload (file <20MB), multi-part (file >20MB), or external_url (you upload the file from an external URL). Include the other parameters based on your needs as per the documentation.

  2. Upload the file: Now that you have the file_upload_id, you will include it in the URL for the request to upload the file to Notion. For this request, use the Content-Type header with multipart/form-data as its value. Include the file parameter in the body of the request, and optionally part_number (for multi-part uploads — i.e., files > 20MB).

  3. Attach the file to a block/property: Use the API endpoint to update/append a block or create/update a database item and include the file data in your request. See details below.

    This step uses standard Notion API endpoints; there’s no special upload-specific API for attaching. Just pass a file object with a type of file_upload and include the id you received earlier.

    You can reuse the same file_upload ID across multiple pages or blocks. Upload once, attach many times.

    Files must be attached to a page or block within 1 hour of creation, or they’ll be automatically deleted.

    — source: documentation

Direct uploads

Direct upload means uploading a file directly to Notion via multipart/form-data requests, not using an external URL. If a file is <20MB in size, you can upload it with one request. For larger files (>20MB), you will first split the file into smaller parts (Notion recommends 10MB each), and then upload it across multiple multipart/form-data requests.

For direct uploads, the three steps written in the previous section is all you need. Here is a more detailed breakdown of each step:

  1. Create a file upload. This generates a unique upload ID and URL, which you will use in the next request (step 2).

    Example cURL:

    curl --request POST \\
    --url '[<https://api.notion.com/v1/file_uploads>](<https://api.notion.com/v1/file_uploads>)' \\
    -H 'Authorization: Bearer ntn_****' \\
    -H 'Content-Type: application/json' \\
    -H 'Notion-Version: 2022-06-28' \\
    --data '{}'
    
  2. Upload the file. Use the upload ID or URL from step 1 to send the binary file to Notion. Make sure to include the Content-Type header as multipart/form-data. Include the file key in the form fields of the request.

    Example cURL:

    curl --request POST \\
      --url '<https://api.notion.com/v1/file_uploads/a3f9d3e2-1abc-42de-b904-badc0ffee000/send>' \\
      -H 'Authorization: Bearer ntn_****' \\
      -H 'Notion-Version: 2022-06-28' \\
      -H 'Content-Type: multipart/form-data' \\
      -F "file=@path/to-file.gif"
    
  3. Attach the file to a Notion block. Do this within 1 hour from the file upload request, else the file upload will be automatically deleted.

    Once the file’s status is uploaded, you can attach it to Notion content using the file_upload ID. This ID can be passed anywhere a File object is accepted — including properties on database pages and content blocks like images or files.

    This step uses standard Notion API endpoints; there’s no special upload-specific API for attaching. Just pass a file object with a type of file_upload and include the id you received earlier.

    — source: documentation