Code Examples

Real-world integration examples for stock photos and AI generation in popular languages and frameworks

✨ New: All examples now include AI generation support. Add provider=ai&style=photo to any URL for AI-generated images.

JavaScript / TypeScript

Vanilla JavaScript

// Simple image fetch
async function getImage(query, width = 800, height = 600) {
  const url = new URL('/api/image', window.location.origin);
  url.searchParams.set('query', query);
  url.searchParams.set('width', width);
  url.searchParams.set('height', height);
  
  const response = await fetch(url, {
    headers: {
      'X-API-Key': process.env.PLACEWISE_API_KEY // Server-side only!
    }
  });
  
  if (response.status === 302) {
    return response.url; // Followed redirect URL
  }
  
  throw new Error(`Failed to fetch image: ${response.status}`);
}

// Usage
const imageUrl = await getImage('mountains');
document.getElementById('myImage').src = imageUrl;

React with AI Support

import { useState, useEffect } from 'react';

function PlacewiseImage({ 
  query, 
  width = 800, 
  height = 600, 
  alt,
  provider = 'unsplash', // 'unsplash', 'pexels', 'pixabay', or 'ai'
  style = 'photo' // AI only: 'photo', 'minimal', 'dark', 'illustration'
}) {
  const [imageUrl, setImageUrl] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    async function fetchImage() {
      try {
        setLoading(true);
        setError(null);
        
        const params = new URLSearchParams({
          query,
          width: width.toString(),
          height: height.toString(),
          provider
        });
        
        // Add AI-specific parameters
        if (provider === 'ai') {
          params.set('style', style);
        }
        
        const response = await fetch(`/api/image?${params}`);
        
        if (response.status === 302) {
          setImageUrl(response.url);
        } else {
          const error = await response.json();
          throw new Error(error.error);
        }
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    }

    fetchImage();
  }, [query, width, height, provider, style]);

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;
  
  return (
    <img 
      src={imageUrl} 
      alt={alt}
      width={width}
      height={height}
      loading="lazy"
    />
  );
}

// Usage - Stock Photos
function App() {
  return (
    <PlacewiseImage 
      query="sunset beach" 
      width={1200} 
      height={800}
      alt="Beautiful sunset at the beach"
    />
  );
}

// Usage - AI Generated
function AppWithAI() {
  return (
    <>
      <PlacewiseImage 
        query="modern office workspace" 
        width={800}
        height={600}
        provider="ai"
        style="photo"
        alt="AI generated office"
      />
      
      <PlacewiseImage 
        query="minimal coffee cup" 
        width={800}
        height={600}
        provider="ai"
        style="minimal"
        alt="Minimal coffee design"
      />
    </>
  );
}

Next.js (Server Components)

// app/api/proxy-image/route.ts - Secure server-side proxy
import { NextRequest, NextResponse } from 'next/server';

export async function GET(request: NextRequest) {
  const { searchParams } = new URL(request.url);
  const query = searchParams.get('query');
  
  if (!query) {
    return NextResponse.json(
      { error: 'Query parameter required' },
      { status: 400 }
    );
  }
  
  const params = new URLSearchParams({
    query,
    width: searchParams.get('width') || '800',
    height: searchParams.get('height') || '600'
  });
  
  const response = await fetch(
    `${process.env.NEXT_PUBLIC_API_URL}/api/image?${params}`,
    {
      headers: {
        'X-API-Key': process.env.PLACEWISE_API_KEY! // Server-side only
      },
      redirect: 'manual'
    }
  );
  
  if (response.status === 302) {
    const imageUrl = response.headers.get('Location');
    return NextResponse.json({ imageUrl });
  }
  
  return NextResponse.json(
    { error: 'Failed to fetch image' },
    { status: response.status }
  );
}

// components/PlacewiseImage.tsx - Client component
'use client';

import { useEffect, useState } from 'react';

export default function PlacewiseImage({ 
  query, 
  width = 800, 
  height = 600 
}: {
  query: string;
  width?: number;
  height?: number;
}) {
  const [imageUrl, setImageUrl] = useState<string | null>(null);

  useEffect(() => {
    fetch(`/api/proxy-image?query=${encodeURIComponent(query)}&width=${width}&height=${height}`)
      .then(res => res.json())
      .then(data => setImageUrl(data.imageUrl))
      .catch(console.error);
  }, [query, width, height]);

  if (!imageUrl) return <div>Loading...</div>;
  
  return <img src={imageUrl} alt={query} width={width} height={height} />;
}

Python

Using requests

import requests
import os
from urllib.parse import urlencode

