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:',
|
'Now that you have generated your first image, explore these resources to build more advanced integrations:',
|
||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
href: '/docs/api/text-to-image',
|
href: '/docs/api/generate',
|
||||||
title: 'API Reference',
|
title: 'Image Generation',
|
||||||
description: 'Explore all available endpoints, parameters, and response formats.',
|
description: 'Explore all available endpoints, parameters, and response formats.',
|
||||||
accent: 'primary',
|
accent: 'primary',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: '/docs/guides/authentication',
|
href: '/docs/api/live',
|
||||||
title: 'Authentication Guide',
|
title: 'Live URLs & CDN',
|
||||||
description: 'Learn about API keys, rate limits, and security best practices.',
|
description: 'Generate images on-demand via URL parameters with automatic caching.',
|
||||||
accent: 'secondary',
|
accent: 'secondary',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
@ -67,9 +67,8 @@ export default function GettingStartedPage() {
|
||||||
Introduction
|
Introduction
|
||||||
</SectionHeader>
|
</SectionHeader>
|
||||||
<p className="text-gray-300 leading-relaxed mb-4">
|
<p className="text-gray-300 leading-relaxed mb-4">
|
||||||
Banatie is a developer-first API for AI-powered image generation. Built on Google Gemini
|
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
|
it transforms text prompts and reference images into production-ready visuals.
|
||||||
production-ready visuals.
|
|
||||||
</p>
|
</p>
|
||||||
<p className="text-gray-300 leading-relaxed mb-6">
|
<p className="text-gray-300 leading-relaxed mb-6">
|
||||||
Whether you are building a content creation platform, e-commerce site, or creative tool,
|
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
|
<CodeBlock
|
||||||
code={`# Create your first API key (one-time bootstrap)
|
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
|
# Save the returned key securely
|
||||||
export BANATIE_API_KEY="bnt_your_key_here"`}
|
export BANATIE_API_KEY="bnt_your_key_here"`}
|
||||||
|
|
@ -156,12 +155,11 @@ export BANATIE_API_KEY="bnt_your_key_here"`}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<CodeBlock
|
<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 "X-API-Key: YOUR_API_KEY" \\
|
||||||
-H "Content-Type: application/json" \\
|
-H "Content-Type: application/json" \\
|
||||||
-d '{
|
-d '{
|
||||||
"prompt": "a serene mountain landscape at sunset",
|
"prompt": "a serene mountain landscape at sunset",
|
||||||
"filename": "mountain_sunset",
|
|
||||||
"aspectRatio": "16:9",
|
"aspectRatio": "16:9",
|
||||||
"autoEnhance": true
|
"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>
|
<p className="text-sm font-semibold text-gray-300 mb-3">Expected Response:</p>
|
||||||
<ResponseBlock
|
<ResponseBlock
|
||||||
status="success"
|
status="success"
|
||||||
statusCode={200}
|
statusCode={201}
|
||||||
statusLabel="✓ 200 Success"
|
statusLabel="201 Created"
|
||||||
content={`{
|
content={`{
|
||||||
"success": true,
|
"success": true,
|
||||||
"data": {
|
"data": {
|
||||||
"url": "https://cdn.banatie.com/org/project/generated/2025-01/mountain_sunset.png",
|
"id": "550e8400-e29b-41d4-a716-446655440000",
|
||||||
"filepath": "org/project/generated/2025-01/mountain_sunset.png",
|
"prompt": "A breathtaking mountain landscape at sunset...",
|
||||||
"width": 1920,
|
"originalPrompt": "a serene mountain landscape at sunset",
|
||||||
"height": 1080,
|
"autoEnhance": true,
|
||||||
"promptEnhancement": {
|
"aspectRatio": "16:9",
|
||||||
"enhancedPrompt": "A breathtaking mountain landscape..."
|
"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';
|
import { MetadataRoute } from 'next';
|
||||||
|
|
||||||
export default function sitemap(): MetadataRoute.Sitemap {
|
export default function sitemap(): MetadataRoute.Sitemap {
|
||||||
|
const baseUrl = 'https://banatie.app';
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
url: 'https://banatie.app/',
|
url: baseUrl,
|
||||||
lastModified: new Date(),
|
lastModified: new Date(),
|
||||||
changeFrequency: 'weekly',
|
changeFrequency: 'weekly',
|
||||||
priority: 1,
|
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:
|
* Navigation Structure:
|
||||||
* - Getting Started
|
* - Getting Started
|
||||||
* - API Reference (collapsible)
|
* - API Reference (collapsible): Generation, Advanced, Upload, Images, Live URLs
|
||||||
* - Guides (collapsible)
|
* - Guides (collapsible): Authentication, API Keys
|
||||||
* - Examples
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
@ -48,30 +47,17 @@ const navigationItems: NavItem[] = [
|
||||||
href: '/docs/api',
|
href: '/docs/api',
|
||||||
icon: '📚',
|
icon: '📚',
|
||||||
children: [
|
children: [
|
||||||
{ label: 'Text to Image', href: '/docs/api/text-to-image' },
|
{ label: 'Image Generation', href: '/docs/api/generate' },
|
||||||
{ label: 'Upload', href: '/docs/api/upload' },
|
{ label: 'Advanced Generation', href: '/docs/api/advanced' },
|
||||||
{ label: 'Images', href: '/docs/api/images' },
|
{ 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) => {
|
export const DocsSidebar = ({ currentPath }: DocsSidebarProps) => {
|
||||||
const [expandedSections, setExpandedSections] = useState<string[]>(['API Reference', 'Guides']);
|
const [expandedSections, setExpandedSections] = useState<string[]>(['API Reference']);
|
||||||
|
|
||||||
const toggleSection = (label: string) => {
|
const toggleSection = (label: string) => {
|
||||||
setExpandedSections((prev) =>
|
setExpandedSections((prev) =>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue