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

# Get Document Upload URL

> Get a presigned URL to upload an invoice directly to S3 before or after creating a payout.

## Overview

Returns a **presigned PUT URL** so your server can upload an invoice **directly to Yala's private S3 bucket**. Yala does **not** accept file bytes on this endpoint—only metadata (`filename`, `contentType`).

After uploading to S3, use the returned **`documentUrl`** on:

* `POST /initiate` as `supportingDocument`, or
* `PATCH /:id/documents` in the `documents` array

<Note>
  Read [Uploading Supporting Documents](/guides/uploading-supporting-documents) for the full 3-step flow: call Yala, upload to S3, then call Yala again with `documentUrl`.
</Note>

## Upload flow (3 steps)

| Step | Where         | Action                                                             |
| ---- | ------------- | ------------------------------------------------------------------ |
| 1    | **Yala API**  | `POST /documents/upload-url` returns `uploadUrl` and `documentUrl` |
| 2    | **Amazon S3** | `PUT` file bytes to `uploadUrl` (not Yala)                         |
| 3    | **Yala API**  | `POST /initiate` or `PATCH /:id/documents` with `documentUrl`      |

## Request

```http theme={null}
POST /v1/payout-api/payouts/documents/upload-url HTTP/1.1
Host: gateway.staging.useyala.com
Content-Type: application/json
x-api-key: <YOUR_API_KEY>
```

```json theme={null}
{
  "filename": "invoice.pdf",
  "contentType": "application/pdf"
}
```

### Request Fields

| Field         | Type   | Required | Description                                                             |
| ------------- | ------ | -------- | ----------------------------------------------------------------------- |
| `filename`    | string | Yes      | Original filename (basename only, e.g. `invoice.pdf`)                   |
| `contentType` | string | Yes      | MIME type: `application/pdf`, `image/jpeg`, `image/jpg`, or `image/png` |

## Response

```json theme={null}
{
  "documentId": "550e8400-e29b-41d4-a716-446655440000",
  "uploadUrl": "https://yala-payout-api-docs-staging.s3.us-east-1.amazonaws.com/staging/payout-api/.../invoice.pdf?X-Amz-Algorithm=...",
  "documentUrl": "https://yala-payout-api-docs-staging.s3.us-east-1.amazonaws.com/staging/payout-api/<businessId>/<documentId>/invoice.pdf",
  "expiresAt": "2024-01-20T10:15:00.000Z",
  "method": "PUT",
  "headers": {
    "Content-Type": "application/pdf"
  }
}
```

### Response Fields

| Field         | Type              | Description                                                              |
| ------------- | ----------------- | ------------------------------------------------------------------------ |
| `documentId`  | string (UUID)     | Document identifier (embedded in S3 key)                                 |
| `uploadUrl`   | string            | Presigned URL for **one-time PUT** to S3 (\~15 min TTL)                  |
| `documentUrl` | string            | **Stable HTTPS URL** — pass this to initiate/PATCH after upload succeeds |
| `expiresAt`   | string (ISO 8601) | When `uploadUrl` expires                                                 |
| `method`      | string            | Always `PUT`                                                             |
| `headers`     | object            | Headers required on the PUT request (e.g. `Content-Type`)                |

## Upload the file to S3

```bash theme={null}
curl -X PUT "<uploadUrl>" \
  -H "Content-Type: application/pdf" \
  --data-binary @invoice.pdf
```

```javascript theme={null}
const { uploadUrl, documentUrl, headers } = await uploadUrlResponse.json();
const file = await fs.readFile('invoice.pdf');

const putResult = await fetch(uploadUrl, {
  method: 'PUT',
  headers,
  body: file,
});

if (!putResult.ok) {
  throw new Error('S3 upload failed');
}

// Use documentUrl on initiate or PATCH — not uploadUrl
```

For manual testing, use the [Postman collection](/guides/postman-collection) **Upload File to S3** request.

## Error Responses

### 400 Bad Request

Invalid filename or unsupported `contentType`.

### 401 Unauthorized

Invalid or missing API key.