def get_image_url(query: str, width: int = 800, height: int = 600) -> str:
    """Fetch image URL from Placewise API."""
    
    params = {
        'query': query,
        'width': width,
        'height': height
    }
    
    headers = {
        'X-API-Key': os.getenv('PLACEWISE_API_KEY')
    }
    
    response = requests.get(
        'https://yourdomain.com/api/image',
        params=params,
        headers=headers,
        allow_redirects=False
    )
    
    if response.status_code == 302:
        return response.headers['Location']
    elif response.status_code == 429:
        retry_after = int(response.headers.get('Retry-After', 60))
        raise Exception(f'Rate limit exceeded. Retry after {retry_after} seconds')
    else:
        error = response.json()
        raise Exception(f"API error: {error.get('error')}")

# Usage
try:
    image_url = get_image_url('mountains', width=1920, height=1080)
    print(f'Image URL: {image_url}')
except Exception as e:
    print(f'Error: {e}')

Flask API Endpoint

from flask import Flask, request, jsonify
import requests
import os

app = Flask(__name__)

@app.route('/api/images/search')
def search_images():
    """Proxy endpoint for Placewise API."""
    
    query = request.args.get('query')
    if not query:
        return jsonify({'error': 'Query parameter required'}), 400
    
    width = request.args.get('width', 800, type=int)
    height = request.args.get('height', 600, type=int)
    
    # Validate dimensions
    if not (100 <= width <= 4000) or not (100 <= height <= 4000):
        return jsonify({'error': 'Invalid dimensions'}), 400
    
    try:
        response = requests.get(
            'https://yourdomain.com/api/image',
            params={'query': query, 'width': width, 'height': height},
            headers={'X-API-Key': os.getenv('PLACEWISE_API_KEY')},
            allow_redirects=False,
            timeout=10
        )
        
        if response.status_code == 302:
            image_url = response.headers['Location']
            return jsonify({
                'imageUrl': image_url,
                'query': query,
                'dimensions': {'width': width, 'height': height}
            })
        elif response.status_code == 429:
            return jsonify({
                'error': 'Rate limit exceeded',
                'retryAfter': int(response.headers.get('Retry-After', 60))
            }), 429
        else:
            error_data = response.json()
            return jsonify(error_data), response.status_code
            
    except requests.Timeout:
        return jsonify({'error': 'Request timeout'}), 504
    except Exception as e:
        return jsonify({'error': str(e)}), 500

if __name__ == '__main__':
    app.run(debug=True)

PHP

cURL Implementation

<?php

class PlacewiseClient {
    private $apiKey;
    private $baseUrl;
    
    public function __construct($apiKey, $baseUrl = 'https://yourdomain.com') {
        $this->apiKey = $apiKey;
        $this->baseUrl = $baseUrl;
    }
    
    public function getImageUrl($query, $width = 800, $height = 600) {
        $params = http_build_query([
            'query' => $query,
            'width' => $width,
            'height' => $height
        ]);
        
        $url = $this->baseUrl . '/api/image?' . $params;
        
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => false,
            CURLOPT_HEADER => true,
            CURLOPT_HTTPHEADER => [
                'X-API-Key: ' . $this->apiKey
            ]
        ]);
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        
        if ($httpCode === 302) {
            // Extract Location header
            preg_match('/Location: (.+)/', $response, $matches);
            return trim($matches[1]);
        }
        
        if ($httpCode === 429) {
            throw new Exception('Rate limit exceeded');
        }
        
        throw new Exception('Failed to fetch image: HTTP ' . $httpCode);
    }
}

// Usage
try {
    $client = new PlacewiseClient(getenv('PLACEWISE_API_KEY'));
    $imageUrl = $client->getImageUrl('mountains', 1920, 1080);
    echo "Image URL: " . $imageUrl . "\n";
} catch (Exception $e) {
    echo "Error: " . $e->getMessage() . "\n";
}

?>

Ruby

Using Net::HTTP

require 'net/http'
require 'uri'
require 'json'

class PlacewiseClient
  def initialize(api_key, base_url = 'https://yourdomain.com')
    @api_key = api_key
    @base_url = base_url
  end

  def get_image_url(query, width: 800, height: 600)
    params = URI.encode_www_form(
      query: query,
      width: width,
      height: height
    )
    
    uri = URI("#{@base_url}/api/image?#{params}")
    
    request = Net::HTTP::Get.new(uri)
    request['X-API-Key'] = @api_key
    
    response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
      http.request(request)
    end
    
    case response.code.to_i
    when 302
      response['Location']
    when 429
      raise "Rate limit exceeded. Retry after #{response['Retry-After']} seconds"
    else
      error = JSON.parse(response.body)
      raise "API error: #{error['error']}"
    end
  end
end

# Usage
begin
  client = PlacewiseClient.new(ENV['PLACEWISE_API_KEY'])
  image_url = client.get_image_url('mountains', width: 1920, height: 1080)
  puts "Image URL: #{image_url}"
