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

# Upload Design

> Upload design images for use with generation

# Upload Design

Upload a design image and receive a URL for use with the `/generate` endpoint.

<Info>
  This endpoint is **free** — no tokens required.
</Info>

## Endpoint

```
POST https://garmint.app/api/v1/upload
```

## Request Formats

### Multipart Form Upload

Send the image as `multipart/form-data`:

```bash theme={}
curl -X POST https://garmint.app/api/v1/upload \
  -H "Authorization: Bearer gm_live_xxx" \
  -F "file=@my-design.png"
```

### Base64 JSON Upload

Send base64-encoded image data:

```bash theme={}
curl -X POST https://garmint.app/api/v1/upload \
  -H "Authorization: Bearer gm_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "imageData": "data:image/png;base64,iVBORw0KGgo..."
  }'
```

## Constraints

| Constraint             | Value                 |
| ---------------------- | --------------------- |
| Max file size          | 10 MB                 |
| Allowed formats        | PNG, JPEG, WebP, GIF  |
| Recommended resolution | 2400x3000px or higher |

## Response

<ResponseField name="id" type="string">
  Unique upload identifier.
</ResponseField>

<ResponseField name="url" type="string">
  Public URL of the uploaded image. Use this with `/generate`.
</ResponseField>

<ResponseField name="thumbnailUrl" type="string">
  Smaller thumbnail version.
</ResponseField>

<ResponseField name="dimensions" type="object">
  <Expandable title="properties">
    <ResponseField name="width" type="number">
      Image width in pixels.
    </ResponseField>

    <ResponseField name="height" type="number">
      Image height in pixels.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="fileSize" type="number">
  File size in bytes.
</ResponseField>

<ResponseField name="mimeType" type="string">
  Detected MIME type.
</ResponseField>

## Example

<CodeGroup>
  ```bash cURL (Form) theme={}
  curl -X POST https://garmint.app/api/v1/upload \
    -H "Authorization: Bearer gm_live_xxx" \
    -F "file=@my-design.png"
  ```

  ```typescript TypeScript theme={}
  // Using FormData (browser or Node 18+)
  const formData = new FormData();
  formData.append('file', fileBlob, 'design.png');

  const response = await fetch('https://garmint.app/api/v1/upload', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${GARMINT_API_KEY}`,
    },
    body: formData,
  });

  const upload = await response.json();
  console.log(upload.url); // Use this with /generate
  ```

  ```typescript TypeScript (Base64) theme={}
  // From base64 data URL
  const response = await fetch('https://garmint.app/api/v1/upload', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${GARMINT_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      imageData: 'data:image/png;base64,iVBORw0KGgo...',
    }),
  });

  const upload = await response.json();
  ```

  ```python Python theme={}
  import requests

  # Form upload
  with open('my-design.png', 'rb') as f:
      response = requests.post(
          'https://garmint.app/api/v1/upload',
          headers={'Authorization': f'Bearer {GARMINT_API_KEY}'},
          files={'file': f}
      )

  upload = response.json()
  print(upload['url'])
  ```
</CodeGroup>

## Response Example

```json theme={}
{
  "id": "upl_1703001234_xyz789",
  "url": "https://res.cloudinary.com/garmint/image/upload/v123/api-uploads/xyz789.png",
  "thumbnailUrl": "https://res.cloudinary.com/garmint/image/upload/v123/api-uploads/xyz789.png",
  "dimensions": {
    "width": 2400,
    "height": 3000
  },
  "fileSize": 1548276,
  "mimeType": "image/png"
}
```

## Full Workflow

Upload → Analyze → Generate:

```typescript theme={}
async function createMockup(file: File, garmentId: string) {
  // 1. Upload the design
  const formData = new FormData();
  formData.append('file', file);
  
  const uploadRes = await fetch('https://garmint.app/api/v1/upload', {
    method: 'POST',
    headers: { 'Authorization': `Bearer ${API_KEY}` },
    body: formData,
  });
  const upload = await uploadRes.json();
  
  // 2. Analyze (optional but recommended)
  const analyzeRes = await fetch('https://garmint.app/api/v1/analyze', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ imageUrl: upload.url }),
  });
  const analysis = await analyzeRes.json();
  
  if (analysis.warnings.length > 0) {
    console.warn('Design warnings:', analysis.warnings);
  }
  
  // 3. Generate mockup
  const generateRes = await fetch('https://garmint.app/api/v1/generate', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      designUrl: upload.url,
      garmentId,
      garmentImageUrl: '...', // Get from /garments
      placement: { x: 50, y: 35, scale: 0.8 },
    }),
  });
  
  return generateRes.json();
}
```

## Image Preparation Tips

<AccordionGroup>
  <Accordion title="Use PNG for designs with transparency">
    PNG preserves alpha channels for transparent backgrounds, essential for printing on colored garments.
  </Accordion>

  <Accordion title="High resolution = better prints">
    Upload at 300 DPI or higher. For a 12" wide print, that's at least 3600px wide.
  </Accordion>

  <Accordion title="sRGB color space">
    Ensure images are in sRGB color space for consistent color representation.
  </Accordion>

  <Accordion title="Remove excess transparency">
    Trim transparent borders to get accurate placement calculations.
  </Accordion>
</AccordionGroup>

## Errors

| Code              | Status | Description                        |
| ----------------- | ------ | ---------------------------------- |
| `invalid_request` | 400    | No file provided or invalid format |
| `invalid_request` | 400    | File too large (max 10MB)          |
| `invalid_request` | 400    | Could not read image               |