## Related

* [Uploading Supporting Documents](/guides/uploading-supporting-documents)
* [Initiate Payout](/api-reference/endpoint/initiate)
* [Add Supporting Documents](/api-reference/endpoint/add-documents)


## OpenAPI

````yaml POST /v1/payout-api/payouts/documents/upload-url
openapi: 3.0.3
info:
  title: Yala Payout APIs
  description: >-
    Yala Payout API documentation. This comprehensive API suite enables seamless
    integration with our financial services platform, providing secure and
    efficient access to cross-border payment solutions.


    <details>

    <summary><b>✨ Key Features</b></summary>


    - Real-time payment processing

    - Secure wallet management

    - Comprehensive exchange rate calculations

    - Robust transaction monitoring

    </details>


    <details>

    <summary><b>💰 Payment Methods and Fees</b></summary>


    ## USD Payments


    | Destination | Method | Fees | Settlement Time |

    |------------|---------|------|-----------------|

    | United States | Wire | $20 | 1 day |

    | | ACH | $5.00 | 1 to 3 days |

    | China, Hong Kong | China wire/HK FPS | $20 | 24 to 72 hours |

    | Other Countries | Swift | $50 (<$2k)<br>$40 ($2k-$10k)<br>$0 (≥$10k) | 24
    to 72 hours |


    ### EUR Payments


    | Destination | Method | Fees | Settlement Time |

    |------------|---------|------|-----------------|

    | EU Countries | SEPA | $5.00 | < 48 hrs |

    | Other Countries | Swift | $50 (<$2k)<br>$40 ($2k-$10k)<br>$0 (≥$10k) | 24
    to 72 hours |


    ### GBP Payments


    | Destination | Method | Fees | Settlement Time |

    |------------|---------|------|-----------------|

    | United Kingdom | Faster Payments/BACS | $2.00 | < 24 hrs |

    | Other Countries | Swift | $50 (<$2k)<br>$40 ($2k-$10k)<br>$0 (≥$10k) | 24
    to 72 hours |


    ### Other Currencies


    | Currency | Destination | Method | Fees | Settlement Time |

    |----------|------------|---------|------|-----------------|

    | NGN | Nigeria | NIP | N100 | < 24 hrs |

    | CNY | All countries | Swift | $50 (<$2k)<br>$40 ($2k-$10k)<br>$0 (≥$10k) |
    24 to 72 hours |

    | HKD | Hong Kong | FPS | $20 | < 24 hrs |

    | Multiple* | Any Country | Swift | $50 (<$2k)<br>$40 ($2k-$10k)<br>$0
    (≥$10k) | 24 to 72 hours |


    *Includes: GHS, XAF, ZAR, XOF, CAD, KES, UGX, INR

    </details>


    For additional support or integration assistance, please contact our
    developer support team.
  version: 1.0.0
  termsOfService: https://useyala.com/
  contact:
    name: API Support
    email: developers@useyala.com
servers:
  - url: https://gateway.useyala.com
    description: Production server
  - url: https://gateway.staging.useyala.com
    description: Staging (Sandbox) server
security:
  - ApiKeyAuth: []
tags:
  - name: Payouts
    description: Operations related to payouts
  - name: Countries
    description: Operations to fetch supported countries and currency information
  - name: Transactions
    description: Operations to fetch transaction history and details
  - name: Webhooks
    description: Register and manage webhook URLs for payout status notifications
paths:
  /v1/payout-api/payouts/documents/upload-url:
    post:
      tags:
        - Payouts
      summary: Get presigned URL to upload supporting document
      description: >-
        Returns uploadUrl (PUT to S3) and documentUrl (pass to initiate or
        PATCH). Request body is JSON only; file bytes go to S3.
      operationId: createDocumentUploadUrl
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - filename
                - contentType
              properties:
                filename:
                  type: string
                  example: invoice.pdf
                contentType:
                  type: string
                  example: application/pdf
      responses:
        '200':
          description: Presigned upload URL created
        '400':
          description: Validation error
        '401':
          description: Unauthorized
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key

````