rescue => e
  puts "Error: #{e.message}"
end

Go

HTTP Client

package main

import (
    "fmt"
    "io"
    "net/http"
    "net/url"
    "os"
    "strconv"
)

type PlacewiseClient struct {
    APIKey  string
    BaseURL string
}

func NewClient(apiKey string) *PlacewiseClient {
    return &PlacewiseClient{
        APIKey:  apiKey,
        BaseURL: "https://yourdomain.com",
    }
}

func (c *PlacewiseClient) GetImageURL(query string, width, height int) (string, error) {
    params := url.Values{}
    params.Add("query", query)
    params.Add("width", strconv.Itoa(width))
    params.Add("height", strconv.Itoa(height))
    
    reqURL := fmt.Sprintf("%s/api/image?%s", c.BaseURL, params.Encode())
    
    req, err := http.NewRequest("GET", reqURL, nil)
    if err != nil {
        return "", err
    }
    
    req.Header.Set("X-API-Key", c.APIKey)
    
    client := &http.Client{
        CheckRedirect: func(req *http.Request, via []*http.Request) error {
            return http.ErrUseLastResponse
        },
    }
    
    resp, err := client.Do(req)
    if err != nil {
        return "", err
    }
    defer resp.Body.Close()
    
    if resp.StatusCode == 302 {
        location := resp.Header.Get("Location")
        return location, nil
    }
    
    if resp.StatusCode == 429 {
        return "", fmt.Errorf("rate limit exceeded")
    }
    
    body, _ := io.ReadAll(resp.Body)
    return "", fmt.Errorf("API error: %s", string(body))
}

func main() {
    client := NewClient(os.Getenv("PLACEWISE_API_KEY"))
    
    imageURL, err := client.GetImageURL("mountains", 1920, 1080)
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }
    
    fmt.Printf("Image URL: %s\n", imageURL)
}

cURL

Command Line Examples

Get redirect location:

curl -I -H "X-API-Key: pk_live_YOUR_KEY" \
  "https://yourdomain.com/api/image?query=mountains&width=800&height=600"

Download image directly:

curl -L -H "X-API-Key: pk_live_YOUR_KEY" \
  -o image.jpg \
  "https://yourdomain.com/api/image?query=mountains&width=1920&height=1080"

With query parameter authentication:

curl -L -o sunset.jpg \
  "https://yourdomain.com/api/image?query=sunset&width=800&height=600&api_key=pk_live_YOUR_KEY"

Advanced Examples

TypeScript with Retry Logic

interface FetchOptions {
  maxRetries?: number;
  retryDelay?: number;
}

async function fetchImageWithRetry(
  query: string,
  width: number,
  height: number,
  options: FetchOptions = {}
): Promise<string> {
  const { maxRetries = 3, retryDelay = 1000 } = options;
  
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const params = new URLSearchParams({
        query,
        width: width.toString(),
        height: height.toString()
      });
      
      const response = await fetch(`/api/image?${params}`, {
        headers: {
          'X-API-Key': process.env.PLACEWISE_API_KEY!
        },
        redirect: 'manual'
      });
      
      if (response.status === 302) {
        return response.headers.get('Location')!;
      }
      
      if (response.status === 429) {
        const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
        await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
        continue;
      }
      
      if (response.status >= 500) {
        const delay = retryDelay * Math.pow(2, attempt);
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }
      
      const error = await response.json();
      throw new Error(error.error);
      
    } catch (error) {
      if (attempt === maxRetries - 1) throw error;
      await new Promise(resolve => setTimeout(resolve, retryDelay));
    }
  }
  
  throw new Error('Max retries exceeded');
}

Client-Side Caching

class PlacewiseCache {
  private cache = new Map<string, { url: string; timestamp: number }>();
  private ttl = 24 * 60 * 60 * 1000; // 24 hours

  private getCacheKey(query: string, width: number, height: number): string {
    return `${query}:${width}:${height}`;
  }

  async getImage(query: string, width: number, height: number): Promise<string> {
    const key = this.getCacheKey(query, width, height);
    const cached = this.cache.get(key);
    
    // Check if cached and not expired
    if (cached && Date.now() - cached.timestamp < this.ttl) {
      console.log('Cache hit');
      return cached.url;
    }
    
    // Fetch fresh image
    console.log('Cache miss');
    const params = new URLSearchParams({ query, width: width.toString(), height: height.toString() });
    const response = await fetch(`/api/image?${params}`);
    const imageUrl = response.url;
    
    // Cache the result
    this.cache.set(key, {
      url: imageUrl,
      timestamp: Date.now()
    });
    
    return imageUrl;
  }
  
  clear(): void {
    this.cache.clear();
  }
}

// Usage
const imageCache = new PlacewiseCache();
const imageUrl = await imageCache.getImage('mountains', 800, 600);