Compare commits
2 Commits
main
...
docs-secti
| Author | SHA1 | Date |
|---|---|---|
|
|
8ee4a8b108 | |
|
|
a508ff9527 |
|
|
@ -0,0 +1,448 @@
|
|||
'use client';
|
||||
|
||||
/**
|
||||
* API Reference: Advanced Generation
|
||||
*
|
||||
* Based on docs/api/image-generation-advanced.md
|
||||
*/
|
||||
|
||||
import { TipBox } from '@/components/docs/shared/TipBox';
|
||||
import { Table } from '@/components/docs/shared/Table';
|
||||
import { CodeBlock } from '@/components/docs/shared/CodeBlock';
|
||||
import { DocPage } from '@/components/docs/layout/DocPage';
|
||||
import {
|
||||
Hero,
|
||||
SectionHeader,
|
||||
InlineCode,
|
||||
EndpointCard,
|
||||
} from '@/components/docs/blocks';
|
||||
|
||||
const tocItems = [
|
||||
{ id: 'overview', text: 'Overview', level: 2 },
|
||||
{ id: 'reference-images', text: 'Reference Images', level: 2 },
|
||||
{ id: 'alias-assignment', text: 'Alias Assignment', level: 2 },
|
||||
{ id: 'alias-resolution', text: '3-Tier Alias Resolution', level: 2 },
|
||||
{ id: 'flows', text: 'Generation Flows', level: 2 },
|
||||
{ id: 'regeneration', text: 'Regeneration', level: 2 },
|
||||
{ id: 'flow-management', text: 'Flow Management', level: 2 },
|
||||
{ id: 'next-steps', text: 'Next Steps', level: 2 },
|
||||
];
|
||||
|
||||
const referenceLimits = [
|
||||
['Max references', '3 images'],
|
||||
['Max file size', '5MB per image'],
|
||||
['Supported formats', 'PNG, JPEG, WebP'],
|
||||
];
|
||||
|
||||
const aliasFormat = [
|
||||
['Prefix', 'Must start with @'],
|
||||
['Characters', 'Alphanumeric, underscore, hyphen'],
|
||||
['Pattern', '@[a-zA-Z0-9_-]+'],
|
||||
['Max length', '50 characters'],
|
||||
['Examples', '@logo, @hero-bg, @image_1'],
|
||||
];
|
||||
|
||||
const technicalAliases = [
|
||||
['@last', 'Most recently generated image in flow'],
|
||||
['@first', 'First generated image in flow'],
|
||||
['@upload', 'Most recently uploaded image in flow'],
|
||||
];
|
||||
|
||||
const flowIdBehavior = [
|
||||
['undefined (not provided)', 'Auto-generate pendingFlowId, lazy creation'],
|
||||
['null (explicitly null)', 'No flow association'],
|
||||
['"uuid-string"', 'Use provided ID, create flow if doesn\'t exist'],
|
||||
];
|
||||
|
||||
const regenerationTriggers = [
|
||||
['prompt', 'Yes'],
|
||||
['aspectRatio', 'Yes'],
|
||||
['flowId', 'No (metadata only)'],
|
||||
['meta', 'No (metadata only)'],
|
||||
];
|
||||
|
||||
export default function AdvancedGenerationPage() {
|
||||
return (
|
||||
<DocPage
|
||||
breadcrumbItems={[
|
||||
{ label: 'Documentation', href: '/docs' },
|
||||
{ label: 'API Reference', href: '/docs/api' },
|
||||
{ label: 'Advanced Generation' },
|
||||
]}
|
||||
tocItems={tocItems}
|
||||
nextSteps={{
|
||||
links: [
|
||||
{
|
||||
href: '/docs/api/live',
|
||||
title: 'Live URLs',
|
||||
description: 'Generate images on-demand via URL parameters.',
|
||||
accent: 'primary',
|
||||
},
|
||||
{
|
||||
href: '/docs/api/upload',
|
||||
title: 'Image Upload',
|
||||
description: 'Upload reference images for generation workflows.',
|
||||
accent: 'secondary',
|
||||
},
|
||||
],
|
||||
}}
|
||||
>
|
||||
{/* Hero Section */}
|
||||
<Hero
|
||||
title="Advanced Generation"
|
||||
subtitle="Reference images, aliases, flows, and regeneration for complex workflows."
|
||||
/>
|
||||
|
||||
{/* Overview */}
|
||||
<section id="overview" className="mb-12">
|
||||
<SectionHeader level={2} id="overview">
|
||||
Overview
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
The Advanced Generation API extends basic generation with powerful features for
|
||||
production workflows: reference images for style guidance, aliases for human-readable
|
||||
identifiers, and flows for organizing related generations.
|
||||
</p>
|
||||
<TipBox variant="compact" type="info">
|
||||
<strong>Tip:</strong> For basic generation without these features, see the{' '}
|
||||
<a href="/docs/api/generate" className="text-purple-400 hover:underline">Image Generation</a> page.
|
||||
</TipBox>
|
||||
</section>
|
||||
|
||||
{/* Reference Images */}
|
||||
<section id="reference-images" className="mb-12">
|
||||
<SectionHeader level={2} id="reference-images">
|
||||
Reference Images
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
Use existing images as style or content references for generation.
|
||||
</p>
|
||||
|
||||
<SectionHeader level={3} id="using-references" className="mb-4">
|
||||
Using References
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
Add <InlineCode>referenceImages</InlineCode> array to your generation request:
|
||||
</p>
|
||||
|
||||
<CodeBlock
|
||||
code={`{
|
||||
"prompt": "A product photo with the logo in the corner",
|
||||
"referenceImages": ["@brand-logo", "@product-style"]
|
||||
}`}
|
||||
language="json"
|
||||
filename="Request with References"
|
||||
/>
|
||||
|
||||
<p className="text-gray-300 leading-relaxed mt-6 mb-4">
|
||||
References can be:
|
||||
</p>
|
||||
<ul className="list-disc list-inside text-gray-300 space-y-2 mb-6">
|
||||
<li><strong>Project aliases:</strong> <InlineCode>@logo</InlineCode>, <InlineCode>@brand-style</InlineCode></li>
|
||||
<li><strong>Flow aliases:</strong> <InlineCode>@hero</InlineCode> (with flowId context)</li>
|
||||
<li><strong>Technical aliases:</strong> <InlineCode>@last</InlineCode>, <InlineCode>@first</InlineCode>, <InlineCode>@upload</InlineCode></li>
|
||||
<li><strong>Image UUIDs:</strong> <InlineCode>550e8400-e29b-41d4-a716-446655440000</InlineCode></li>
|
||||
</ul>
|
||||
|
||||
<SectionHeader level={3} id="auto-detection" className="mb-4">
|
||||
Auto-Detection from Prompt
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
Aliases in the prompt are automatically detected and used as references:
|
||||
</p>
|
||||
|
||||
<CodeBlock
|
||||
code={`{
|
||||
"prompt": "Create a banner using @brand-logo with blue background"
|
||||
}
|
||||
// @brand-logo is auto-detected and added to referenceImages`}
|
||||
language="json"
|
||||
filename="Auto-Detection"
|
||||
/>
|
||||
|
||||
<SectionHeader level={3} id="reference-limits" className="mt-6 mb-4">
|
||||
Reference Limits
|
||||
</SectionHeader>
|
||||
<Table
|
||||
headers={['Constraint', 'Limit']}
|
||||
rows={referenceLimits.map(([constraint, limit]) => [
|
||||
constraint,
|
||||
<InlineCode key="limit">{limit}</InlineCode>,
|
||||
])}
|
||||
/>
|
||||
</section>
|
||||
|
||||
{/* Alias Assignment */}
|
||||
<section id="alias-assignment" className="mb-12">
|
||||
<SectionHeader level={2} id="alias-assignment">
|
||||
Alias Assignment
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
Assign aliases to generated images for easy referencing.
|
||||
</p>
|
||||
|
||||
<SectionHeader level={3} id="project-alias" className="mb-4">
|
||||
Project-Scoped Alias
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
Use <InlineCode>alias</InlineCode> parameter to assign a project-wide alias:
|
||||
</p>
|
||||
|
||||
<CodeBlock
|
||||
code={`{
|
||||
"prompt": "A hero banner image",
|
||||
"alias": "@hero-banner"
|
||||
}`}
|
||||
language="json"
|
||||
filename="Project Alias"
|
||||
/>
|
||||
|
||||
<SectionHeader level={3} id="flow-alias" className="mt-6 mb-4">
|
||||
Flow-Scoped Alias
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
Use <InlineCode>flowAlias</InlineCode> parameter to assign a flow-specific alias:
|
||||
</p>
|
||||
|
||||
<CodeBlock
|
||||
code={`{
|
||||
"prompt": "A hero image variation",
|
||||
"flowId": "550e8400-...",
|
||||
"flowAlias": "@best"
|
||||
}`}
|
||||
language="json"
|
||||
filename="Flow Alias"
|
||||
/>
|
||||
|
||||
<SectionHeader level={3} id="alias-format" className="mt-6 mb-4">
|
||||
Alias Format
|
||||
</SectionHeader>
|
||||
<Table
|
||||
headers={['Rule', 'Description']}
|
||||
rows={aliasFormat.map(([rule, description]) => [
|
||||
rule,
|
||||
<InlineCode key="desc">{description}</InlineCode>,
|
||||
])}
|
||||
/>
|
||||
|
||||
<div className="mt-6">
|
||||
<TipBox variant="compact" type="warning">
|
||||
<strong>Override Behavior:</strong> When assigning an existing alias, the new image gets
|
||||
the alias and the old image loses it. The old image is not deleted, just unlinked.
|
||||
</TipBox>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* 3-Tier Alias Resolution */}
|
||||
<section id="alias-resolution" className="mb-12">
|
||||
<SectionHeader level={2} id="alias-resolution">
|
||||
3-Tier Alias Resolution
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
Aliases are resolved in order of precedence:
|
||||
</p>
|
||||
|
||||
<SectionHeader level={3} id="tier-1" className="mb-4">
|
||||
1. Technical Aliases (Highest Priority)
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
Computed on-the-fly, require flow context:
|
||||
</p>
|
||||
<Table
|
||||
headers={['Alias', 'Returns']}
|
||||
rows={technicalAliases.map(([alias, returns]) => [
|
||||
<InlineCode key="alias">{alias}</InlineCode>,
|
||||
returns,
|
||||
])}
|
||||
/>
|
||||
|
||||
<SectionHeader level={3} id="tier-2" className="mt-6 mb-4">
|
||||
2. Flow Aliases
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
Stored in flow's <InlineCode>aliases</InlineCode> JSONB field.
|
||||
Different flows can have the same alias pointing to different images.
|
||||
</p>
|
||||
|
||||
<SectionHeader level={3} id="tier-3" className="mt-6 mb-4">
|
||||
3. Project Aliases (Lowest Priority)
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
Stored in image's <InlineCode>alias</InlineCode> column.
|
||||
Global across the project, unique per project.
|
||||
</p>
|
||||
|
||||
<div className="mt-6">
|
||||
<CodeBlock
|
||||
code={`// Request with flowId
|
||||
GET /api/v1/images/@hero?flowId=abc-123
|
||||
|
||||
// Resolution order:
|
||||
// 1. Is "@hero" a technical alias? No
|
||||
// 2. Does flow abc-123 have "@hero" in aliases? Check flows.aliases JSONB
|
||||
// 3. Does any image have alias = "@hero"? Check images.alias column`}
|
||||
language="bash"
|
||||
filename="Resolution Example"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Generation Flows */}
|
||||
<section id="flows" className="mb-12">
|
||||
<SectionHeader level={2} id="flows">
|
||||
Generation Flows
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
Flows organize related generations into chains.
|
||||
</p>
|
||||
|
||||
<SectionHeader level={3} id="lazy-creation" className="mb-4">
|
||||
Lazy Flow Creation
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
When <InlineCode>flowId</InlineCode> is not provided, a pending flow ID is generated.
|
||||
The flow record is created when a second generation uses the same flowId or a flowAlias is assigned.
|
||||
</p>
|
||||
|
||||
<SectionHeader level={3} id="eager-creation" className="mt-6 mb-4">
|
||||
Eager Flow Creation
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
When <InlineCode>flowAlias</InlineCode> is provided, the flow is created immediately.
|
||||
</p>
|
||||
|
||||
<SectionHeader level={3} id="flowid-behavior" className="mt-6 mb-4">
|
||||
flowId Behavior
|
||||
</SectionHeader>
|
||||
<Table
|
||||
headers={['Value', 'Behavior']}
|
||||
rows={flowIdBehavior.map(([value, behavior]) => [
|
||||
<InlineCode key="value">{value}</InlineCode>,
|
||||
behavior,
|
||||
])}
|
||||
/>
|
||||
</section>
|
||||
|
||||
{/* Regeneration */}
|
||||
<section id="regeneration" className="mb-12">
|
||||
<SectionHeader level={2} id="regeneration">
|
||||
Regeneration
|
||||
</SectionHeader>
|
||||
|
||||
<SectionHeader level={3} id="regenerate-endpoint" className="mb-4">
|
||||
Regenerate Generation
|
||||
</SectionHeader>
|
||||
<EndpointCard
|
||||
method="POST"
|
||||
endpoint="/api/v1/generations/:id/regenerate"
|
||||
baseUrl="https://api.banatie.app"
|
||||
/>
|
||||
<p className="text-gray-300 leading-relaxed mt-4 mb-4">
|
||||
Recreate an image using the exact same parameters. The output image ID and URL are preserved.
|
||||
</p>
|
||||
|
||||
<SectionHeader level={3} id="update-regenerate" className="mt-6 mb-4">
|
||||
Update and Regenerate
|
||||
</SectionHeader>
|
||||
<EndpointCard
|
||||
method="PUT"
|
||||
endpoint="/api/v1/generations/:id"
|
||||
baseUrl="https://api.banatie.app"
|
||||
/>
|
||||
<p className="text-gray-300 leading-relaxed mt-4 mb-4">
|
||||
Modify parameters with smart regeneration:
|
||||
</p>
|
||||
|
||||
<Table
|
||||
headers={['Changed Field', 'Triggers Regeneration']}
|
||||
rows={regenerationTriggers.map(([field, triggers]) => [
|
||||
<InlineCode key="field">{field}</InlineCode>,
|
||||
<span key="triggers" className={triggers === 'Yes' ? 'text-green-400' : 'text-gray-500'}>{triggers}</span>,
|
||||
])}
|
||||
/>
|
||||
|
||||
<SectionHeader level={3} id="flow-regenerate" className="mt-6 mb-4">
|
||||
Flow Regenerate
|
||||
</SectionHeader>
|
||||
<EndpointCard
|
||||
method="POST"
|
||||
endpoint="/api/v1/flows/:id/regenerate"
|
||||
baseUrl="https://api.banatie.app"
|
||||
/>
|
||||
<p className="text-gray-300 leading-relaxed mt-4">
|
||||
Regenerate the most recent generation in a flow.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{/* Flow Management */}
|
||||
<section id="flow-management" className="mb-12">
|
||||
<SectionHeader level={2} id="flow-management">
|
||||
Flow Management
|
||||
</SectionHeader>
|
||||
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<EndpointCard
|
||||
method="GET"
|
||||
endpoint="/api/v1/flows"
|
||||
baseUrl="https://api.banatie.app"
|
||||
/>
|
||||
<p className="text-gray-400 text-sm mt-2">List all flows with pagination</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<EndpointCard
|
||||
method="GET"
|
||||
endpoint="/api/v1/flows/:id"
|
||||
baseUrl="https://api.banatie.app"
|
||||
/>
|
||||
<p className="text-gray-400 text-sm mt-2">Get flow with computed counts and aliases</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<EndpointCard
|
||||
method="GET"
|
||||
endpoint="/api/v1/flows/:id/generations"
|
||||
baseUrl="https://api.banatie.app"
|
||||
/>
|
||||
<p className="text-gray-400 text-sm mt-2">List all generations in the flow</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<EndpointCard
|
||||
method="GET"
|
||||
endpoint="/api/v1/flows/:id/images"
|
||||
baseUrl="https://api.banatie.app"
|
||||
/>
|
||||
<p className="text-gray-400 text-sm mt-2">List all images in the flow (generated and uploaded)</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<EndpointCard
|
||||
method="PUT"
|
||||
endpoint="/api/v1/flows/:id/aliases"
|
||||
baseUrl="https://api.banatie.app"
|
||||
/>
|
||||
<p className="text-gray-400 text-sm mt-2">Update flow aliases (merges with existing)</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<EndpointCard
|
||||
method="DELETE"
|
||||
endpoint="/api/v1/flows/:id"
|
||||
baseUrl="https://api.banatie.app"
|
||||
/>
|
||||
<p className="text-gray-400 text-sm mt-2">Delete flow with cascade behavior</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-6">
|
||||
<TipBox variant="prominent" type="warning">
|
||||
<strong>Cascade Delete:</strong> Deleting a flow hard-deletes all generations and images
|
||||
without project aliases. Images with project aliases are kept but unlinked from the flow.
|
||||
</TipBox>
|
||||
</div>
|
||||
</section>
|
||||
</DocPage>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,352 @@
|
|||
'use client';
|
||||
|
||||
/**
|
||||
* API Reference: Image Generation
|
||||
*
|
||||
* Based on docs/api/image-generation.md
|
||||
*/
|
||||
|
||||
import { TipBox } from '@/components/docs/shared/TipBox';
|
||||
import { Table } from '@/components/docs/shared/Table';
|
||||
import { CodeBlock } from '@/components/docs/shared/CodeBlock';
|
||||
import { DocPage } from '@/components/docs/layout/DocPage';
|
||||
import { InteractiveAPIWidget } from '@/components/docs/blocks/InteractiveAPIWidget';
|
||||
import {
|
||||
Hero,
|
||||
SectionHeader,
|
||||
InlineCode,
|
||||
EndpointCard,
|
||||
} from '@/components/docs/blocks';
|
||||
|
||||
const tocItems = [
|
||||
{ id: 'overview', text: 'Overview', level: 2 },
|
||||
{ id: 'endpoint', text: 'Create Generation', level: 2 },
|
||||
{ id: 'parameters', text: 'Parameters', level: 2 },
|
||||
{ id: 'aspect-ratios', text: 'Aspect Ratios', level: 2 },
|
||||
{ id: 'prompt-enhancement', text: 'Prompt Enhancement', level: 2 },
|
||||
{ id: 'generation-status', text: 'Generation Status', level: 2 },
|
||||
{ id: 'response', text: 'Response Format', level: 2 },
|
||||
{ id: 'error-codes', text: 'Error Codes', level: 2 },
|
||||
{ id: 'interactive', text: 'Try It Live', level: 2 },
|
||||
{ id: 'next-steps', text: 'Next Steps', level: 2 },
|
||||
];
|
||||
|
||||
const parameters = [
|
||||
{ name: 'prompt', type: 'string', required: true, description: 'Text description of the image to generate' },
|
||||
{ name: 'aspectRatio', type: 'string', required: false, default: '"1:1"', description: 'Image aspect ratio (1:1, 16:9, 9:16, 3:2, 21:9)' },
|
||||
{ name: 'autoEnhance', type: 'boolean', required: false, default: 'true', description: 'Enable AI prompt enhancement for better results' },
|
||||
{ name: 'meta', type: 'object', required: false, default: '{}', description: 'Custom metadata to store with generation' },
|
||||
];
|
||||
|
||||
const aspectRatios = [
|
||||
['1:1', 'Square images, social media posts, profile pictures'],
|
||||
['16:9', 'Landscape, hero banners, video thumbnails'],
|
||||
['9:16', 'Portrait, mobile screens, stories'],
|
||||
['3:2', 'Photography standard, print'],
|
||||
['21:9', 'Ultra-wide banners, cinematic'],
|
||||
];
|
||||
|
||||
const statuses = [
|
||||
['pending', 'Generation created, waiting to start'],
|
||||
['processing', 'AI is generating the image'],
|
||||
['success', 'Image generated successfully'],
|
||||
['failed', 'Generation failed (see errorMessage)'],
|
||||
];
|
||||
|
||||
const errorCodes = [
|
||||
['400', 'VALIDATION_ERROR', 'Invalid parameters in the request body'],
|
||||
['401', 'UNAUTHORIZED', 'Missing or invalid API key in X-API-Key header'],
|
||||
['404', 'GENERATION_NOT_FOUND', 'Generation does not exist'],
|
||||
['429', 'RATE_LIMIT_EXCEEDED', 'Too many requests (100/hour limit)'],
|
||||
['500', 'GENERATION_FAILED', 'AI generation failed'],
|
||||
];
|
||||
|
||||
export default function ImageGenerationPage() {
|
||||
return (
|
||||
<DocPage
|
||||
breadcrumbItems={[
|
||||
{ label: 'Documentation', href: '/docs' },
|
||||
{ label: 'API Reference', href: '/docs/api' },
|
||||
{ label: 'Image Generation' },
|
||||
]}
|
||||
tocItems={tocItems}
|
||||
nextSteps={{
|
||||
links: [
|
||||
{
|
||||
href: '/docs/api/advanced',
|
||||
title: 'Advanced Generation',
|
||||
description: 'Learn about references, aliases, and generation flows.',
|
||||
accent: 'primary',
|
||||
},
|
||||
{
|
||||
href: '/docs/api/upload',
|
||||
title: 'Image Upload',
|
||||
description: 'Upload reference images for image-to-image generation.',
|
||||
accent: 'secondary',
|
||||
},
|
||||
],
|
||||
}}
|
||||
>
|
||||
{/* Hero Section */}
|
||||
<Hero
|
||||
title="Image Generation"
|
||||
subtitle="Generate high-quality AI images from text prompts with automatic enhancement."
|
||||
/>
|
||||
|
||||
{/* Overview */}
|
||||
<section id="overview" className="mb-12">
|
||||
<SectionHeader level={2} id="overview">
|
||||
Overview
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
The Image Generation API allows you to create AI-generated images from natural language descriptions.
|
||||
Powered by advanced AI models, it produces high-quality images optimized for your specified requirements.
|
||||
</p>
|
||||
<TipBox variant="compact" type="info">
|
||||
<strong>Tip:</strong> Enable <InlineCode>autoEnhance</InlineCode> (on by default)
|
||||
to let AI improve your prompts for better image quality.
|
||||
</TipBox>
|
||||
</section>
|
||||
|
||||
{/* Endpoint */}
|
||||
<section id="endpoint" className="mb-12">
|
||||
<SectionHeader level={2} id="endpoint">
|
||||
Create Generation
|
||||
</SectionHeader>
|
||||
<EndpointCard
|
||||
method="POST"
|
||||
endpoint="/api/v1/generations"
|
||||
baseUrl="https://api.banatie.app"
|
||||
/>
|
||||
<p className="text-gray-400 text-sm mt-4">
|
||||
Requires <InlineCode>X-API-Key</InlineCode> header with your Project Key.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{/* Parameters */}
|
||||
<section id="parameters" className="mb-12">
|
||||
<SectionHeader level={2} id="parameters" className="mb-6">
|
||||
Parameters
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-6">
|
||||
All parameters should be sent in the request body as JSON.
|
||||
</p>
|
||||
|
||||
<Table
|
||||
headers={['Parameter', 'Type', 'Required', 'Default', 'Description']}
|
||||
rows={parameters.map((param) => [
|
||||
<InlineCode key="name">{param.name}</InlineCode>,
|
||||
<span key="type" className="text-cyan-400">{param.type}</span>,
|
||||
<span key="required" className={param.required ? 'text-green-400' : 'text-gray-500'}>
|
||||
{param.required ? 'Yes' : 'No'}
|
||||
</span>,
|
||||
param.default ? <InlineCode key="default">{param.default}</InlineCode> : <span className="text-gray-500">-</span>,
|
||||
param.description,
|
||||
])}
|
||||
/>
|
||||
|
||||
<div className="mt-6">
|
||||
<CodeBlock
|
||||
code={`{
|
||||
"prompt": "a red sports car on a mountain road",
|
||||
"aspectRatio": "16:9",
|
||||
"autoEnhance": true
|
||||
}`}
|
||||
language="json"
|
||||
filename="Example Request"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Aspect Ratios */}
|
||||
<section id="aspect-ratios" className="mb-12">
|
||||
<SectionHeader level={2} id="aspect-ratios" className="mb-6">
|
||||
Aspect Ratios
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-6">
|
||||
Supported aspect ratios for image generation:
|
||||
</p>
|
||||
|
||||
<Table
|
||||
headers={['Aspect Ratio', 'Use Case']}
|
||||
rows={aspectRatios.map(([ratio, useCase]) => [
|
||||
<InlineCode key="ratio">{ratio}</InlineCode>,
|
||||
useCase,
|
||||
])}
|
||||
/>
|
||||
</section>
|
||||
|
||||
{/* Prompt Enhancement */}
|
||||
<section id="prompt-enhancement" className="mb-12">
|
||||
<SectionHeader level={2} id="prompt-enhancement" className="mb-6">
|
||||
Prompt Enhancement
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
By default, prompts are automatically enhanced by AI to produce better results.
|
||||
</p>
|
||||
|
||||
<SectionHeader level={3} id="how-it-works" className="mb-4">
|
||||
How It Works
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
When <InlineCode>autoEnhance: true</InlineCode> (default):
|
||||
</p>
|
||||
<ul className="list-disc list-inside text-gray-300 space-y-2 mb-6">
|
||||
<li>Your original prompt is preserved in <InlineCode>originalPrompt</InlineCode></li>
|
||||
<li>AI enhances it with style details, lighting, and composition</li>
|
||||
<li>The enhanced version is stored in <InlineCode>prompt</InlineCode> and used for generation</li>
|
||||
</ul>
|
||||
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
When <InlineCode>autoEnhance: false</InlineCode>:
|
||||
</p>
|
||||
<ul className="list-disc list-inside text-gray-300 space-y-2 mb-6">
|
||||
<li>Both <InlineCode>prompt</InlineCode> and <InlineCode>originalPrompt</InlineCode> contain your original text</li>
|
||||
<li>No AI enhancement is applied</li>
|
||||
</ul>
|
||||
|
||||
<TipBox variant="prominent" type="info">
|
||||
<strong>Enhancement Templates (Roadmap):</strong> Template selection for enhancement styles
|
||||
(photorealistic, illustration, minimalist, etc.) is planned for a future release.
|
||||
Currently all enhanced prompts use the default general style.
|
||||
</TipBox>
|
||||
|
||||
<div className="mt-6">
|
||||
<CodeBlock
|
||||
code={`// Request
|
||||
{
|
||||
"prompt": "a cat",
|
||||
"autoEnhance": true
|
||||
}
|
||||
|
||||
// Response
|
||||
{
|
||||
"prompt": "A photorealistic close-up portrait of a domestic cat with soft fur, captured with an 85mm lens...",
|
||||
"originalPrompt": "a cat",
|
||||
"autoEnhance": true
|
||||
}`}
|
||||
language="json"
|
||||
filename="Enhancement Example"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Generation Status */}
|
||||
<section id="generation-status" className="mb-12">
|
||||
<SectionHeader level={2} id="generation-status" className="mb-6">
|
||||
Generation Status
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-6">
|
||||
Generations go through these status stages:
|
||||
</p>
|
||||
|
||||
<Table
|
||||
headers={['Status', 'Description']}
|
||||
rows={statuses.map(([status, description]) => [
|
||||
<InlineCode key="status">{status}</InlineCode>,
|
||||
description,
|
||||
])}
|
||||
/>
|
||||
|
||||
<p className="text-gray-300 leading-relaxed mt-6 mb-4">
|
||||
Poll the generation endpoint to check status:
|
||||
</p>
|
||||
<EndpointCard
|
||||
method="GET"
|
||||
endpoint="/api/v1/generations/:id"
|
||||
baseUrl="https://api.banatie.app"
|
||||
/>
|
||||
<p className="text-gray-400 text-sm mt-4">
|
||||
When <InlineCode>status: "success"</InlineCode>, the <InlineCode>outputImageId</InlineCode> field
|
||||
contains the generated image ID.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{/* Response */}
|
||||
<section id="response" className="mb-12">
|
||||
<SectionHeader level={2} id="response" className="mb-4">
|
||||
Response Format
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
On success, the API returns a JSON object containing the generation details and output image.
|
||||
</p>
|
||||
|
||||
<CodeBlock
|
||||
code={`{
|
||||
"success": true,
|
||||
"data": {
|
||||
"id": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"projectId": "57c7f7f4-47de-4d70-9ebd-3807a0b63746",
|
||||
"prompt": "A photorealistic establishing shot of a sleek red sports car...",
|
||||
"originalPrompt": "a red sports car on a mountain road",
|
||||
"autoEnhance": true,
|
||||
"aspectRatio": "16:9",
|
||||
"status": "success",
|
||||
"outputImageId": "7c4ccf47-41ce-4718-afbc-8c553b2c631a",
|
||||
"outputImage": {
|
||||
"id": "7c4ccf47-41ce-4718-afbc-8c553b2c631a",
|
||||
"storageUrl": "https://cdn.banatie.app/default/my-project/img/7c4ccf47-41ce-4718-afbc-8c553b2c631a",
|
||||
"mimeType": "image/png",
|
||||
"width": 1792,
|
||||
"height": 1024,
|
||||
"fileSize": 1909246
|
||||
},
|
||||
"processingTimeMs": 8500,
|
||||
"createdAt": "2025-11-28T10:00:00.000Z"
|
||||
}
|
||||
}`}
|
||||
language="json"
|
||||
filename="Success Response"
|
||||
/>
|
||||
|
||||
<TipBox variant="compact" type="info" >
|
||||
<strong>Note:</strong> The image URL uses the UUID as filename with no extension.
|
||||
Content-Type is stored in object metadata.
|
||||
</TipBox>
|
||||
</section>
|
||||
|
||||
{/* Error Codes */}
|
||||
<section id="error-codes" className="mb-12">
|
||||
<SectionHeader level={2} id="error-codes" className="mb-6">
|
||||
Error Codes
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-6">
|
||||
The API uses standard HTTP status codes and returns descriptive error messages.
|
||||
</p>
|
||||
|
||||
<Table
|
||||
headers={['Status', 'Code', 'Description']}
|
||||
rows={errorCodes.map(([status, code, description]) => [
|
||||
<InlineCode key="status" color="error">{status}</InlineCode>,
|
||||
<InlineCode key="code">{code}</InlineCode>,
|
||||
description,
|
||||
])}
|
||||
/>
|
||||
|
||||
<div className="mt-6">
|
||||
<TipBox variant="compact" type="warning">
|
||||
<strong>Rate Limits:</strong> Project API keys are limited to 100 requests per hour.
|
||||
Check <InlineCode>X-RateLimit-Remaining</InlineCode> header for current usage.
|
||||
</TipBox>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Interactive Widget */}
|
||||
<section id="interactive" className="mb-12">
|
||||
<SectionHeader level={2} id="interactive" className="mb-4">
|
||||
Try It Live
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-6">
|
||||
Test the API directly from this page. Enter your API key and customize the parameters below.
|
||||
</p>
|
||||
|
||||
<InteractiveAPIWidget
|
||||
endpoint="/api/v1/generations"
|
||||
method="POST"
|
||||
description="Generate an image from a text prompt"
|
||||
parameters={parameters}
|
||||
/>
|
||||
</section>
|
||||
</DocPage>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,330 @@
|
|||
'use client';
|
||||
|
||||
/**
|
||||
* API Reference: Image Management
|
||||
*
|
||||
* Based on docs/api/images-upload.md (CRUD sections)
|
||||
*/
|
||||
|
||||
import { TipBox } from '@/components/docs/shared/TipBox';
|
||||
import { Table } from '@/components/docs/shared/Table';
|
||||
import { CodeBlock } from '@/components/docs/shared/CodeBlock';
|
||||
import { DocPage } from '@/components/docs/layout/DocPage';
|
||||
import {
|
||||
Hero,
|
||||
SectionHeader,
|
||||
InlineCode,
|
||||
EndpointCard,
|
||||
} from '@/components/docs/blocks';
|
||||
|
||||
const tocItems = [
|
||||
{ id: 'overview', text: 'Overview', level: 2 },
|
||||
{ id: 'list-images', text: 'List Images', level: 2 },
|
||||
{ id: 'get-image', text: 'Get Image', level: 2 },
|
||||
{ id: 'update-metadata', text: 'Update Metadata', level: 2 },
|
||||
{ id: 'assign-alias', text: 'Assign Alias', level: 2 },
|
||||
{ id: 'delete-image', text: 'Delete Image', level: 2 },
|
||||
{ id: 'response-fields', text: 'Response Fields', level: 2 },
|
||||
{ id: 'next-steps', text: 'Next Steps', level: 2 },
|
||||
];
|
||||
|
||||
const listQueryParams = [
|
||||
{ name: 'flowId', type: 'string', default: '-', description: 'Filter by flow UUID' },
|
||||
{ name: 'source', type: 'string', default: '-', description: 'Filter by source: generated, uploaded' },
|
||||
{ name: 'alias', type: 'string', default: '-', description: 'Filter by exact alias match' },
|
||||
{ name: 'limit', type: 'number', default: '20', description: 'Results per page (max: 100)' },
|
||||
{ name: 'offset', type: 'number', default: '0', description: 'Pagination offset' },
|
||||
{ name: 'includeDeleted', type: 'boolean', default: 'false', description: 'Include soft-deleted records' },
|
||||
];
|
||||
|
||||
const responseFields = [
|
||||
['id', 'string', 'Image UUID (same as filename in storage)'],
|
||||
['projectId', 'string', 'Project UUID'],
|
||||
['flowId', 'string', 'Associated flow UUID (null if none)'],
|
||||
['storageUrl', 'string', 'CDN URL for direct access'],
|
||||
['mimeType', 'string', 'Image MIME type'],
|
||||
['fileSize', 'number', 'File size in bytes'],
|
||||
['width', 'number', 'Image width in pixels'],
|
||||
['height', 'number', 'Image height in pixels'],
|
||||
['source', 'string', '"generated" or "uploaded"'],
|
||||
['alias', 'string', 'Project-scoped alias (null if none)'],
|
||||
['focalPoint', 'object', '{ x, y } coordinates (0.0-1.0)'],
|
||||
['meta', 'object', 'Custom metadata'],
|
||||
['createdAt', 'string', 'ISO timestamp'],
|
||||
['updatedAt', 'string', 'ISO timestamp'],
|
||||
];
|
||||
|
||||
export default function ImageManagementPage() {
|
||||
return (
|
||||
<DocPage
|
||||
breadcrumbItems={[
|
||||
{ label: 'Documentation', href: '/docs' },
|
||||
{ label: 'API Reference', href: '/docs/api' },
|
||||
{ label: 'Image Management' },
|
||||
]}
|
||||
tocItems={tocItems}
|
||||
nextSteps={{
|
||||
links: [
|
||||
{
|
||||
href: '/docs/api/live',
|
||||
title: 'Live URLs',
|
||||
description: 'Learn about CDN access and live URL generation.',
|
||||
accent: 'primary',
|
||||
},
|
||||
{
|
||||
href: '/docs/api/advanced',
|
||||
title: 'Advanced Generation',
|
||||
description: 'Use aliases and references in generation workflows.',
|
||||
accent: 'secondary',
|
||||
},
|
||||
],
|
||||
}}
|
||||
>
|
||||
{/* Hero Section */}
|
||||
<Hero
|
||||
title="Image Management"
|
||||
subtitle="List, retrieve, update, and delete images in your project."
|
||||
/>
|
||||
|
||||
{/* Overview */}
|
||||
<section id="overview" className="mb-12">
|
||||
<SectionHeader level={2} id="overview">
|
||||
Overview
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
The Image Management API provides CRUD operations for images in your project.
|
||||
Access images by UUID or alias, update metadata, and manage aliases for easy reference.
|
||||
</p>
|
||||
<TipBox variant="compact" type="info">
|
||||
<strong>Tip:</strong> Use aliases like <InlineCode>@hero</InlineCode> for human-readable
|
||||
references instead of UUIDs.
|
||||
</TipBox>
|
||||
</section>
|
||||
|
||||
{/* List Images */}
|
||||
<section id="list-images" className="mb-12">
|
||||
<SectionHeader level={2} id="list-images">
|
||||
List Images
|
||||
</SectionHeader>
|
||||
<EndpointCard
|
||||
method="GET"
|
||||
endpoint="/api/v1/images"
|
||||
baseUrl="https://api.banatie.app"
|
||||
/>
|
||||
|
||||
<SectionHeader level={3} id="list-params" className="mt-6 mb-4">
|
||||
Query Parameters
|
||||
</SectionHeader>
|
||||
<Table
|
||||
headers={['Parameter', 'Type', 'Default', 'Description']}
|
||||
rows={listQueryParams.map((param) => [
|
||||
<InlineCode key="name">{param.name}</InlineCode>,
|
||||
<span key="type" className="text-cyan-400">{param.type}</span>,
|
||||
param.default === '-' ? <span className="text-gray-500">-</span> : <InlineCode key="default">{param.default}</InlineCode>,
|
||||
param.description,
|
||||
])}
|
||||
/>
|
||||
|
||||
<div className="mt-6">
|
||||
<CodeBlock
|
||||
code={`{
|
||||
"success": true,
|
||||
"data": [
|
||||
{
|
||||
"id": "7c4ccf47-41ce-4718-afbc-8c553b2c631a",
|
||||
"storageUrl": "https://cdn.banatie.app/default/my-project/img/7c4ccf47-...",
|
||||
"source": "uploaded",
|
||||
"alias": "@brand-logo",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"createdAt": "2025-11-28T10:00:00.000Z"
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"limit": 20,
|
||||
"offset": 0,
|
||||
"total": 25,
|
||||
"hasMore": true
|
||||
}
|
||||
}`}
|
||||
language="json"
|
||||
filename="Response"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Get Image */}
|
||||
<section id="get-image" className="mb-12">
|
||||
<SectionHeader level={2} id="get-image">
|
||||
Get Image
|
||||
</SectionHeader>
|
||||
<EndpointCard
|
||||
method="GET"
|
||||
endpoint="/api/v1/images/:id_or_alias"
|
||||
baseUrl="https://api.banatie.app"
|
||||
/>
|
||||
<p className="text-gray-300 leading-relaxed mt-4 mb-4">
|
||||
Retrieve a single image by UUID or alias.
|
||||
</p>
|
||||
|
||||
<CodeBlock
|
||||
code={`# By UUID
|
||||
GET /api/v1/images/7c4ccf47-41ce-4718-afbc-8c553b2c631a
|
||||
|
||||
# By project alias
|
||||
GET /api/v1/images/@brand-logo
|
||||
|
||||
# By technical alias (requires flowId)
|
||||
GET /api/v1/images/@last?flowId=flow-123
|
||||
|
||||
# By flow alias
|
||||
GET /api/v1/images/@hero?flowId=flow-123`}
|
||||
language="bash"
|
||||
filename="Examples"
|
||||
/>
|
||||
|
||||
<div className="mt-6">
|
||||
<TipBox variant="compact" type="info">
|
||||
<strong>Alias Resolution:</strong> When using aliases with <InlineCode>flowId</InlineCode>,
|
||||
the system checks flow aliases first, then falls back to project aliases.
|
||||
</TipBox>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Update Metadata */}
|
||||
<section id="update-metadata" className="mb-12">
|
||||
<SectionHeader level={2} id="update-metadata">
|
||||
Update Metadata
|
||||
</SectionHeader>
|
||||
<EndpointCard
|
||||
method="PUT"
|
||||
endpoint="/api/v1/images/:id_or_alias"
|
||||
baseUrl="https://api.banatie.app"
|
||||
/>
|
||||
<p className="text-gray-300 leading-relaxed mt-4 mb-4">
|
||||
Update image metadata including focal point and custom data.
|
||||
</p>
|
||||
|
||||
<CodeBlock
|
||||
code={`{
|
||||
"focalPoint": { "x": 0.5, "y": 0.3 },
|
||||
"meta": {
|
||||
"description": "Updated brand logo",
|
||||
"tags": ["logo", "brand", "2025"]
|
||||
}
|
||||
}`}
|
||||
language="json"
|
||||
filename="Request Body"
|
||||
/>
|
||||
|
||||
<p className="text-gray-400 text-sm mt-4">
|
||||
<strong>Note:</strong> Alias assignment has its own dedicated endpoint.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{/* Assign Alias */}
|
||||
<section id="assign-alias" className="mb-12">
|
||||
<SectionHeader level={2} id="assign-alias">
|
||||
Assign Alias
|
||||
</SectionHeader>
|
||||
<EndpointCard
|
||||
method="PUT"
|
||||
endpoint="/api/v1/images/:id_or_alias/alias"
|
||||
baseUrl="https://api.banatie.app"
|
||||
/>
|
||||
<p className="text-gray-300 leading-relaxed mt-4 mb-4">
|
||||
Assign or remove a project-scoped alias from an image.
|
||||
</p>
|
||||
|
||||
<CodeBlock
|
||||
code={`// Assign alias
|
||||
{ "alias": "@new-logo" }
|
||||
|
||||
// Remove alias
|
||||
{ "alias": null }`}
|
||||
language="json"
|
||||
filename="Request Body"
|
||||
/>
|
||||
|
||||
<div className="mt-6">
|
||||
<TipBox variant="compact" type="warning">
|
||||
<strong>Override Behavior:</strong> If another image has the alias, it loses the alias.
|
||||
The target image gets the alias. The old image is preserved, just unlinked.
|
||||
</TipBox>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Delete Image */}
|
||||
<section id="delete-image" className="mb-12">
|
||||
<SectionHeader level={2} id="delete-image">
|
||||
Delete Image
|
||||
</SectionHeader>
|
||||
<EndpointCard
|
||||
method="DELETE"
|
||||
endpoint="/api/v1/images/:id_or_alias"
|
||||
baseUrl="https://api.banatie.app"
|
||||
/>
|
||||
<p className="text-gray-300 leading-relaxed mt-4 mb-4">
|
||||
Permanently delete an image and its storage file.
|
||||
</p>
|
||||
|
||||
<CodeBlock
|
||||
code={`{
|
||||
"success": true,
|
||||
"message": "Image deleted"
|
||||
}`}
|
||||
language="json"
|
||||
filename="Response"
|
||||
/>
|
||||
|
||||
<div className="mt-6">
|
||||
<TipBox variant="prominent" type="warning">
|
||||
<strong>Warning:</strong> This action is irreversible. The image record and storage file
|
||||
are permanently deleted. Related generations will have their <InlineCode>outputImageId</InlineCode> set to null.
|
||||
</TipBox>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Response Fields */}
|
||||
<section id="response-fields" className="mb-12">
|
||||
<SectionHeader level={2} id="response-fields" className="mb-6">
|
||||
Response Fields
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-6">
|
||||
Complete list of fields returned in image responses:
|
||||
</p>
|
||||
|
||||
<Table
|
||||
headers={['Field', 'Type', 'Description']}
|
||||
rows={responseFields.map(([field, type, description]) => [
|
||||
<InlineCode key="field">{field}</InlineCode>,
|
||||
<span key="type" className="text-cyan-400">{type}</span>,
|
||||
description,
|
||||
])}
|
||||
/>
|
||||
|
||||
<SectionHeader level={3} id="accessing-images" className="mt-8 mb-4">
|
||||
Accessing Images
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
Use <InlineCode>storageUrl</InlineCode> for direct CDN access:
|
||||
</p>
|
||||
|
||||
<CodeBlock
|
||||
code={`<!-- Direct access via UUID (fastest, cached) -->
|
||||
<img src="https://cdn.banatie.app/default/my-project/img/7c4ccf47-..." />
|
||||
|
||||
<!-- Access via alias (requires API resolution) -->
|
||||
<img src="https://cdn.banatie.app/default/my-project/img/@brand-logo" />`}
|
||||
language="html"
|
||||
filename="Usage Examples"
|
||||
/>
|
||||
|
||||
<TipBox variant="compact" type="info">
|
||||
<strong>Performance:</strong> UUID URLs are served directly from CDN.
|
||||
Alias URLs require API resolution but enable dynamic reassignment.
|
||||
</TipBox>
|
||||
</section>
|
||||
</DocPage>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,414 @@
|
|||
'use client';
|
||||
|
||||
/**
|
||||
* API Reference: Live URLs & CDN
|
||||
*
|
||||
* Based on docs/api/live-url.md
|
||||
*/
|
||||
|
||||
import { TipBox } from '@/components/docs/shared/TipBox';
|
||||
import { Table } from '@/components/docs/shared/Table';
|
||||
import { CodeBlock } from '@/components/docs/shared/CodeBlock';
|
||||
import { DocPage } from '@/components/docs/layout/DocPage';
|
||||
import {
|
||||
Hero,
|
||||
SectionHeader,
|
||||
InlineCode,
|
||||
EndpointCard,
|
||||
} from '@/components/docs/blocks';
|
||||
|
||||
const tocItems = [
|
||||
{ id: 'overview', text: 'Overview', level: 2 },
|
||||
{ id: 'url-architecture', text: 'URL Architecture', level: 2 },
|
||||
{ id: 'cdn-serving', text: 'CDN Image Serving', level: 2 },
|
||||
{ id: 'live-generation', text: 'Live URL Generation', level: 2 },
|
||||
{ id: 'cache-behavior', text: 'Cache Behavior', level: 2 },
|
||||
{ id: 'rate-limiting', text: 'IP Rate Limiting', level: 2 },
|
||||
{ id: 'scope-management', text: 'Scope Management', level: 2 },
|
||||
{ id: 'use-cases', text: 'Use Cases', level: 2 },
|
||||
{ id: 'next-steps', text: 'Next Steps', level: 2 },
|
||||
];
|
||||
|
||||
const urlPatterns = [
|
||||
['/{org}/{proj}/img/{uuid}', 'Direct image by UUID', 'Caddy → MinIO (public)'],
|
||||
['/{org}/{proj}/img/@{alias}', 'Image by alias', 'Caddy → API → MinIO'],
|
||||
['/{org}/{proj}/live/{scope}?prompt=...', 'Live generation', 'Caddy → API → MinIO'],
|
||||
];
|
||||
|
||||
const liveQueryParams = [
|
||||
{ name: 'prompt', type: 'string', required: true, default: '-', description: 'Image description' },
|
||||
{ name: 'aspectRatio', type: 'string', required: false, default: '"1:1"', description: 'Aspect ratio' },
|
||||
{ name: 'autoEnhance', type: 'boolean', required: false, default: 'true', description: 'Enable prompt enhancement' },
|
||||
];
|
||||
|
||||
const cacheHitHeaders = [
|
||||
['Content-Type', 'image/jpeg'],
|
||||
['Cache-Control', 'public, max-age=31536000'],
|
||||
['X-Cache-Status', 'HIT'],
|
||||
['X-Scope', 'Scope identifier'],
|
||||
['X-Image-Id', 'Image UUID'],
|
||||
];
|
||||
|
||||
const cacheMissHeaders = [
|
||||
['Content-Type', 'image/jpeg'],
|
||||
['Cache-Control', 'public, max-age=31536000'],
|
||||
['X-Cache-Status', 'MISS'],
|
||||
['X-Scope', 'Scope identifier'],
|
||||
['X-Generation-Id', 'Generation UUID'],
|
||||
['X-Image-Id', 'Image UUID'],
|
||||
['X-RateLimit-Limit', '10'],
|
||||
['X-RateLimit-Remaining', 'Remaining requests'],
|
||||
['X-RateLimit-Reset', 'Seconds until reset'],
|
||||
];
|
||||
|
||||
const rateLimits = [
|
||||
['New generations', '10 per hour per IP'],
|
||||
['Cache hits', 'Unlimited'],
|
||||
];
|
||||
|
||||
const scopeParams = [
|
||||
{ name: 'slug', type: 'string', required: true, default: '-', description: 'Unique identifier' },
|
||||
{ name: 'allowNewGenerations', type: 'boolean', required: false, default: 'true', description: 'Allow new generations' },
|
||||
{ name: 'newGenerationsLimit', type: 'number', required: false, default: '30', description: 'Max generations in scope' },
|
||||
{ name: 'meta', type: 'object', required: false, default: '{}', description: 'Custom metadata' },
|
||||
];
|
||||
|
||||
const errorCodes = [
|
||||
['400', 'SCOPE_INVALID_FORMAT', 'Invalid scope slug format'],
|
||||
['403', 'SCOPE_CREATION_DISABLED', 'New scope creation not allowed'],
|
||||
['404', 'ORG_NOT_FOUND', 'Organization not found'],
|
||||
['404', 'PROJECT_NOT_FOUND', 'Project not found'],
|
||||
['404', 'SCOPE_NOT_FOUND', 'Scope does not exist'],
|
||||
['409', 'SCOPE_ALREADY_EXISTS', 'Scope slug already in use'],
|
||||
['429', 'IP_RATE_LIMIT_EXCEEDED', 'IP rate limit (10/hour) exceeded'],
|
||||
['429', 'SCOPE_GENERATION_LIMIT_EXCEEDED', 'Scope limit reached'],
|
||||
];
|
||||
|
||||
export default function LiveUrlsPage() {
|
||||
return (
|
||||
<DocPage
|
||||
breadcrumbItems={[
|
||||
{ label: 'Documentation', href: '/docs' },
|
||||
{ label: 'API Reference', href: '/docs/api' },
|
||||
{ label: 'Live URLs' },
|
||||
]}
|
||||
tocItems={tocItems}
|
||||
nextSteps={{
|
||||
links: [
|
||||
{
|
||||
href: '/docs/api/generate',
|
||||
title: 'Image Generation',
|
||||
description: 'API-based generation with full control over parameters.',
|
||||
accent: 'primary',
|
||||
},
|
||||
{
|
||||
href: '/docs/api/advanced',
|
||||
title: 'Advanced Generation',
|
||||
description: 'Learn about reference images, aliases, and generation flows.',
|
||||
accent: 'secondary',
|
||||
},
|
||||
],
|
||||
}}
|
||||
>
|
||||
{/* Hero Section */}
|
||||
<Hero
|
||||
title="Live URLs & CDN"
|
||||
subtitle="Generate images on-demand via URL parameters with automatic caching."
|
||||
/>
|
||||
|
||||
{/* Overview */}
|
||||
<section id="overview" className="mb-12">
|
||||
<SectionHeader level={2} id="overview">
|
||||
Overview
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
Live URLs provide a simple way to generate images on-demand using URL parameters.
|
||||
Images are cached automatically, so repeated requests return instantly without counting
|
||||
toward rate limits.
|
||||
</p>
|
||||
<TipBox variant="compact" type="info">
|
||||
<strong>No API Key Required:</strong> Live URLs are public endpoints. Rate limiting
|
||||
is done by IP address instead of API key.
|
||||
</TipBox>
|
||||
</section>
|
||||
|
||||
{/* URL Architecture */}
|
||||
<section id="url-architecture" className="mb-12">
|
||||
<SectionHeader level={2} id="url-architecture">
|
||||
URL Architecture
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
All images are accessible via CDN at <InlineCode>https://cdn.banatie.app</InlineCode>:
|
||||
</p>
|
||||
|
||||
<Table
|
||||
headers={['URL Pattern', 'Description', 'Routing']}
|
||||
rows={urlPatterns.map(([pattern, description, routing]) => [
|
||||
<InlineCode key="pattern">{pattern}</InlineCode>,
|
||||
description,
|
||||
<span key="routing" className="text-gray-400 text-sm">{routing}</span>,
|
||||
])}
|
||||
/>
|
||||
|
||||
<div className="mt-6">
|
||||
<CodeBlock
|
||||
code={`# Direct UUID access (fastest, edge cached)
|
||||
https://cdn.banatie.app/default/my-project/img/7c4ccf47-41ce-4718-afbc-8c553b2c631a
|
||||
|
||||
# Alias access (API resolution)
|
||||
https://cdn.banatie.app/default/my-project/img/@hero-banner
|
||||
|
||||
# Live generation (on-demand with caching)
|
||||
https://cdn.banatie.app/default/my-project/live/hero?prompt=mountain+sunset`}
|
||||
language="bash"
|
||||
filename="Example URLs"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* CDN Image Serving */}
|
||||
<section id="cdn-serving" className="mb-12">
|
||||
<SectionHeader level={2} id="cdn-serving">
|
||||
CDN Image Serving
|
||||
</SectionHeader>
|
||||
<EndpointCard
|
||||
method="GET"
|
||||
endpoint="/cdn/:orgSlug/:projectSlug/img/:imageIdOrAlias"
|
||||
baseUrl="https://cdn.banatie.app"
|
||||
/>
|
||||
<p className="text-gray-300 leading-relaxed mt-4 mb-4">
|
||||
Serve images by UUID or project-scoped alias. No authentication required.
|
||||
</p>
|
||||
|
||||
<CodeBlock
|
||||
code={`# By UUID (direct MinIO access, fastest)
|
||||
GET /cdn/acme/website/img/7c4ccf47-41ce-4718-afbc-8c553b2c631a
|
||||
|
||||
# By alias (API resolution, then MinIO)
|
||||
GET /cdn/acme/website/img/@hero`}
|
||||
language="bash"
|
||||
filename="Examples"
|
||||
/>
|
||||
|
||||
<TipBox variant="compact" type="info">
|
||||
<strong>Performance:</strong> UUID requests are served directly from MinIO with edge caching.
|
||||
Alias requests require API resolution but enable dynamic reassignment.
|
||||
</TipBox>
|
||||
</section>
|
||||
|
||||
{/* Live URL Generation */}
|
||||
<section id="live-generation" className="mb-12">
|
||||
<SectionHeader level={2} id="live-generation">
|
||||
Live URL Generation
|
||||
</SectionHeader>
|
||||
<EndpointCard
|
||||
method="GET"
|
||||
endpoint="/cdn/:orgSlug/:projectSlug/live/:scope"
|
||||
baseUrl="https://cdn.banatie.app"
|
||||
/>
|
||||
<p className="text-gray-300 leading-relaxed mt-4 mb-4">
|
||||
Generate images on-demand via URL parameters. No authentication required.
|
||||
</p>
|
||||
|
||||
<SectionHeader level={3} id="live-params" className="mb-4">
|
||||
Query Parameters
|
||||
</SectionHeader>
|
||||
<Table
|
||||
headers={['Parameter', 'Type', 'Required', 'Default', 'Description']}
|
||||
rows={liveQueryParams.map((param) => [
|
||||
<InlineCode key="name">{param.name}</InlineCode>,
|
||||
<span key="type" className="text-cyan-400">{param.type}</span>,
|
||||
<span key="required" className={param.required ? 'text-green-400' : 'text-gray-500'}>
|
||||
{param.required ? 'Yes' : 'No'}
|
||||
</span>,
|
||||
param.default === '-' ? <span className="text-gray-500">-</span> : <InlineCode key="default">{param.default}</InlineCode>,
|
||||
param.description,
|
||||
])}
|
||||
/>
|
||||
|
||||
<div className="mt-6">
|
||||
<CodeBlock
|
||||
code={`<!-- Generate a 16:9 landscape image -->
|
||||
<img src="https://cdn.banatie.app/acme/website/live/hero-section?prompt=mountain+landscape&aspectRatio=16:9" />`}
|
||||
language="html"
|
||||
filename="Example Usage"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Cache Behavior */}
|
||||
<section id="cache-behavior" className="mb-12">
|
||||
<SectionHeader level={2} id="cache-behavior">
|
||||
Cache Behavior
|
||||
</SectionHeader>
|
||||
|
||||
<SectionHeader level={3} id="cache-hit" className="mb-4">
|
||||
Cache HIT
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
Image exists in cache - returns instantly without rate limit check.
|
||||
</p>
|
||||
<Table
|
||||
headers={['Header', 'Value']}
|
||||
rows={cacheHitHeaders.map(([header, value]) => [
|
||||
<InlineCode key="header">{header}</InlineCode>,
|
||||
<InlineCode key="value">{value}</InlineCode>,
|
||||
])}
|
||||
/>
|
||||
|
||||
<SectionHeader level={3} id="cache-miss" className="mt-8 mb-4">
|
||||
Cache MISS
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
New generation - generates image, stores in cache, counts toward rate limit.
|
||||
</p>
|
||||
<Table
|
||||
headers={['Header', 'Value']}
|
||||
rows={cacheMissHeaders.map(([header, value]) => [
|
||||
<InlineCode key="header">{header}</InlineCode>,
|
||||
<InlineCode key="value">{value}</InlineCode>,
|
||||
])}
|
||||
/>
|
||||
|
||||
<div className="mt-6">
|
||||
<TipBox variant="compact" type="info">
|
||||
<strong>Cache Key:</strong> Computed from{' '}
|
||||
<InlineCode>projectId + scope + prompt + aspectRatio + autoEnhance</InlineCode>
|
||||
</TipBox>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* IP Rate Limiting */}
|
||||
<section id="rate-limiting" className="mb-12">
|
||||
<SectionHeader level={2} id="rate-limiting">
|
||||
IP Rate Limiting
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
Live URLs are rate limited by IP address:
|
||||
</p>
|
||||
|
||||
<Table
|
||||
headers={['Limit', 'Value']}
|
||||
rows={rateLimits.map(([limit, value]) => [
|
||||
limit,
|
||||
<InlineCode key="value">{value}</InlineCode>,
|
||||
])}
|
||||
/>
|
||||
|
||||
<div className="mt-6">
|
||||
<TipBox variant="compact" type="warning">
|
||||
<strong>Important:</strong> Only cache MISS (new generations) count toward the limit.
|
||||
Cache HIT requests are unlimited.
|
||||
</TipBox>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Scope Management */}
|
||||
<section id="scope-management" className="mb-12">
|
||||
<SectionHeader level={2} id="scope-management">
|
||||
Scope Management
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
Scopes organize live URL generation budgets. Scope endpoints require Project Key authentication.
|
||||
</p>
|
||||
|
||||
<SectionHeader level={3} id="create-scope" className="mb-4">
|
||||
Create Scope
|
||||
</SectionHeader>
|
||||
<EndpointCard
|
||||
method="POST"
|
||||
endpoint="/api/v1/live/scopes"
|
||||
baseUrl="https://api.banatie.app"
|
||||
/>
|
||||
|
||||
<Table
|
||||
headers={['Parameter', 'Type', 'Required', 'Default', 'Description']}
|
||||
rows={scopeParams.map((param) => [
|
||||
<InlineCode key="name">{param.name}</InlineCode>,
|
||||
<span key="type" className="text-cyan-400">{param.type}</span>,
|
||||
<span key="required" className={param.required ? 'text-green-400' : 'text-gray-500'}>
|
||||
{param.required ? 'Yes' : 'No'}
|
||||
</span>,
|
||||
param.default === '-' ? <span className="text-gray-500">-</span> : <InlineCode key="default">{param.default}</InlineCode>,
|
||||
param.description,
|
||||
])}
|
||||
/>
|
||||
|
||||
<SectionHeader level={3} id="lazy-scope" className="mt-6 mb-4">
|
||||
Lazy Scope Creation
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
Scopes are auto-created on first live URL request if <InlineCode>project.allowNewLiveScopes = true</InlineCode>.
|
||||
</p>
|
||||
|
||||
<SectionHeader level={3} id="scope-endpoints" className="mt-6 mb-4">
|
||||
Scope Endpoints
|
||||
</SectionHeader>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<EndpointCard method="GET" endpoint="/api/v1/live/scopes" baseUrl="https://api.banatie.app" />
|
||||
<p className="text-gray-400 text-sm mt-2">List all scopes with pagination</p>
|
||||
</div>
|
||||
<div>
|
||||
<EndpointCard method="GET" endpoint="/api/v1/live/scopes/:slug" baseUrl="https://api.banatie.app" />
|
||||
<p className="text-gray-400 text-sm mt-2">Get scope with statistics</p>
|
||||
</div>
|
||||
<div>
|
||||
<EndpointCard method="PUT" endpoint="/api/v1/live/scopes/:slug" baseUrl="https://api.banatie.app" />
|
||||
<p className="text-gray-400 text-sm mt-2">Update scope settings</p>
|
||||
</div>
|
||||
<div>
|
||||
<EndpointCard method="POST" endpoint="/api/v1/live/scopes/:slug/regenerate" baseUrl="https://api.banatie.app" />
|
||||
<p className="text-gray-400 text-sm mt-2">Regenerate scope images</p>
|
||||
</div>
|
||||
<div>
|
||||
<EndpointCard method="DELETE" endpoint="/api/v1/live/scopes/:slug" baseUrl="https://api.banatie.app" />
|
||||
<p className="text-gray-400 text-sm mt-2">Delete scope (cascades to images)</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-6">
|
||||
<TipBox variant="prominent" type="warning">
|
||||
<strong>Delete Warning:</strong> Deleting a scope permanently removes all cached images.
|
||||
Aliased images may be kept based on alias protection rules.
|
||||
</TipBox>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Use Cases */}
|
||||
<section id="use-cases" className="mb-12">
|
||||
<SectionHeader level={2} id="use-cases">
|
||||
Use Cases
|
||||
</SectionHeader>
|
||||
|
||||
<SectionHeader level={3} id="hero-images" className="mb-4">
|
||||
Dynamic Hero Images
|
||||
</SectionHeader>
|
||||
<CodeBlock
|
||||
code={`<img src="https://cdn.banatie.app/acme/website/live/hero?prompt=professional+office+workspace&aspectRatio=16:9" />`}
|
||||
language="html"
|
||||
filename="Hero Image"
|
||||
/>
|
||||
<p className="text-gray-400 text-sm mt-2 mb-6">First load generates, subsequent loads are cached.</p>
|
||||
|
||||
<SectionHeader level={3} id="placeholders" className="mb-4">
|
||||
Product Placeholders
|
||||
</SectionHeader>
|
||||
<CodeBlock
|
||||
code={`<img src="https://cdn.banatie.app/acme/store/live/products?prompt=product+placeholder+gray+box&aspectRatio=1:1" />`}
|
||||
language="html"
|
||||
filename="Product Placeholder"
|
||||
/>
|
||||
|
||||
<SectionHeader level={3} id="blog-images" className="mt-6 mb-4">
|
||||
Blog Post Images
|
||||
</SectionHeader>
|
||||
<CodeBlock
|
||||
code={`<img src="https://cdn.banatie.app/acme/blog/live/posts?prompt=abstract+technology+background&aspectRatio=16:9" />`}
|
||||
language="html"
|
||||
filename="Blog Image"
|
||||
/>
|
||||
</section>
|
||||
</DocPage>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,226 +0,0 @@
|
|||
'use client';
|
||||
|
||||
/**
|
||||
* API Reference: Text to Image
|
||||
*
|
||||
* Refactored to use DocPage component for consistent layout
|
||||
* Layout handles SubsectionNav and Left Sidebar
|
||||
* DocPage handles Breadcrumb, Article structure, Next Steps, and TOC
|
||||
* This page provides only the content (Hero + sections)
|
||||
*/
|
||||
|
||||
import { TipBox } from '@/components/docs/shared/TipBox';
|
||||
import { Table } from '@/components/docs/shared/Table';
|
||||
import { CodeBlock } from '@/components/docs/shared/CodeBlock';
|
||||
import { DocPage } from '@/components/docs/layout/DocPage';
|
||||
import { InteractiveAPIWidget } from '@/components/docs/blocks/InteractiveAPIWidget';
|
||||
import {
|
||||
Hero,
|
||||
SectionHeader,
|
||||
InlineCode,
|
||||
EndpointCard,
|
||||
} from '@/components/docs/blocks';
|
||||
|
||||
const tocItems = [
|
||||
{ id: 'overview', text: 'Overview', level: 2 },
|
||||
{ id: 'endpoint', text: 'Endpoint', level: 2 },
|
||||
{ id: 'parameters', text: 'Parameters', level: 2 },
|
||||
{ id: 'response', text: 'Response', level: 2 },
|
||||
{ id: 'error-codes', text: 'Error Codes', level: 2 },
|
||||
{ id: 'interactive', text: 'Try It Live', level: 2 },
|
||||
{ id: 'next-steps', text: 'Next Steps', level: 2 },
|
||||
];
|
||||
|
||||
const parameters = [
|
||||
{ name: 'prompt', type: 'string', required: true, description: 'Text description of the image to generate' },
|
||||
{ name: 'filename', type: 'string', required: false, description: 'Output filename (without extension)' },
|
||||
{ name: 'aspectRatio', type: 'string', required: false, description: 'Image aspect ratio: "1:1", "16:9", "9:16", "4:3"' },
|
||||
{ name: 'autoEnhance', type: 'boolean', required: false, description: 'Enable AI prompt enhancement for better results' },
|
||||
];
|
||||
|
||||
export default function TextToImageAPIPage() {
|
||||
return (
|
||||
<DocPage
|
||||
breadcrumbItems={[
|
||||
{ label: 'Documentation', href: '/docs' },
|
||||
{ label: 'API Reference', href: '/docs/api' },
|
||||
{ label: 'Text to Image' },
|
||||
]}
|
||||
tocItems={tocItems}
|
||||
nextSteps={{
|
||||
links: [
|
||||
{
|
||||
href: '/docs/api/upload',
|
||||
title: 'Upload API',
|
||||
description: 'Learn how to upload reference images for image-to-image generation.',
|
||||
accent: 'primary',
|
||||
},
|
||||
{
|
||||
href: '/docs/guides/error-handling',
|
||||
title: 'Error Handling',
|
||||
description: 'Best practices for handling errors and retries in production.',
|
||||
accent: 'secondary',
|
||||
},
|
||||
],
|
||||
}}
|
||||
>
|
||||
|
||||
{/* Hero Section */}
|
||||
<Hero
|
||||
title="Text to Image"
|
||||
subtitle="Generate high-quality images from text prompts using AI-powered models."
|
||||
/>
|
||||
|
||||
{/* Overview */}
|
||||
<section id="overview" className="mb-12">
|
||||
<SectionHeader level={2} id="overview">
|
||||
Overview
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
The Text to Image endpoint allows you to generate images from natural language descriptions.
|
||||
Powered by Google Gemini 2.5 Flash and Imagen 4.0, it produces photorealistic images
|
||||
optimized for your specified requirements.
|
||||
</p>
|
||||
<TipBox variant="compact" type="info">
|
||||
<strong>Tip:</strong> Enable <InlineCode>autoEnhance</InlineCode>
|
||||
to let AI improve your prompts for better image quality.
|
||||
</TipBox>
|
||||
</section>
|
||||
|
||||
{/* Endpoint */}
|
||||
<section id="endpoint" className="mb-12">
|
||||
<SectionHeader level={2} id="endpoint">
|
||||
Endpoint
|
||||
</SectionHeader>
|
||||
<EndpointCard
|
||||
method="POST"
|
||||
endpoint="/api/text-to-image"
|
||||
baseUrl="https://api.banatie.com"
|
||||
/>
|
||||
</section>
|
||||
|
||||
{/* Parameters */}
|
||||
<section id="parameters" className="mb-12">
|
||||
<SectionHeader level={2} id="parameters" className="mb-6">
|
||||
Parameters
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-6">
|
||||
All parameters should be sent in the request body as JSON.
|
||||
</p>
|
||||
|
||||
<Table
|
||||
headers={['Parameter', 'Type', 'Required', 'Description']}
|
||||
rows={parameters.map((param) => [
|
||||
<InlineCode key="name">{param.name}</InlineCode>,
|
||||
<span key="type" className="text-cyan-400">{param.type}</span>,
|
||||
<span key="required" className={param.required ? 'text-green-400' : 'text-gray-500'}>
|
||||
{param.required ? 'Yes' : 'No'}
|
||||
</span>,
|
||||
param.description,
|
||||
])}
|
||||
/>
|
||||
|
||||
<div className="mt-6">
|
||||
<TipBox variant="compact" type="info">
|
||||
<strong>Default Values:</strong> If not specified, <InlineCode>filename</InlineCode> is
|
||||
auto-generated, <InlineCode>aspectRatio</InlineCode> defaults
|
||||
to "1:1", and <InlineCode>autoEnhance</InlineCode> is false.
|
||||
</TipBox>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Response */}
|
||||
<section id="response" className="mb-12">
|
||||
<SectionHeader level={2} id="response" className="mb-4">
|
||||
Response
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
On success, the API returns a JSON object containing the generated image URL and metadata.
|
||||
</p>
|
||||
|
||||
<CodeBlock
|
||||
code={`{
|
||||
"success": true,
|
||||
"data": {
|
||||
"url": "https://cdn.banatie.com/org/project/generated/2025-01/image.png",
|
||||
"filepath": "org/project/generated/2025-01/image.png",
|
||||
"width": 1024,
|
||||
"height": 1024,
|
||||
"promptEnhancement": {
|
||||
"enhancedPrompt": "A highly detailed, photorealistic...",
|
||||
"wasEnhanced": true
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"generationTime": 3.42,
|
||||
"model": "imagen-4.0"
|
||||
}
|
||||
}`}
|
||||
language="json"
|
||||
filename="Success Response"
|
||||
/>
|
||||
</section>
|
||||
|
||||
{/* Error Codes */}
|
||||
<section id="error-codes" className="mb-12">
|
||||
<SectionHeader level={2} id="error-codes" className="mb-6">
|
||||
Error Codes
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-6">
|
||||
The API uses standard HTTP status codes and returns descriptive error messages.
|
||||
</p>
|
||||
|
||||
<Table
|
||||
headers={['Status Code', 'Error Type', 'Description']}
|
||||
rows={[
|
||||
[
|
||||
<InlineCode key="code" color="error">400</InlineCode>,
|
||||
'Bad Request',
|
||||
'Missing or invalid parameters in the request body',
|
||||
],
|
||||
[
|
||||
<InlineCode key="code" color="error">401</InlineCode>,
|
||||
'Unauthorized',
|
||||
'Missing or invalid API key in X-API-Key header',
|
||||
],
|
||||
[
|
||||
<InlineCode key="code" color="error">429</InlineCode>,
|
||||
'Rate Limit',
|
||||
'Too many requests. Check rate limit headers for retry timing',
|
||||
],
|
||||
[
|
||||
<InlineCode key="code" color="error">500</InlineCode>,
|
||||
'Server Error',
|
||||
'Internal server error. Contact support if persists',
|
||||
],
|
||||
]}
|
||||
/>
|
||||
|
||||
<div className="mt-6">
|
||||
<TipBox variant="compact" type="warning">
|
||||
<strong>Rate Limits:</strong> Project API keys are limited to 100 requests per hour.
|
||||
Upgrade your plan for higher limits.
|
||||
</TipBox>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Interactive Widget */}
|
||||
<section id="interactive" className="mb-12">
|
||||
<SectionHeader level={2} id="interactive" className="mb-4">
|
||||
Try It Live
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-6">
|
||||
Test the API directly from this page. Enter your API key and customize the parameters below.
|
||||
</p>
|
||||
|
||||
<InteractiveAPIWidget
|
||||
endpoint="/api/text-to-image"
|
||||
method="POST"
|
||||
description="Generate an image from a text prompt"
|
||||
parameters={parameters}
|
||||
/>
|
||||
</section>
|
||||
|
||||
</DocPage>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,269 @@
|
|||
'use client';
|
||||
|
||||
/**
|
||||
* API Reference: Image Upload
|
||||
*
|
||||
* Based on docs/api/images-upload.md (upload section)
|
||||
*/
|
||||
|
||||
import { TipBox } from '@/components/docs/shared/TipBox';
|
||||
import { Table } from '@/components/docs/shared/Table';
|
||||
import { CodeBlock } from '@/components/docs/shared/CodeBlock';
|
||||
import { DocPage } from '@/components/docs/layout/DocPage';
|
||||
import {
|
||||
Hero,
|
||||
SectionHeader,
|
||||
InlineCode,
|
||||
EndpointCard,
|
||||
} from '@/components/docs/blocks';
|
||||
|
||||
const tocItems = [
|
||||
{ id: 'overview', text: 'Overview', level: 2 },
|
||||
{ id: 'endpoint', text: 'Upload Endpoint', level: 2 },
|
||||
{ id: 'parameters', text: 'Form Parameters', level: 2 },
|
||||
{ id: 'constraints', text: 'File Constraints', level: 2 },
|
||||
{ id: 'flow-association', text: 'Flow Association', level: 2 },
|
||||
{ id: 'response', text: 'Response Format', level: 2 },
|
||||
{ id: 'error-codes', text: 'Error Codes', level: 2 },
|
||||
{ id: 'next-steps', text: 'Next Steps', level: 2 },
|
||||
];
|
||||
|
||||
const formParameters = [
|
||||
{ name: 'file', type: 'file', required: true, description: 'Image file (PNG, JPEG, WebP)' },
|
||||
{ name: 'alias', type: 'string', required: false, description: 'Project-scoped alias (e.g., @logo)' },
|
||||
{ name: 'flowId', type: 'string', required: false, description: 'Flow UUID to associate with' },
|
||||
{ name: 'flowAlias', type: 'string', required: false, description: 'Flow-scoped alias (requires flowId)' },
|
||||
{ name: 'meta', type: 'string', required: false, description: 'JSON string with custom metadata' },
|
||||
];
|
||||
|
||||
const fileConstraints = [
|
||||
['Max file size', '5MB'],
|
||||
['Supported formats', 'PNG, JPEG, JPG, WebP'],
|
||||
['MIME types', 'image/png, image/jpeg, image/webp'],
|
||||
];
|
||||
|
||||
const flowIdBehavior = [
|
||||
['Not provided', 'Auto-generate pendingFlowId, lazy flow creation'],
|
||||
['null', 'No flow association'],
|
||||
['"uuid"', 'Associate with specified flow'],
|
||||
];
|
||||
|
||||
const errorCodes = [
|
||||
['400', 'VALIDATION_ERROR', 'Invalid parameters'],
|
||||
['400', 'FILE_TOO_LARGE', 'File exceeds 5MB limit'],
|
||||
['400', 'UNSUPPORTED_FILE_TYPE', 'Not PNG, JPEG, or WebP'],
|
||||
['400', 'ALIAS_FORMAT_CHECK', 'Alias must start with @'],
|
||||
['401', 'UNAUTHORIZED', 'Missing or invalid API key'],
|
||||
];
|
||||
|
||||
export default function ImageUploadPage() {
|
||||
return (
|
||||
<DocPage
|
||||
breadcrumbItems={[
|
||||
{ label: 'Documentation', href: '/docs' },
|
||||
{ label: 'API Reference', href: '/docs/api' },
|
||||
{ label: 'Image Upload' },
|
||||
]}
|
||||
tocItems={tocItems}
|
||||
nextSteps={{
|
||||
links: [
|
||||
{
|
||||
href: '/docs/api/images',
|
||||
title: 'Image Management',
|
||||
description: 'Learn how to list, update, and delete uploaded images.',
|
||||
accent: 'primary',
|
||||
},
|
||||
{
|
||||
href: '/docs/api/advanced',
|
||||
title: 'Advanced Generation',
|
||||
description: 'Use uploaded images as references for generation.',
|
||||
accent: 'secondary',
|
||||
},
|
||||
],
|
||||
}}
|
||||
>
|
||||
{/* Hero Section */}
|
||||
<Hero
|
||||
title="Image Upload"
|
||||
subtitle="Upload images for reference in generations or as standalone assets."
|
||||
/>
|
||||
|
||||
{/* Overview */}
|
||||
<section id="overview" className="mb-12">
|
||||
<SectionHeader level={2} id="overview">
|
||||
Overview
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
The Upload API allows you to upload images to your project. Uploaded images can be used as
|
||||
references for image-to-image generation, assigned aliases for easy access, or stored as
|
||||
standalone assets.
|
||||
</p>
|
||||
<TipBox variant="compact" type="info">
|
||||
<strong>Tip:</strong> Use aliases like <InlineCode>@logo</InlineCode> to reference
|
||||
uploaded images by name instead of UUID.
|
||||
</TipBox>
|
||||
</section>
|
||||
|
||||
{/* Endpoint */}
|
||||
<section id="endpoint" className="mb-12">
|
||||
<SectionHeader level={2} id="endpoint">
|
||||
Upload Endpoint
|
||||
</SectionHeader>
|
||||
<EndpointCard
|
||||
method="POST"
|
||||
endpoint="/api/v1/images/upload"
|
||||
baseUrl="https://api.banatie.app"
|
||||
/>
|
||||
<p className="text-gray-400 text-sm mt-4">
|
||||
Requires <InlineCode>X-API-Key</InlineCode> header with your Project Key.
|
||||
Content-Type must be <InlineCode>multipart/form-data</InlineCode>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{/* Parameters */}
|
||||
<section id="parameters" className="mb-12">
|
||||
<SectionHeader level={2} id="parameters" className="mb-6">
|
||||
Form Parameters
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-6">
|
||||
Send parameters as <InlineCode>multipart/form-data</InlineCode>:
|
||||
</p>
|
||||
|
||||
<Table
|
||||
headers={['Parameter', 'Type', 'Required', 'Description']}
|
||||
rows={formParameters.map((param) => [
|
||||
<InlineCode key="name">{param.name}</InlineCode>,
|
||||
<span key="type" className="text-cyan-400">{param.type}</span>,
|
||||
<span key="required" className={param.required ? 'text-green-400' : 'text-gray-500'}>
|
||||
{param.required ? 'Yes' : 'No'}
|
||||
</span>,
|
||||
param.description,
|
||||
])}
|
||||
/>
|
||||
|
||||
<div className="mt-6">
|
||||
<CodeBlock
|
||||
code={`curl -X POST https://api.banatie.app/api/v1/images/upload \\
|
||||
-H "X-API-Key: YOUR_PROJECT_KEY" \\
|
||||
-F "file=@logo.png" \\
|
||||
-F "alias=@brand-logo" \\
|
||||
-F 'meta={"tags": ["logo", "brand"]}'`}
|
||||
language="bash"
|
||||
filename="Example Request"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* File Constraints */}
|
||||
<section id="constraints" className="mb-12">
|
||||
<SectionHeader level={2} id="constraints" className="mb-6">
|
||||
File Constraints
|
||||
</SectionHeader>
|
||||
|
||||
<Table
|
||||
headers={['Constraint', 'Limit']}
|
||||
rows={fileConstraints.map(([constraint, limit]) => [
|
||||
constraint,
|
||||
<InlineCode key="limit">{limit}</InlineCode>,
|
||||
])}
|
||||
/>
|
||||
|
||||
<div className="mt-6">
|
||||
<TipBox variant="compact" type="warning">
|
||||
<strong>File Size:</strong> Files larger than 5MB will be rejected with a 400 error.
|
||||
Compress images before uploading if needed.
|
||||
</TipBox>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Flow Association */}
|
||||
<section id="flow-association" className="mb-12">
|
||||
<SectionHeader level={2} id="flow-association" className="mb-6">
|
||||
Flow Association
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-6">
|
||||
Images can be associated with generation flows for organized workflows.
|
||||
The <InlineCode>flowId</InlineCode> parameter controls this behavior:
|
||||
</p>
|
||||
|
||||
<Table
|
||||
headers={['flowId Value', 'Behavior']}
|
||||
rows={flowIdBehavior.map(([value, behavior]) => [
|
||||
<InlineCode key="value">{value}</InlineCode>,
|
||||
behavior,
|
||||
])}
|
||||
/>
|
||||
|
||||
<div className="mt-6">
|
||||
<CodeBlock
|
||||
code={`# Associate with existing flow
|
||||
curl -X POST https://api.banatie.app/api/v1/images/upload \\
|
||||
-H "X-API-Key: YOUR_PROJECT_KEY" \\
|
||||
-F "file=@reference.png" \\
|
||||
-F "flowId=550e8400-e29b-41d4-a716-446655440000" \\
|
||||
-F "flowAlias=@reference"`}
|
||||
language="bash"
|
||||
filename="Upload with Flow"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Response */}
|
||||
<section id="response" className="mb-12">
|
||||
<SectionHeader level={2} id="response" className="mb-4">
|
||||
Response Format
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
On success, the API returns a JSON object containing the uploaded image details.
|
||||
</p>
|
||||
|
||||
<CodeBlock
|
||||
code={`{
|
||||
"success": true,
|
||||
"data": {
|
||||
"id": "7c4ccf47-41ce-4718-afbc-8c553b2c631a",
|
||||
"projectId": "57c7f7f4-47de-4d70-9ebd-3807a0b63746",
|
||||
"flowId": null,
|
||||
"storageUrl": "https://cdn.banatie.app/default/my-project/img/7c4ccf47-41ce-4718-afbc-8c553b2c631a",
|
||||
"mimeType": "image/png",
|
||||
"fileSize": 45678,
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"source": "uploaded",
|
||||
"alias": "@brand-logo",
|
||||
"focalPoint": null,
|
||||
"meta": { "tags": ["logo", "brand"] },
|
||||
"createdAt": "2025-11-28T10:00:00.000Z"
|
||||
}
|
||||
}`}
|
||||
language="json"
|
||||
filename="Success Response"
|
||||
/>
|
||||
|
||||
<TipBox variant="compact" type="info">
|
||||
<strong>Note:</strong> The <InlineCode>id</InlineCode> field equals the filename in storage (UUID).
|
||||
Original filename is preserved in object metadata.
|
||||
</TipBox>
|
||||
</section>
|
||||
|
||||
{/* Error Codes */}
|
||||
<section id="error-codes" className="mb-12">
|
||||
<SectionHeader level={2} id="error-codes" className="mb-6">
|
||||
Error Codes
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-6">
|
||||
The API uses standard HTTP status codes and returns descriptive error messages.
|
||||
</p>
|
||||
|
||||
<Table
|
||||
headers={['Status', 'Code', 'Description']}
|
||||
rows={errorCodes.map(([status, code, description]) => [
|
||||
<InlineCode key="status" color="error">{status}</InlineCode>,
|
||||
<InlineCode key="code">{code}</InlineCode>,
|
||||
description,
|
||||
])}
|
||||
/>
|
||||
</section>
|
||||
</DocPage>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,313 +0,0 @@
|
|||
'use client';
|
||||
|
||||
/**
|
||||
* Authentication Guide
|
||||
*
|
||||
* Refactored to use DocPage component for consistent layout
|
||||
* Layout handles SubsectionNav and Left Sidebar
|
||||
* DocPage handles Breadcrumb, Article structure, Next Steps, and TOC
|
||||
* This page provides only the content (Hero + sections)
|
||||
*/
|
||||
|
||||
import { TipBox } from '@/components/docs/shared/TipBox';
|
||||
import { Table } from '@/components/docs/shared/Table';
|
||||
import { CodeBlock } from '@/components/docs/shared/CodeBlock';
|
||||
import { DocPage } from '@/components/docs/layout/DocPage';
|
||||
import {
|
||||
Hero,
|
||||
SectionHeader,
|
||||
InlineCode,
|
||||
} from '@/components/docs/blocks';
|
||||
|
||||
const tocItems = [
|
||||
{ id: 'overview', text: 'Overview', level: 2 },
|
||||
{ id: 'api-keys', text: 'API Keys', level: 2 },
|
||||
{ id: 'key-types', text: 'Key Types', level: 3 },
|
||||
{ id: 'creating-keys', text: 'Creating Keys', level: 3 },
|
||||
{ id: 'using-keys', text: 'Using API Keys', level: 2 },
|
||||
{ id: 'rate-limits', text: 'Rate Limits', level: 2 },
|
||||
{ id: 'security', text: 'Security Best Practices', level: 2 },
|
||||
{ id: 'next-steps', text: 'Next Steps', level: 2 },
|
||||
];
|
||||
|
||||
export default function AuthenticationGuidePage() {
|
||||
return (
|
||||
<DocPage
|
||||
breadcrumbItems={[
|
||||
{ label: 'Documentation', href: '/docs' },
|
||||
{ label: 'Guides', href: '/docs/guides' },
|
||||
{ label: 'Authentication' },
|
||||
]}
|
||||
tocItems={tocItems}
|
||||
nextSteps={{
|
||||
links: [
|
||||
{
|
||||
href: '/docs/api/text-to-image',
|
||||
title: 'Start Generating Images',
|
||||
description: 'Explore the Text to Image API and start building your integration.',
|
||||
accent: 'primary',
|
||||
},
|
||||
{
|
||||
href: '/docs/guides/error-handling',
|
||||
title: 'Error Handling Guide',
|
||||
description: 'Learn how to handle authentication errors and implement retry logic.',
|
||||
accent: 'secondary',
|
||||
},
|
||||
],
|
||||
}}
|
||||
>
|
||||
|
||||
{/* Hero Section */}
|
||||
<Hero
|
||||
title="Authentication"
|
||||
subtitle="Learn how to authenticate with the Banatie API using API keys, manage rate limits, and implement security best practices."
|
||||
/>
|
||||
|
||||
{/* Overview */}
|
||||
<section id="overview" className="mb-12">
|
||||
<SectionHeader level={2} id="overview" className="mb-4">
|
||||
Overview
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-6">
|
||||
Banatie uses API keys to authenticate requests. All API endpoints require authentication
|
||||
via the <InlineCode>X-API-Key</InlineCode> header.
|
||||
API keys are tied to organizations and projects, providing fine-grained access control.
|
||||
</p>
|
||||
|
||||
<TipBox variant="compact" type="info">
|
||||
<strong>Quick Start:</strong> New to API authentication? Check out our{' '}
|
||||
<a href="/docs" className="text-purple-400 hover:underline">
|
||||
Getting Started guide
|
||||
</a>{' '}
|
||||
for a step-by-step walkthrough.
|
||||
</TipBox>
|
||||
</section>
|
||||
|
||||
{/* API Keys */}
|
||||
<section id="api-keys" className="mb-12">
|
||||
<SectionHeader level={2} id="api-keys" className="mb-6">
|
||||
API Keys
|
||||
</SectionHeader>
|
||||
|
||||
<div id="key-types" className="mb-8">
|
||||
<SectionHeader level={3} id="key-types" className="mb-4">
|
||||
Key Types
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-6">
|
||||
Banatie supports two types of API keys, each with different permissions and use cases:
|
||||
</p>
|
||||
|
||||
<Table
|
||||
headers={['Key Type', 'Permissions', 'Expiration', 'Use Case']}
|
||||
rows={[
|
||||
[
|
||||
<InlineCode key="type">Master Key</InlineCode>,
|
||||
'Full admin access, can create/revoke keys',
|
||||
<span key="exp" className="text-green-400">Never expires</span>,
|
||||
'Server-side admin operations, key management',
|
||||
],
|
||||
[
|
||||
<InlineCode key="type" color="success">Project Key</InlineCode>,
|
||||
'Image generation only',
|
||||
<span key="exp" className="text-amber-400">90 days</span>,
|
||||
'Application integration, API requests',
|
||||
],
|
||||
]}
|
||||
/>
|
||||
|
||||
<div className="mt-6">
|
||||
<TipBox variant="prominent" type="warning">
|
||||
<strong className="text-amber-300">Master Key Security:</strong> Master keys have full
|
||||
administrative access and never expire. Store them securely in encrypted vaults or
|
||||
secret managers. Never expose master keys in client-side code, logs, or version control.
|
||||
Use project keys for application integration whenever possible.
|
||||
</TipBox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="creating-keys" className="mb-8">
|
||||
<SectionHeader level={3} id="creating-keys" className="mb-4">
|
||||
Creating Keys
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
For first-time setup, use the bootstrap endpoint to create your initial master key:
|
||||
</p>
|
||||
|
||||
<CodeBlock
|
||||
code={`# Bootstrap your first master key (one-time only)
|
||||
curl -X POST https://api.banatie.com/api/bootstrap/initial-key
|
||||
|
||||
# Response
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"key": "bnt_master_abc123...",
|
||||
"type": "master"
|
||||
}
|
||||
}`}
|
||||
language="bash"
|
||||
filename="Bootstrap Master Key"
|
||||
/>
|
||||
|
||||
<div className="mt-6">
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
Once you have a master key, you can create project keys for your applications:
|
||||
</p>
|
||||
|
||||
<CodeBlock
|
||||
code={`# Create a project key with master key authentication
|
||||
curl -X POST https://api.banatie.com/api/admin/keys \\
|
||||
-H "X-API-Key: YOUR_MASTER_KEY" \\
|
||||
-H "Content-Type: application/json" \\
|
||||
-d '{
|
||||
"type": "project",
|
||||
"projectId": "my-app",
|
||||
"name": "Production API Key"
|
||||
}'
|
||||
|
||||
# Response
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"key": "bnt_project_xyz789...",
|
||||
"type": "project",
|
||||
"expiresAt": "2025-04-14T00:00:00Z"
|
||||
}
|
||||
}`}
|
||||
language="bash"
|
||||
filename="Create Project Key"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Using API Keys */}
|
||||
<section id="using-keys" className="mb-12">
|
||||
<SectionHeader level={2} id="using-keys" className="mb-4">
|
||||
Using API Keys
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
Include your API key in the <InlineCode>X-API-Key</InlineCode> header
|
||||
with every request:
|
||||
</p>
|
||||
|
||||
<CodeBlock
|
||||
code={`# Example: Generate an image with project key
|
||||
curl -X POST https://api.banatie.com/api/text-to-image \\
|
||||
-H "X-API-Key: bnt_project_xyz789..." \\
|
||||
-H "Content-Type: application/json" \\
|
||||
-d '{
|
||||
"prompt": "a sunset over the ocean",
|
||||
"aspectRatio": "16:9"
|
||||
}'`}
|
||||
language="bash"
|
||||
filename="Authenticated Request"
|
||||
/>
|
||||
|
||||
<div className="mt-6">
|
||||
<TipBox variant="compact" type="info">
|
||||
<strong>Environment Variables:</strong> Store API keys in environment variables, not
|
||||
hardcoded in your application. Example:{' '}
|
||||
<InlineCode>BANATIE_API_KEY</InlineCode>
|
||||
</TipBox>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Rate Limits */}
|
||||
<section id="rate-limits" className="mb-12">
|
||||
<SectionHeader level={2} id="rate-limits" className="mb-6">
|
||||
Rate Limits
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-6">
|
||||
API keys are subject to rate limits to ensure fair usage and system stability. Limits
|
||||
vary by key type and plan tier:
|
||||
</p>
|
||||
|
||||
<Table
|
||||
headers={['Key Type', 'Rate Limit', 'Reset Window', 'Upgrade Available']}
|
||||
rows={[
|
||||
[
|
||||
<InlineCode key="type">Master Key</InlineCode>,
|
||||
<span key="limit" className="text-green-400">Unlimited</span>,
|
||||
'N/A',
|
||||
'N/A',
|
||||
],
|
||||
[
|
||||
<InlineCode key="type" color="success">Project Key (Free)</InlineCode>,
|
||||
<span key="limit" className="text-amber-400">100 requests/hour</span>,
|
||||
'1 hour rolling',
|
||||
<a key="upgrade" href="/pricing" className="text-purple-400 hover:underline">Yes</a>,
|
||||
],
|
||||
[
|
||||
<InlineCode key="type" color="success">Project Key (Pro)</InlineCode>,
|
||||
<span key="limit" className="text-green-400">1,000 requests/hour</span>,
|
||||
'1 hour rolling',
|
||||
<a key="upgrade" href="/pricing" className="text-purple-400 hover:underline">Yes</a>,
|
||||
],
|
||||
]}
|
||||
/>
|
||||
|
||||
<div className="mt-6">
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
When you exceed rate limits, the API returns a <InlineCode color="error">429 Too Many Requests</InlineCode> status.
|
||||
Check the response headers for retry timing:
|
||||
</p>
|
||||
|
||||
<CodeBlock
|
||||
code={`# Rate limit response headers
|
||||
X-RateLimit-Limit: 100
|
||||
X-RateLimit-Remaining: 0
|
||||
X-RateLimit-Reset: 1704153600
|
||||
|
||||
# Error response body
|
||||
{
|
||||
"error": "Rate limit exceeded",
|
||||
"retryAfter": 3600
|
||||
}`}
|
||||
language="bash"
|
||||
filename="Rate Limit Response"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Security Best Practices */}
|
||||
<section id="security" className="mb-12">
|
||||
<SectionHeader level={2} id="security" className="mb-6">
|
||||
Security Best Practices
|
||||
</SectionHeader>
|
||||
|
||||
<TipBox variant="prominent" type="warning">
|
||||
<strong className="text-amber-300">Critical Security Guidelines:</strong>
|
||||
<ul className="mt-3 space-y-2 list-disc list-inside">
|
||||
<li>Never commit API keys to version control systems (Git, SVN, etc.)</li>
|
||||
<li>Store keys in environment variables or secret management services</li>
|
||||
<li>Use project keys in applications, reserve master keys for admin operations</li>
|
||||
<li>Rotate keys regularly, especially after team member changes</li>
|
||||
<li>Implement server-side API calls for production applications</li>
|
||||
<li>Monitor API key usage in your dashboard for suspicious activity</li>
|
||||
</ul>
|
||||
</TipBox>
|
||||
|
||||
<div className="mt-6">
|
||||
<h3 className="text-lg font-semibold text-white mb-3">Key Rotation Example</h3>
|
||||
<CodeBlock
|
||||
code={`# 1. Create new project key
|
||||
curl -X POST https://api.banatie.com/api/admin/keys \\
|
||||
-H "X-API-Key: YOUR_MASTER_KEY" \\
|
||||
-d '{"type": "project", "projectId": "my-app", "name": "New Key"}'
|
||||
|
||||
# 2. Update your application to use new key
|
||||
export BANATIE_API_KEY="bnt_project_new..."
|
||||
|
||||
# 3. Revoke old key
|
||||
curl -X DELETE https://api.banatie.com/api/admin/keys/OLD_KEY_ID \\
|
||||
-H "X-API-Key: YOUR_MASTER_KEY"`}
|
||||
language="bash"
|
||||
filename="Key Rotation Process"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</DocPage>
|
||||
);
|
||||
}
|
||||
|
|
@ -40,15 +40,15 @@ export default function GettingStartedPage() {
|
|||
'Now that you have generated your first image, explore these resources to build more advanced integrations:',
|
||||
links: [
|
||||
{
|
||||
href: '/docs/api/text-to-image',
|
||||
title: 'API Reference',
|
||||
href: '/docs/api/generate',
|
||||
title: 'Image Generation',
|
||||
description: 'Explore all available endpoints, parameters, and response formats.',
|
||||
accent: 'primary',
|
||||
},
|
||||
{
|
||||
href: '/docs/guides/authentication',
|
||||
title: 'Authentication Guide',
|
||||
description: 'Learn about API keys, rate limits, and security best practices.',
|
||||
href: '/docs/api/live',
|
||||
title: 'Live URLs & CDN',
|
||||
description: 'Generate images on-demand via URL parameters with automatic caching.',
|
||||
accent: 'secondary',
|
||||
},
|
||||
],
|
||||
|
|
@ -67,9 +67,8 @@ export default function GettingStartedPage() {
|
|||
Introduction
|
||||
</SectionHeader>
|
||||
<p className="text-gray-300 leading-relaxed mb-4">
|
||||
Banatie is a developer-first API for AI-powered image generation. Built on Google Gemini
|
||||
2.5 Flash and Imagen 4.0, it transforms text prompts and reference images into
|
||||
production-ready visuals.
|
||||
Banatie is a developer-first API for AI-powered image generation. Built on Google Gemini,
|
||||
it transforms text prompts and reference images into production-ready visuals.
|
||||
</p>
|
||||
<p className="text-gray-300 leading-relaxed mb-6">
|
||||
Whether you are building a content creation platform, e-commerce site, or creative tool,
|
||||
|
|
@ -135,7 +134,7 @@ go get github.com/banatie/sdk-go`}
|
|||
|
||||
<CodeBlock
|
||||
code={`# Create your first API key (one-time bootstrap)
|
||||
curl -X POST https://api.banatie.com/api/bootstrap/initial-key
|
||||
curl -X POST https://api.banatie.app/api/bootstrap/initial-key
|
||||
|
||||
# Save the returned key securely
|
||||
export BANATIE_API_KEY="bnt_your_key_here"`}
|
||||
|
|
@ -156,12 +155,11 @@ export BANATIE_API_KEY="bnt_your_key_here"`}
|
|||
</p>
|
||||
|
||||
<CodeBlock
|
||||
code={`curl -X POST https://api.banatie.com/api/text-to-image \\
|
||||
code={`curl -X POST https://api.banatie.app/api/v1/generations \\
|
||||
-H "X-API-Key: YOUR_API_KEY" \\
|
||||
-H "Content-Type: application/json" \\
|
||||
-d '{
|
||||
"prompt": "a serene mountain landscape at sunset",
|
||||
"filename": "mountain_sunset",
|
||||
"aspectRatio": "16:9",
|
||||
"autoEnhance": true
|
||||
}'`}
|
||||
|
|
@ -173,17 +171,22 @@ export BANATIE_API_KEY="bnt_your_key_here"`}
|
|||
<p className="text-sm font-semibold text-gray-300 mb-3">Expected Response:</p>
|
||||
<ResponseBlock
|
||||
status="success"
|
||||
statusCode={200}
|
||||
statusLabel="✓ 200 Success"
|
||||
statusCode={201}
|
||||
statusLabel="201 Created"
|
||||
content={`{
|
||||
"success": true,
|
||||
"data": {
|
||||
"url": "https://cdn.banatie.com/org/project/generated/2025-01/mountain_sunset.png",
|
||||
"filepath": "org/project/generated/2025-01/mountain_sunset.png",
|
||||
"width": 1920,
|
||||
"height": 1080,
|
||||
"promptEnhancement": {
|
||||
"enhancedPrompt": "A breathtaking mountain landscape..."
|
||||
"id": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"prompt": "A breathtaking mountain landscape at sunset...",
|
||||
"originalPrompt": "a serene mountain landscape at sunset",
|
||||
"autoEnhance": true,
|
||||
"aspectRatio": "16:9",
|
||||
"status": "success",
|
||||
"outputImage": {
|
||||
"id": "7c4ccf47-41ce-4718-afbc-8c553b2c631a",
|
||||
"storageUrl": "https://cdn.banatie.app/default/my-project/img/7c4ccf47-...",
|
||||
"width": 1792,
|
||||
"height": 1024
|
||||
}
|
||||
}
|
||||
}`}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,50 @@
|
|||
import { MetadataRoute } from 'next';
|
||||
|
||||
export default function sitemap(): MetadataRoute.Sitemap {
|
||||
const baseUrl = 'https://banatie.app';
|
||||
|
||||
return [
|
||||
{
|
||||
url: 'https://banatie.app/',
|
||||
url: baseUrl,
|
||||
lastModified: new Date(),
|
||||
changeFrequency: 'weekly',
|
||||
priority: 1,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/docs`,
|
||||
lastModified: new Date(),
|
||||
changeFrequency: 'weekly',
|
||||
priority: 0.9,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/docs/api/generate`,
|
||||
lastModified: new Date(),
|
||||
changeFrequency: 'weekly',
|
||||
priority: 0.8,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/docs/api/advanced`,
|
||||
lastModified: new Date(),
|
||||
changeFrequency: 'weekly',
|
||||
priority: 0.8,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/docs/api/upload`,
|
||||
lastModified: new Date(),
|
||||
changeFrequency: 'weekly',
|
||||
priority: 0.8,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/docs/api/images`,
|
||||
lastModified: new Date(),
|
||||
changeFrequency: 'weekly',
|
||||
priority: 0.8,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/docs/api/live`,
|
||||
lastModified: new Date(),
|
||||
changeFrequency: 'weekly',
|
||||
priority: 0.8,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,9 +19,8 @@
|
|||
*
|
||||
* Navigation Structure:
|
||||
* - Getting Started
|
||||
* - API Reference (collapsible)
|
||||
* - Guides (collapsible)
|
||||
* - Examples
|
||||
* - API Reference (collapsible): Generation, Advanced, Upload, Images, Live URLs
|
||||
* - Guides (collapsible): Authentication, API Keys
|
||||
*/
|
||||
|
||||
import { useState } from 'react';
|
||||
|
|
@ -48,30 +47,17 @@ const navigationItems: NavItem[] = [
|
|||
href: '/docs/api',
|
||||
icon: '📚',
|
||||
children: [
|
||||
{ label: 'Text to Image', href: '/docs/api/text-to-image' },
|
||||
{ label: 'Upload', href: '/docs/api/upload' },
|
||||
{ label: 'Images', href: '/docs/api/images' },
|
||||
{ label: 'Image Generation', href: '/docs/api/generate' },
|
||||
{ label: 'Advanced Generation', href: '/docs/api/advanced' },
|
||||
{ label: 'Image Upload', href: '/docs/api/upload' },
|
||||
{ label: 'Image Management', href: '/docs/api/images' },
|
||||
{ label: 'Live URLs', href: '/docs/api/live' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Guides',
|
||||
href: '/docs/guides',
|
||||
icon: '📖',
|
||||
children: [
|
||||
{ label: 'Authentication', href: '/docs/guides/authentication' },
|
||||
{ label: 'Error Handling', href: '/docs/guides/error-handling' },
|
||||
{ label: 'Rate Limits', href: '/docs/guides/rate-limits' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Examples',
|
||||
href: '/docs/examples',
|
||||
icon: '💡',
|
||||
},
|
||||
];
|
||||
|
||||
export const DocsSidebar = ({ currentPath }: DocsSidebarProps) => {
|
||||
const [expandedSections, setExpandedSections] = useState<string[]>(['API Reference', 'Guides']);
|
||||
const [expandedSections, setExpandedSections] = useState<string[]>(['API Reference']);
|
||||
|
||||
const toggleSection = (label: string) => {
|
||||
setExpandedSections((prev) =>
|
||||
|
|
|
|||
Loading…
Reference in New Issue