Skip to content

Latest commit

 

History

History
 
 

README.md

@pollinations/sdk

Official SDK for pollinations.ai - Generate images, text, audio, and video with one simple package.

npm version License: MIT

Warning

The alpha release line (5.1.0-alpha.x) is unstable and breakage-prone. It ships the in-progress rebuild (model-catalog helper and provider changes) and its API may change between alpha versions without notice. The stable latest line is 5.0.0. Opt into the alpha only deliberately, and pin an exact version.

Installation

Stable (recommended):

npm install @pollinations/sdk

Alpha (in-progress rebuild — pin an exact version):

npm install @pollinations/sdk@alpha
# or pin exactly: npm install @pollinations/sdk@5.1.0-alpha.6

CDN / <script> tag

The SDK also ships a browser IIFE bundle for direct <script> use:

<script src="https://cdn.jsdelivr.net/npm/@pollinations/sdk"></script>
<script>
  const { generateImage, generateText } = Pollinations;
  // ...
</script>

The IIFE bundle exposes only the API client under the global Pollinations. The React subpath (PolliProvider, useAuthState, etc.) is shipped as ESM/CJS only — use a bundler (Vite, webpack, Next.js, etc.) to consume it. There's no IIFE entry for ./react because every React app already has a build step.

Quick Start

First, get your API key at https://enter.pollinations.ai/keys and set it:

export POLLINATIONS_API_KEY=your_api_key

Then:

import { generateImage, generateText } from '@pollinations/sdk';

// Generate an image
const image = await generateImage('a futuristic cityscape');
await image.saveToFile('cityscape.png');

// Generate text
const text = await generateText('explain quantum computing in simple terms');
console.log(text);

Complete Beginner Example

New to coding? Here's a complete file you can copy-paste and run:

// save this as: my-first-ai.mjs
// First run: export POLLINATIONS_API_KEY=your_api_key

import { generateText, generateImage } from '@pollinations/sdk';

async function main() {
  // Generate text
  const poem = await generateText('write a short poem about robots');
  console.log('Generated poem:');
  console.log(poem);

  // Generate an image
  const image = await generateImage('a friendly robot waving hello');
  await image.saveToFile('robot.png');
  console.log('Image saved to robot.png!');
}

main();

Run it with:

export POLLINATIONS_API_KEY=your_api_key
node my-first-ai.mjs

Browser Example

<script type="module">
  import { configure, generateText, generateImage } from 'https://esm.sh/@pollinations/sdk';

  // Set your API key
  configure({ apiKey: 'your_api_key' });

  // Generate text
  const text = await generateText('write a haiku');

  // Generate image
  const image = await generateImage('a cute robot');

  // Display both — build nodes instead of interpolating into innerHTML
  // so model output cannot inject markup or script into the page.
  const p = document.createElement('p');
  p.textContent = text;
  const img = document.createElement('img');
  img.src = image.toDataURL();
  document.body.replaceChildren(p, img);
</script>

API Key

An API key is required. Get one for free at https://enter.pollinations.ai/keys

import { configure } from '@pollinations/sdk';

configure({ apiKey: 'your_api_key' });

Or set the environment variable:

export POLLINATIONS_API_KEY=your_api_key

OAuth device flow (CLI / headless)

For CLI tools, scripts, or any environment without a browser redirect, use the OAuth device flow to let the user approve access without pasting a key:

import { authorizeDevice, configure, userInfo } from '@pollinations/sdk';

const auth = await authorizeDevice();
console.log(`Open ${auth.verificationUri} and enter code: ${auth.userCode}`);

const accessToken = await auth.poll(); // blocks until user approves
configure({ apiKey: accessToken });

const me = await userInfo();
console.log(`Logged in as ${me.name} (${me.preferred_username})`);

authorizeDevice() does NOT require an API key — it's how you get one.

React auth provider

React apps can use the @pollinations/sdk/react subpath for shared login state. The provider only owns the session token and OAuth flow; account data is loaded by opt-in hooks.

import {
  PolliProvider,
  useAccountProfile,
  useAuth,
} from '@pollinations/sdk/react';

