Skip to content

Attach resource ​

API Reference

Note: The path is a placeholder. The actual path is determined by the configuration of the app component.

When the user attaches a resource URL to a task, Asana will make a signed request to the specified resource_attach_url in the app configuration. Information about the attached resource should be included in the response.

OpenAPI definition ​

json
{
  "openapi": "3.0.0",
  "info": {
    "description": "This is the interface for handling requests for app components. This reference is generated from an [OpenAPI spec] (https://raw.githubusercontent.com/Asana/openapi/master/defs/app_components_oas.yaml).",
    "title": "App Components",
    "termsOfService": "https://asana.com/terms",
    "contact": {
      "name": "Asana Support",
      "url": "https://asana.com/support"
    },
    "license": {
      "name": "Apache 2.0",
      "url": "https://www.apache.org/licenses/LICENSE-2.0"
    },
    "version": "0.1",
    "x-docs-schema-whitelist": [
      "AttachedResourceResponse",
      "FormField-Checkbox",
      "FormField-Date",
      "FormField-Datetime",
      "FormField-Dropdown",
      "FormField-MultiLineText",
      "FormField-RadioButton",
      "FormField-RichText",
      "FormField-SingleLineText",
      "FormField-StaticText",
      "FormField-Typeahead",
      "FormMetadataResponse",
      "RanActionResponse",
      "WidgetFooter-CustomText",
      "WidgetFooter-Created",
      "WidgetFooter-Updated",
      "WidgetMetadataResponse",
      "WidgetField-DatetimeWithIcon",
      "WidgetField-Pill",
      "WidgetField-TextWithIcon",
      "TypeaheadListResponse",
      "TypeaheadItem",
      "FormValues",
      "BadRequestResponse",
      "UnauthorizedResponse",
      "ForbiddenResponse",
      "NotFoundResponse",
      "InternalServerErrorResponse"
    ]
  },
  "x-readme": {
    "explorer-enabled": false
  },
  "servers": [
    {
      "url": "{siteUrl}",
      "description": "Main endpoint."
    }
  ],
  "tags": [
    {
      "name": "Lookups",
      "description": "If the app defined a resource attach URL, tasks without a widget offer the lookup functionality. This appears as a text input to the user. When the user submits the text, the app responds with either a resource attachment or with an error."
    }
  ],
  "components": {
    "responses": {
      "BadRequest": {
        "description": "Bad request",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/BadRequestResponse"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Unauthorized",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/UnauthorizedResponse"
            }
          }
        }
      },
      "Forbidden": {
        "description": "Forbidden",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ForbiddenResponse"
            }
          }
        }
      },
      "NotFound": {
        "description": "Not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/NotFoundResponse"
            }
          }
        }
      },
      "InternalServerError": {
        "description": "Server error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/InternalServerErrorResponse"
            }
          }
        }
      }
    },
    "schemas": {
      "RootUIComponentRequest": {
        "description": "The building block of all app component requests.",
        "type": "object",
        "properties": {
          "expires_at": {
            "type": "string",
            "description": "The time (in ISO 8601 date format) when the request should expire.",
            "example": "2019-04-15T01:01:46.055Z"
          },
          "user": {
            "type": "string",
            "description": "The user GID this hook is coming from.",
            "example": "54321"
          },
          "workspace": {
            "type": "string",
            "description": "The workspace GID this hook is coming from.",
            "example": "12345"
          }
        }
      },
      "AttachResourceRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/RootUIComponentRequest"
          },
          {
            "type": "object",
            "description": "The body of an attach request.",
            "properties": {
              "task": {
                "type": "string",
                "description": "The task GID this hook is coming from."
              },
              "attachment": {
                "type": "string",
                "description": "The attachment ID of the URL attachment"
              },
              "query": {
                "type": "string",
                "description": "The user’s input in the lookup text input. This is often a resource URL or resource key, such as `\"CP-1\"` or `\"https://abcde.atlassian.net/browse/CP-1\"`"
              }
            }
          }
        ]
      },
      "AttachedResourceResponse": {
        "description": "The response to a successful lookup request.",
        "type": "object",
        "required": [
          "resource_name",
          "resource_url"
        ],
        "properties": {
          "resource_name": {
            "description": "The name of the attached resource",
            "type": "string",
            "example": "Build the Thing"
          },
          "resource_url": {
            "description": "The URL of the attached resource",
            "type": "string",
            "example": "https://example.atlassian.net/browse/CP-1"
          },
          "error": {
            "description": "The error that should be displayed to the user",
            "type": "string",
            "example": "No resource matched that input"
          }
        }
      },
      "BadRequestResponse": {
        "description": "An error response object indicating a bad request (i.e., a status code of `400`).",
        "type": "object",
        "properties": {
          "error": {
            "description": "The error to display.",
            "type": "string",
            "example": "Illegal or malformed request."
          }
        }
      },
      "ForbiddenResponse": {
        "description": "An error response object indicating a forbidden request (i.e., a status code of `403`).",
        "type": "object",
        "properties": {
          "error": {
            "description": "The error to display.",
            "type": "string",
            "example": "Access forbidden."
          }
        }
      },
      "InternalServerErrorResponse": {
        "description": "An error response object indicating a request that could not be found (i.e., a status code of `500`).",
        "type": "object",
        "properties": {
          "error": {
            "description": "The error to display.",
            "type": "string",
            "example": "Internal server error."
          }
        }
      },
      "NotFoundResponse": {
        "description": "An error response object indicating a request that could not be found (i.e., a status code of `404`).",
        "type": "object",
        "properties": {
          "error": {
            "description": "The error to display.",
            "type": "string",
            "example": "Not found."
          }
        }
      },
      "UnauthorizedResponse": {
        "description": "An error response object indicating a unauthorized request (i.e., a status code of `401`).",
        "type": "object",
        "properties": {
          "error": {
            "description": "The error to display.",
            "type": "string",
            "example": "Authorization required."
          }
        }
      }
    }
  },
  "paths": {
    "/resource_attach_url_path_placeholder": {
      "post": {
        "summary": "Attach resource",
        "description": "_Note: The path is a placeholder. The actual path is determined by the configuration of the app component._\n\nWhen the user attaches a resource URL to a task, Asana will make a signed request to the specified `resource_attach_url` in the app configuration. Information about the attached resource should be included in the response.",
        "tags": [
          "Lookups"
        ],
        "operationId": "attachResource",
        "requestBody": {
          "description": "Request to attach a resource.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AttachResourceRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successfully attached the resource to the given object.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AttachedResourceResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    }
  }
}