Skip to content

Image Uploads

Overview

The KOOB API provides a comprehensive attachment system for managing image uploads across various entities in the platform. Understanding how this system works is crucial to avoid accidentally losing existing images when updating entity attachments.

For detailed information about all endpoints, request/response schemas, and additional details, visit our complete API Reference.

Critical

When updating entity images, the API replaces the entire image collection. Any existing images not included in your request will be deleted. Always include all images you want to keep, not just the ones you're adding or updating.

How Image Management Works

The KOOB API uses a synchronization approach for image management, which means:

  1. Complete Replacement: Each API call replaces the entire image collection for an entity
  2. Automatic Cleanup: Images not included in the request are automatically removed
  3. Smart Operations: The system determines whether to create, update, or delete images based on the provided data

Image Retrieval

Accessing Uploaded Images

Once uploaded, images are accessible through the entity's attachments imageUrl field. The URL points to the image stored in our cloud storage.

json
{
  "attachments": [
    {
      "id": "att-123",
      "displayName": "Hotel Exterior.jpg",
      "imageUrl": "https://storage.googleapis.com/bucket/attachments/Hotel/uuid.jpg",
      "isMainPicture": true
    }
  ]
}

Image Upload Methods

On the entity creation (POST)

When creating new entities with images, you only need to provide the new images:

Example - Creating a hotel with images:

json
{
  "attachments": [
    {
      "displayName": "Hotel Exterior.jpg",
      "imageUrl": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQ...",
      "kind": "primary"
    },
    {
      "displayName": "Lobby View.jpg", 
      "imageUrl": "data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAAB...",
      "kind": "secondary"
    }
  ],
}

On the entity update (PUT/PATCH)

When updating existing entities, you must include all images you want to keep:

Incorrect Approach (Will Delete Existing Images):

json
{
  "attachments": [
    {
      "displayName": "New Room Photo.jpg",
      "imageUrl": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQ..."
    }
  ]
}

This will delete all existing images and keep only the new one.

Correct Approach (Preserves Existing Images):

json
{
  "attachments": [
    {
      "id": "att-123",
      "displayName": "Existing Hotel Exterior.jpg"
    },
    {
      "id": "att-456", 
      "displayName": "Updated Lobby Name.jpg"
    },
    {
      "displayName": "New Room Photo.jpg",
      "imageUrl": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQ..."
    }
  ]
}

Sync Operations Explained

The API automatically determines the operation based on your request data:

1. Create New Images

Trigger: Attachments without an id field

json
{
  "displayName": "New Image.jpg",
  "imageUrl": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQ...",
  "kind": "primary"
}

2. Update Existing Images

Trigger: Attachments with an id field

json
{
  "id": "existing-attachment-123",
  "displayName": "Updated Name.jpg",
  "kind": "secondary"
}

Image Modification

You cannot change the actual image file, only metadata like display name and kind.

If you need to change the image, you must delete the old image and create a new one with the updated file.

3. Delete Images

Trigger: Existing images not included in the request

If entity has images with IDs: att-123, att-456, att-789, and you only send the following:

json
{
  "attachments": [
    {
      "id": "att-123",
      "displayName": "Keep This Image.jpg"
    }
  ]
}

Images att-456 and att-789 will be deleted.

Image Data Formats

Base64 Data URLs (New Uploads)

json
{
  "imageUrl": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQ..."
}

Base64 Format Required

The imageUrl must be a valid Base64 data URL. External URLs are not processed and will be skipped.

Existing Images (Updates Only)

json
{
  "id": "att-123"
  // No imageUrl needed for existing images
}

Supported Image Formats

  • JPEG (.jpg, .jpeg)
  • PNG (.png)
  • GIF (.gif)
  • WebP (.webp)

Image Categories

The API supports different image kinds to categorize images based on their usage:

  • primary: Main entity image
  • secondary: Secondary entity image(s)
  • Custom kinds: Based on specific entity requirements

Custom Kinds

Unless stated otherwise, only primary and secondary kinds are supported for most entities.

These can be specified in the kind field of the attachment object.

Best Practices

1. Always Fetch Current Images Before Updates

bash
# Get current entity images
GET /api/v1/hotels/{hotelId}

# Include all existing images in your update
PATCH /api/v1/hotels/{hotelId}

2. Use Meaningful Display Names

json
{
  "displayName": "Hotel Exterior - Main Entrance.jpg",  // Good
  "displayName": "IMG_001.jpg"                          // Avoid
}

3. Optimize Images Before Upload

  • Compress images to reduce upload time and storage costs
  • Use appropriate resolution for the intended use case
  • Consider using WebP format for better compression

4. Handle Large Image Collections

For entities with many images, consider:

  • Paginating image updates
  • Processing images in batches
  • Implementing client-side preview before upload

Common Pitfalls

❌ Accidentally Deleting All Images

json
{
  "name": "Updated Hotel Name",
  "attachments": []  // This deletes all existing images!
}

For most entities, the attachments or pictures field is optional, but if you send an empty array, it will delete all existing images.

If you don't need to update images, simply omit the attachments field entirely.

❌ Forgetting Existing Images

json
{
  "attachments": [
    {
      "displayName": "Only New Image.jpg",
      "imageUrl": "data:image/jpeg;base64,..."
    }
    // Missing existing images - they will be deleted!
  ]
}

✅ Correct Full Update

json
{
  "attachments": [
    {
      "id": "att-123",
      "displayName": "Existing Image 1.jpg"
    },
    {
      "id": "att-456", 
      "displayName": "Existing Image 2.jpg"
    },
    {
      "displayName": "New Image.jpg",
      "imageUrl": "data:image/jpeg;base64,..."
    }
  ]
}