function AccountStatus() {
  const { isLoggedIn, login, logout } = useAuth();
  const { data: profile } = useAccountProfile({ enabled: isLoggedIn });

  if (!isLoggedIn) {
    return <button onClick={() => login()}>Log in</button>;
  }

  return (
    <button onClick={logout}>
      Log out{profile?.name ? ` ${profile.name}` : ''}
    </button>
  );
}

export function App() {
  return (
    <PolliProvider appKey="pk_your_publishable_key" permissions={['profile']}>
      <AccountStatus />
    </PolliProvider>
  );
}

Account hooks are intentionally separate from the provider: useAccountProfile, useAccountBalance, useAccountKey, and useAccountKeyUsage return the raw SDK response shapes plus { isLoading, error, refresh }.

SSR / Next.js App Router / RSC

PolliProvider is SSR-safe but is a client component (it uses useState / useEffect and reads from window.localStorage):

  • First paint contract: state starts null on both server and client, so initial HTML always renders as logged-out. No hydration mismatch.

  • Hydration: after mount, the provider reads the session token from storage (default localStorage) and parses any #api_key=…&state=… fragment from an OAuth redirect. No account data is fetched until an account hook is mounted.

  • Next.js App Router: mount the provider inside a client component. Either put it in a file with "use client" at the top, or wrap a small client subtree from a server component:

    // app/providers.tsx
    "use client";
    import { PolliProvider } from "@pollinations/sdk/react";
    export function Providers({ children }: { children: React.ReactNode }) {
      return <PolliProvider appKey="pk_…">{children}</PolliProvider>;
    }
    
    // app/layout.tsx (server component)
    import { Providers } from "./providers";
    export default function RootLayout({ children }) {
      return <html><body><Providers>{children}</Providers></body></html>;
    }
  • React Server Components: useAuth, useAuthState, useAuthActions, and account hooks cannot be called from server components. Any component that reads auth state must be a client component.

  • Custom storage: pass a sync StorageAdapter if the default localStorage doesn't fit. Async backends (IndexedDB, RN AsyncStorage) are not supported — see the storage section below.

Managing API keys

Programmatically create, list, and revoke keys for your account. Useful for BYOP ("bring your own pollen") flows, multi-tenant apps, and automation:

import { listKeys, createKey, revokeKey } from '@pollinations/sdk';

// List all keys on the account
const keys = await listKeys();
keys.forEach(k => console.log(k.name, k.prefix, k.enabled));

// Create a scoped key (the raw value is only shown at creation)
const created = await createKey({
  name: 'my-bot',
  type: 'secret',
  pollenBudget: 1000,
  accountPermissions: ['usage'],
});
console.log('Save now — will not be shown again:', created.key);

// Revoke by id
await revokeKey(created.id);

Without accountPermissions, scoped keys can generate media but cannot read account state (balance, usage).

Image Generation

import { generateImage, imageUrl } from '@pollinations/sdk';

// Generate and save
const image = await generateImage('a robot painting', {
  model: 'zimage',
  width: 1920,
  height: 1080,
});
await image.saveToFile('robot.png');

// Get as base64 or data URL
const base64 = image.toBase64();
const dataUrl = image.toDataURL();

// Just get the URL (no download)
const url = await imageUrl('a sunset');

Options

Defaults are applied by the API; the SDK sends only options you provide.

Option Type Default Description
model string 'zimage' Model to use
width number 1024 Width in pixels
height number 1024 Height in pixels
seed number random Reproducible results
safe boolean false Safety filter
quality string 'medium' 'low', 'medium', 'high', 'hd'
referenceImage string - URL for image-to-image
transparent boolean false Transparent background (PNG)
guidanceScale number - Prompt strictness (1-20)
reasoning boolean | 'fast' | 'balanced' | 'pro' 'balanced' Reasoning mode for nanobanana models. Booleans are accepted for backward compatibility.

Image Editing

import { editImage } from '@pollinations/sdk';

const result = await editImage('Make the sky purple', {
  image: 'https://example.com/photo.jpg',
  model: 'flux',
});
await result.saveToFile('edited.png');

