---
title: "Add attachment"
method: POST
path: "/rest/api/2/issue/{issueIdOrKey}/attachments"
tags: ["Issue attachments"]
---

# Add attachment

`POST /rest/api/2/issue/{issueIdOrKey}/attachments`

Adds one or more attachments to an issue. Attachments are posted as multipart/form-data ([RFC 1867](https://www.ietf.org/rfc/rfc1867.txt)).

Note that:

 *  The request must have a `X-Atlassian-Token: no-check` header, if not it is blocked. See [Special headers](#special-request-headers) for more information.
 *  The name of the multipart/form-data parameter that contains the attachments must be `file`.

The following examples upload a file called *myfile.txt* to the issue *TEST-123*:

#### curl ####

    curl --location --request POST 'https://your-domain.atlassian.net/rest/api/2/issue/TEST-123/attachments'
     -u 'email@example.com:<api_token>'
     -H 'X-Atlassian-Token: no-check'
     --form 'file=@"myfile.txt"'

#### Node.js ####

    // This code sample uses the 'node-fetch' and 'form-data' libraries:
     // https://www.npmjs.com/package/node-fetch
     // https://www.npmjs.com/package/form-data
     const fetch = require('node-fetch');
     const FormData = require('form-data');
     const fs = require('fs');
    
     const filePath = 'myfile.txt';
     const form = new FormData();
     const stats = fs.statSync(filePath);
     const fileSizeInBytes = stats.size;
     const fileStream = fs.createReadStream(filePath);
    
     form.append('file', fileStream, {knownLength: fileSizeInBytes});
    
     fetch('https://your-domain.atlassian.net/rest/api/2/issue/TEST-123/attachments', {
         method: 'POST',
         body: form,
         headers: {
             'Authorization': `Basic ${Buffer.from(
                 'email@example.com:'
             ).toString('base64')}`,
             'Accept': 'application/json',
             'X-Atlassian-Token': 'no-check'
         }
     })
         .then(response => {
             console.log(
                 `Response: ${response.status} ${response.statusText}`
             );
             return response.text();
         })
         .then(text => console.log(text))
         .catch(err => console.error(err));

#### Java ####

    // This code sample uses the  'Unirest' library:
     // http://unirest.io/java.html
     HttpResponse response = Unirest.post("https://your-domain.atlassian.net/rest/api/2/issue/{issueIdOrKey}/attachments")
             .basicAuth("email@example.com", "")
             .header("Accept", "application/json")
             .header("X-Atlassian-Token", "no-check")
             .field("file", new File("myfile.txt"))
             .asJson();
    
             System.out.println(response.getBody());

#### Python ####

    # This code sample uses the 'requests' library:
     # http://docs.python-requests.org
     import requests
     from requests.auth import HTTPBasicAuth
     import json
    
     url = "https://your-domain.atlassian.net/rest/api/2/issue/{issueIdOrKey}/attachments"
    
     auth = HTTPBasicAuth("email@example.com", "")
    
     headers = {
        "Accept": "application/json",
        "X-Atlassian-Token": "no-check"
     }
    
     response = requests.request(
        "POST",
        url,
        headers = headers,
        auth = auth,
        files = {
             "file": ("myfile.txt", open("myfile.txt","rb"), "application-type")
        }
     )
    
     print(json.dumps(json.loads(response.text), sort_keys=True, indent=4, separators=(",", ": ")))

#### PHP ####

    // This code sample uses the 'Unirest' library:
     // http://unirest.io/php.html
     Unirest\Request::auth('email@example.com', '');
    
     $headers = array(
       'Accept' => 'application/json',
       'X-Atlassian-Token' => 'no-check'
     );
    
     $parameters = array(
       'file' => File::add('myfile.txt')
     );
    
     $response = Unirest\Request::post(
       'https://your-domain.atlassian.net/rest/api/2/issue/{issueIdOrKey}/attachments',
       $headers,
       $parameters
     );
    
     var_dump($response)

#### Forge ####

    // This sample uses Atlassian Forge and the `form-data` library.
     // https://developer.atlassian.com/platform/forge/
     // https://www.npmjs.com/package/form-data
     import api from "@forge/api";
     import FormData from "form-data";
    
     const form = new FormData();
     form.append('file', fileStream, {knownLength: fileSizeInBytes});
    
     const response = await api.asApp().requestJira('/rest/api/2/issue/{issueIdOrKey}/attachments', {
         method: 'POST',
         body: form,
         headers: {
             'Accept': 'application/json',
             'X-Atlassian-Token': 'no-check'
         }
     });
    
     console.log(`Response: ${response.status} ${response.statusText}`);
     console.log(await response.json());

Tip: Use a client library. Many client libraries have classes for handling multipart POST operations. For example, in Java, the Apache HTTP Components library provides a [MultiPartEntity](http://hc.apache.org/httpcomponents-client-ga/httpmime/apidocs/org/apache/http/entity/mime/MultipartEntity.html) class for multipart POST operations.

This operation can be accessed anonymously.

**[Permissions](#permissions) required:** 

 *  *Browse Projects* and *Create attachments* [ project permission](https://confluence.atlassian.com/x/yodKLg) for the project that the issue is in.
 *  If [issue-level security](https://confluence.atlassian.com/x/J4lKLg) is configured, issue-level security permission to view the issue.

## Path parameters

- `issueIdOrKey` string, required

## Response `200`

Returned if the request is successful.

- Attachment[]
  - `author` UserDetails — User details permitted by the user's Atlassian Account privacy settings. However, be aware of these exceptions: * User record deleted from Atlassian: This occurs as the result of a right to be forgotten request. In this case, `displayName` provides an indication and other parameters have default values or are blank (for example, email is blank). * User record corrupted: This occurs as a results of events such as a server import and can only happen to deleted users. In this case, `accountId` returns *unknown* and all other parameters have fallback values. * User record unavailable: This usually occurs due to an internal service outage. In this case, all parameters have fallback values.
    - `accountId` string — The account ID of the user, which uniquely identifies the user across all Atlassian products. For example, *5b10ac8d82e05b22cc7d4ef5*.
    - `accountType` string — The type of account represented by this user. This will be one of 'atlassian' (normal users), 'app' (application user) or 'customer' (Jira Service Desk customer user)
    - `active` boolean — Whether the user is active.
    - `avatarUrls` AvatarUrlsBean
      - `16x16` string, uri — The URL of the item's 16x16 pixel avatar.
      - `24x24` string, uri — The URL of the item's 24x24 pixel avatar.
      - `32x32` string, uri — The URL of the item's 32x32 pixel avatar.
      - `48x48` string, uri — The URL of the item's 48x48 pixel avatar.
    - `displayName` string — The display name of the user. Depending on the user’s privacy settings, this may return an alternative value.
    - `emailAddress` string — The email address of the user. Depending on the user’s privacy settings, this may be returned as null.
    - `key` string — This property is no longer available and will be removed from the documentation soon. See the [deprecation notice](https://developer.atlassian.com/cloud/jira/platform/deprecation-notice-user-privacy-api-migration-guide/) for details.
    - `name` string — This property is no longer available and will be removed from the documentation soon. See the [deprecation notice](https://developer.atlassian.com/cloud/jira/platform/deprecation-notice-user-privacy-api-migration-guide/) for details.
    - `self` string — The URL of the user.
    - `timeZone` string — The time zone specified in the user's profile. Depending on the user’s privacy settings, this may be returned as null.
  - `content` string — The content of the attachment.
  - `created` string, date-time — The datetime the attachment was created.
  - `filename` string — The file name of the attachment.
  - `id` string — The ID of the attachment.
  - `mimeType` string — The MIME type of the attachment.
  - `self` string — The URL of the attachment details response.
  - `size` integer — The size of the attachment.
  - `thumbnail` string — The URL of a thumbnail representing the attachment.

## Other responses

- `403` — Returned if the user does not have the necessary permission.
- `404` — Returned if any of the following is true: * the issue is not found. * the user does not have permission to view the issue.
- `413` — Returned if any of the following is true: * the attachments exceed the maximum attachment size for issues. * more than 60 files are requested to be uploaded. * the per-issue limit for attachments has been breached. See [Configuring file attachments](https://confluence.atlassian.com/x/wIXKM) for details.

---

[API](https://skmtc.net/atlassian/apis/the-jira-cloud-platform-rest-api.md) · [All operations](https://skmtc.net/atlassian/apis/the-jira-cloud-platform-rest-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/atlassian/the-jira-cloud-platform-rest-api/versions/a26541c2f8bd/schema)
