Skip to content

Attachments

Return the downloadable attachment URLs (solicitation PDFs, drawings, statements of work, amendments) for one notice. URLs are direct SAM.gov download links you can hand to a browser or HTTP client; we do not proxy them.

Parameters

  • notice_id (path): same 32-character hex rule as /opportunities/{notice_id}. A solicitation number returns the same structured 400 with a hint_url.

No query parameters are accepted.

Response

{
  "notice_id": "002b2fe0c9bd4af9809196504715c3e1",
  "title": "Mobile Subscription Services for U.S. Embassy Singapore",
  "attachment_count": 3,
  "attachments": [
    "https://sam.gov/api/prod/opps/v3/opportunities/resources/files/959fd907efa448b1af181b670c5f704a/download",
    "https://sam.gov/api/prod/opps/v3/opportunities/resources/files/63cb930c9e2d4a89aff94210164cfbc4/download",
    "https://sam.gov/api/prod/opps/v3/opportunities/resources/files/94798000ce104244a06dd0f4ee195285/download"
  ],
  "files": [
    {
      "url": "https://sam.gov/api/prod/opps/v3/opportunities/resources/files/959fd907efa448b1af181b670c5f704a/download",
      "resource_id": "959fd907efa448b1af181b670c5f704a",
      "filename": "19SN1026R0005_Attachment 2_Data Roaming.pdf",
      "size_bytes": 105070,
      "file_type": ".pdf"
    },
    {
      "url": "https://sam.gov/api/prod/opps/v3/opportunities/resources/files/63cb930c9e2d4a89aff94210164cfbc4/download",
      "resource_id": "63cb930c9e2d4a89aff94210164cfbc4",
      "filename": "19SN1026R0005_Attachment 1_C-SCRM Questionnaire.xlsx",
      "size_bytes": 172980,
      "file_type": ".xlsx"
    }
  ]
}
  • attachment_count: length of attachments. Often 0; many notices carry their documents as external links or have no files at all.
  • attachments: array of canonical SAM.gov download URLs. Same data as resource_links_array on the main opportunity record. An empty array ([]) is returned when a notice has none.
  • files: the same attachments as structured objects, in the same order, so you can label a file before downloading it. Each object carries the url (identical to the matching attachments entry), the resource_id (the hex key inside the URL, and the join key into attachment full text via ?content=), and three descriptive fields: filename, size_bytes (integer bytes), and file_type (SAM's type tag, usually the extension such as .pdf, .docx, .xlsx; a few carry a label like Category Attachment or an empty string). Use files when you want to pick the solicitation out of a set without opening each one; use the plain attachments string array when all you need is the URLs.

Metadata can lag on brand-new notices. The descriptive fields are populated by a background pass, so on a notice posted in the last day or two a file may appear in files with filename, size_bytes, and file_type all null while url and resource_id are still present. The URL is never withheld: an unlabelled file is always still downloadable. Coverage is complete within a couple of days of posting.

This is the same data the search filter has_attachments reads, so the two stay consistent: has_attachments=true on search selects notices where this array is non-empty.

Finding notices that have attachments

There is no list endpoint; look them up per notice. Filter search first, then fetch attachments for each id:

# 1) find notices that have files, in your space
"https://govconapi.com/api/v1/opportunities/search?has_attachments=true&naics=541512&limit=50"

# 2) for each result.notice_id:
"https://govconapi.com/api/v1/opportunities/{notice_id}/attachments"

Downloading the files

Each URL is a SAM.gov "front-door" link. When a client follows it, SAM 303-redirects to a short-lived signed S3 URL and the file streams from there. Three practical notes:

  • Use GET with redirect-follow, not HEAD. AWS pre-signed URLs scope the signature to the GET method; a HEAD against the resolved S3 URL returns 403.
  • Do not cache the resolved S3 URL. The signature has a very short expiry. Re-hit the SAM URL each time you need the file.
  • Allow *.s3.amazonaws.com through proxies / firewalls. If a corporate proxy blocks S3, the redirect lands on a host that fails to load.

Errors

  • 400: path is not 32-char hex (e.g. a solicitation number). Structured body with hint_url to the search endpoint, same shape as /opportunities/{notice_id}.
  • 404: well-formed id, no such notice. Body: {"detail": "Opportunity not found"}. A notice that exists but has no files returns 200 with attachment_count: 0, not 404.
  • 429: rate limit exceeded.

Example

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://govconapi.com/api/v1/opportunities/002b2fe0c9bd4af9809196504715c3e1/attachments"

When a file URL returns "BAD_REQUEST: The resource has been deleted". SAM occasionally removes individual files after publication (a contracting officer pulls or replaces them in an amendment). The notice's attachment list still references the URL until the next refresh of our copy, so a previously-working URL can stop working. The error comes from SAM directly, not our endpoint; the same file is unreachable from sam.gov for the same reason. If you suspect a file is missing, re-fetch this endpoint to see if our copy has updated.

Some notices' documents are not on SAM at all. A subset of solicitations (notably DLA / NAVSUP NSN parts buys) reference Technical Data Packages hosted in DoD systems like cFolders or NECO that require JCP (Joint Certification Program) certification. Our endpoint correctly returns attachment_count: 0 in that case; the documents exist but are not in the SAM extract.

Freshness: the array is rebuilt periodically from the source; a brand-new notice may briefly show 0 before its files are picked up, even when SAM already has them.

A REST API and MCP server for U.S. federal procurement data.

Get a free key, emailed instantly, or follow the quickstart.

Found something wrong, missing or confusing on this page?

Press Ctrl + Enter to send a note. Highlight text first and it travels with your note.