// Multiple source images
const result2 = await editImage('Combine these two scenes', {
  image: ['https://example.com/a.jpg', 'https://example.com/b.jpg'],
});

Image Generation (OpenAI-compatible)

The imageGenerate helper wraps POST /v1/images/generations — useful when you need OpenAI SDK parity (size string, n, response_format) or want multiple images from a single call.

import { imageGenerate } from '@pollinations/sdk';

// Single image with OpenAI-style size string
const img = await imageGenerate('A robot reading a book', {
  size: '1024x1024',
  model: 'flux',
});
await img.saveToFile('robot.png');

// Multiple images in one request
const imgs = await imageGenerate('A robot reading a book', { n: 3 });
imgs.forEach((img, i) => img.saveToFile(`robot-${i}.png`));

For the simpler GET-based endpoint, see generateImage above.

Text Generation

import { generateText, generateTextStream } from '@pollinations/sdk';

// Simple
const text = await generateText('write a poem about coding');

// With options
const story = await generateText('explain gravity', {
  model: 'openai',
  systemPrompt: 'You are a physics teacher',
});

// Streaming
for await (const chunk of generateTextStream('tell me a story')) {
  process.stdout.write(chunk);
}

// Full response with metadata
const result = await generateText('hello', { raw: true });
console.log(result.text);
console.log(result.tokens);      // { input, output, total }
console.log(result.actualModel); // actual model used

Options

Option Type Default Description
model string 'openai' Model to use
systemPrompt string - System prompt
temperature number 1 Creativity (0-2)
maxTokens number - Max output tokens
frequencyPenalty number - Reduce repetition (-2 to 2)
presencePenalty number - Encourage new topics (-2 to 2)
seed number random Reproducible results
json boolean false JSON output mode
private boolean false Keep generation private
raw boolean false Return full response

Chat

import { chat, chatStream, conversation } from '@pollinations/sdk';

// Single message
const response = await chat([
  { role: 'system', content: 'You are a helpful assistant' },
  { role: 'user', content: 'What is 2+2?' }
]);
console.log(response.text);

// Streaming
for await (const chunk of chatStream([{ role: 'user', content: 'Write a poem' }])) {
  process.stdout.write(chunk.choices[0]?.delta?.content || '');
}

// Conversation (auto-manages history)
const convo = conversation({ model: 'openai' });
convo.system('You are a pirate');

const r1 = await convo.say('Hello!');        // "Ahoy, matey!"
const r2 = await convo.say('Where are we?'); // Remembers context

console.log(convo.getHistory()); // Full message history
convo.clear(); // Reset conversation

Video Generation

import { generateVideo } from '@pollinations/sdk';

const video = await generateVideo('a timelapse of clouds', {
  model: 'veo',
  duration: 6,
});
await video.saveToFile('clouds.mp4');

Options

Option Type Default Description
model string 'veo' 'veo', 'seedance', 'wan', etc.
duration number - Duration in seconds (supported range varies by model)
aspectRatio string - e.g. '16:9', '9:16', '1:1'
seed number random Reproducible results
audio boolean false Include audio (wan always has audio)
referenceImage string - URL for image-to-video
safe boolean false Safety filter

Audio (Text-to-Speech & Music)

import { generateAudio } from '@pollinations/sdk';

// Text-to-speech
const speech = await generateAudio('Hello, welcome!', { voice: 'nova' });
await speech.saveToFile('welcome.mp3');

// Music generation
const music = await generateAudio('upbeat jazz piano', {
  model: 'elevenmusic',
  duration: 30,
});
await music.saveToFile('jazz.mp3');

// Get as base64 or data URL
const base64 = speech.toBase64();
const dataUrl = speech.toDataURL();

// Play in browser
const audioEl = new Audio(speech.toDataURL());
audioEl.play();

Options

Option Type Default Description
voice string 'alloy' Voice to use (see voices below)
model string 'elevenlabs' 'elevenlabs', 'elevenmusic'
duration number - Duration in seconds (for music models)
seed number random Reproducible results

Available Voices

