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

# Get Bill Download URL

> Issue a temporary download URL for one existing bill file belonging to the current merchant.

Verify that the bill belongs to the current merchant, then issue a temporary download URL for its existing file. The URL is valid for 600 seconds. Download the file directly from OSS using the returned URL.

<Note>
  The download URL is valid for **600 seconds**. This endpoint only issues URLs for existing files; it does not generate, merge, or recalculate bills.
</Note>

## Authentication and Headers

Authenticate with a Bearer API Key and include the signing headers below. GET requests use an empty `requestBody`, so the signature payload is `{timestamp}.{nonce}.`. Compute HMAC-SHA256 with the merchant API Secret and encode the result as lowercase hex. See [Authentication and Signing](/en/api/getting-started#authentication-and-signing).

<ParamField header="Authorization" type="string" required>
  Bearer API Key in the format `Bearer sk_live_xxx`.
</ParamField>

<ParamField header="X-StablePay-Timestamp" type="string" required>
  Unix timestamp in seconds. It must be within 5 minutes of the server time.
</ParamField>

<ParamField header="X-StablePay-Nonce" type="string" required>
  Random string for replay protection, 16–64 characters long. Use a new UUID for each request. Minimum length: 16 characters. Maximum length: 64 characters.
</ParamField>

<ParamField header="X-StablePay-Signature" type="string" required>
  HMAC-SHA256 of `{timestamp}.{nonce}.{requestBody}` using the merchant API Secret, encoded as lowercase hex. For GET requests, `requestBody` is an empty string.
</ParamField>

## Path Parameters

<ParamField path="bill_id" type="string" required>
  Bill ID. Use the string value returned by the List Bills endpoint. Pattern: `^[1-9][0-9]*$`.
</ParamField>

## Success Response

HTTP `200`, `application/json`. Download URL issued successfully.

<ResponseField name="bill_id" type="string" required>
  Bill ID.
</ResponseField>

<ResponseField name="filename" type="string" required>
  Download filename.
</ResponseField>

<ResponseField name="content_type" type="string" required>
  Media type of the file, such as `text/csv`.
</ResponseField>

<ResponseField name="download_url" type="string" required>
  Temporary signed OSS download URL. This URL contains access credentials; do not publish it or store it for long periods. Format: `uri`.
</ResponseField>

<ResponseField name="expires_in" type="integer" required>
  Remaining validity of the download URL, in seconds. Value: `600`.
</ResponseField>

## Error Responses

| HTTP Status | Description |
| - | - |
| 400 | Invalid bill ID or request parameters. |
| 401 | Authentication failed. |
| 404 | The bill does not exist, belongs to another merchant, or its file does not exist. |
| 410 | The historical bill file does not meet the current merchant isolation rules and cannot be downloaded. |
| 422 | The bill record exists, but its file is not yet available. |
| 503 | BillProd, OSS, or another dependent service is temporarily unavailable. |

### Service Error Structure

<ResponseField name="error" type="object" required>
  <Expandable title="Fields">
    <ResponseField name="code" type="string" required>
      Error code, such as `invalid_parameter`, `resource_not_found`, `historical_report_unavailable`, `report_incomplete`, or `service_unavailable`.
    </ResponseField>

    <ResponseField name="message" type="string" required>
      Error message.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="request_id" type="string" required>
  Request ID.
</ResponseField>

<ResponseField name="timestamp" type="integer" required>
  Time of the error, as a Unix timestamp in seconds. Format: `int64`.
</ResponseField>

### Gateway Authentication Error Structure

Before a request reaches PaymentProd, the API gateway may return an HTTP `401` response with the following structure.

<ResponseField name="status" type="string" required>
  Value: `error`.
</ResponseField>

<ResponseField name="error" type="string" required>
  Reason for the authentication failure.
</ResponseField>

Use the string `bill_id` returned by [List Bills](/en/api/bills/list). The download URL contains access credentials; do not publish it or store it for long periods.

<RequestExample>
  ```bash cURL theme={"system"}
  TIMESTAMP=$(date +%s)
  NONCE=$(uuidgen)
  SIGNATURE=$(printf '%s' "${TIMESTAMP}.${NONCE}." | openssl dgst -sha256 -hmac "${SECRET_KEY}" | awk '{print $NF}')

  curl --get 'https://api.stablepay.co/api/v1/bills/1234567890/download_url' \
    -H "Authorization: Bearer ${API_KEY}" \
    -H "X-StablePay-Timestamp: ${TIMESTAMP}" \
    -H "X-StablePay-Nonce: ${NONCE}" \
    -H "X-StablePay-Signature: ${SIGNATURE}"
  ```
</RequestExample>

<ResponseExample>
  ```json 200 (Example) theme={"system"}
  {
    "bill_id": "1234567890",
    "filename": "payment-2026-09-01.csv",
    "content_type": "text/csv",
    "download_url": "https://example.com/bills/payment-2026-09-01.csv?signature=example",
    "expires_in": 600
  }
  ```

  ```json Service Error (Example) theme={"system"}
  {
    "error": {
      "code": "invalid_parameter",
      "message": "Invalid request parameters"
    },
    "request_id": "req_example",
    "timestamp": 1790812800
  }
  ```

  ```json Gateway Authentication Error (Example) theme={"system"}
  {
    "status": "error",
    "error": "Authentication failed"
  }
  ```
</ResponseExample>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.