alloy, echo, fable, onyx, nova, shimmer, ash, ballad, coral, sage, verse, rachel, domi, bella, elli, charlotte, dorothy, sarah, emily, lily, matilda, adam, antoni, arnold, josh, sam, daniel, charlie, james, fin, callum, liam, george, brian, bill

Vision (Image Input)

import { chat } from '@pollinations/sdk';

const response = await chat([
  {
    role: 'user',
    content: [
      { type: 'text', text: 'What is in this image?' },
      { type: 'image_url', image_url: { url: 'https://example.com/photo.jpg' } }
    ]
  }
]);

List Available Models

import { getTextModels, getImageModels } from '@pollinations/sdk';

const textModels = await getTextModels();
const imageModels = await getImageModels();

console.log(textModels.map(m => m.name));

Media Upload

Uploads use multipart form data, accept up to 100MB of file bytes, and return a public URL. Adding tags publishes the upload to those public tag galleries.

import { upload } from '@pollinations/sdk';

const media = await upload(imageBuffer, {
  name: 'cat.png',
  contentType: 'image/png',
  tags: ['cats', 'gallery'],
});

console.log(media.url);

Error Handling

import { generateImage, PollinationsError } from '@pollinations/sdk';

try {
  const image = await generateImage('test');
} catch (err) {
  if (err instanceof PollinationsError) {
    console.error(err.message);    // Error message
    console.error(err.code);       // Error code (BAD_REQUEST, UNAUTHORIZED, INSUFFICIENT_BALANCE, etc.)
    console.error(err.status);     // HTTP status (400, 401, 402, 403, 500)
    console.error(err.requestId);  // Server request ID — include it in support reports
  }
}

Common error codes: 400 invalid params, 401 missing/invalid key, 402 insufficient balance, 403 permission denied, 500 server error.

Advanced: Client Class

import { Pollinations } from '@pollinations/sdk';

const client = new Pollinations({ apiKey: 'your_key' });

const imageResponse = await client.image('a sunset');
const text = await client.text('hello');
const chatResponse = await client.chat([{ role: 'user', content: 'hi' }]);

TypeScript

Full TypeScript support with exported types:

import type {
  ImageGenerateOptions,
  TextGenerateOptions,
  ChatOptions,
  Message,
  ImageResponseExt,
  ChatResponseExt,
} from '@pollinations/sdk';

API Reference

Function Description
generateImage(prompt, options?) Generate an image
editImage(prompt, options?) Edit image with prompt
imageUrl(prompt, options?) Get image URL
generateText(prompt, options?) Generate text
generateTextStream(prompt, options?) Stream text
chat(messages, options?) Chat completion
chatStream(messages, options?) Stream chat
conversation(options?) Create conversation
generateVideo(prompt, options?) Generate a video
videoUrl(prompt, options?) Get video URL
generateAudio(text, options?) Text-to-speech / music
transcribe(audio, options?) Speech-to-text
upload(data, options?) Upload media, optionally publishing it with tags
getTextModels() List text models
getImageModels() List image models
getModels() List all models
configure({ apiKey }) Set global config

Troubleshooting

"saveToFile is only available in Node.js"

If you're in a browser, use toDataURL() or toBase64() instead:

const image = await generateImage('a cat');
const dataUrl = image.toDataURL();  // Use this for <img src="">
const base64 = image.toBase64();    // Raw base64 string

Request Timeout

Default timeouts: text/chat 5min, images 10min, videos 20min. For custom timeouts:

import { Pollinations } from '@pollinations/sdk';

const client = new Pollinations({
  timeout: 600000,       // 10 minutes for all requests
  textTimeout: 300000,   // 5 minutes for text
  imageTimeout: 600000,  // 10 minutes for images
  videoTimeout: 1200000, // 20 minutes for videos
});

Rate Limiting

Publishable keys (pk_) have rate limits. Use a secret key (sk_) for unlimited requests.

Network Errors

The SDK returns network and API errors directly and does not retry requests automatically. A timed-out generation may still complete and incur usage. Callers can inspect PollinationsError.retryAfter when deciding how to handle rate limits.

Links

License

MIT