Fellowi

개발자를 위한 NSFW 이미지 생성 API

Fellowi 팀 작성 · · 7 분 소요

AI 이미지 생성을 위한 개발자용 API를 상징하는 어두운 보라색에서 인디고로 이어지는 그라데이션 아트워크.

대부분의 이미지 생성 API는 기술적인 한계에 이르기도 전에 정책상 NSFW 콘텐츠를 아예 거부합니다. 범용 플랫폼으로서는 합리적인 선택이지만, 성인용 콘텐츠를 허용하는 생성기에 프로그램 방식으로 접근해야 하는 개발자에게는 남는 선택지가 거의 없습니다. Fellowi의 공개 API는 바로 이런 경우를 위해 존재합니다. 등록된 성인 계정에 한해 노골적인 생성을 허용하되, 절대 바뀌지 않는 엄격한 제한 아래에서입니다: 미성년자가 등장하는 콘텐츠, 동의 없는 행위를 묘사하는 콘텐츠는 어느 쪽도 허용되지 않습니다. 이는 껐다 켤 수 있는 설정이 아니라, 예외 없이 거부됩니다.

그 외에는 평범한 REST API입니다: 키, 작업을 대기열에 넣는 POST, 폴링, 다운로드. 다른 비동기 생성 API를 사용해본 적이 있다면 익숙하게 느껴질 것입니다.

키 발급받기

계정을 만든 다음 API 콘솔에서 API 키를 생성하세요. 키는 fk_live_<임의의 문자열> 형태이며, 생성 시 딱 한 번 전체가 표시됩니다. 그 이후로는 저희 쪽에는 해시와 짧은 미리보기만 저장됩니다 - 잃어버렸다면 폐기하고 새로 만드세요, 지금까지 다뤄본 다른 어떤 API 키와도 마찬가지입니다. 탭을 닫기 전에 반드시 안전한 곳에 저장하세요.

모든 요청은 표준 bearer 헤더로 인증합니다:

Authorization: Bearer fk_live_your_key_here

생성 작업을 대기열에 넣기

POST /v1/api/images에 프롬프트와 옵션을 담아 보냅니다. 호출은 즉시 HTTP 202를 반환하며, 렌더링이 끝날 때까지 블록되지 않습니다:

POST /v1/api/images
Content-Type: application/json
Authorization: Bearer fk_live_your_key_here
Idempotency-Key: a-key-you-generate-per-attempt

{
  "prompt": "a neon-lit rooftop at night, wide shot, cinematic lighting",
  "quality": "standard",
  "format": "png",
  "aspectRatio": "16:9"
}

응답에는 작업 id, etaMs 예상 시간, 그리고 차감 후 남은 코인 잔액이 담깁니다. 선택적인 Idempotency-Key 헤더를 사용하면 재시도가 안전해집니다 - 재시도 시 같은 키를 보내면 같은 시도에 대해 두 번 차감되지 않습니다.

작업 본체는 image 아래에 있고, 그 옆에 지갑 잔액이 함께 담깁니다:

{
  "image": { "id": "0f9c...", "status": "queued", "etaMs": 42000, "coinsCharged": 40 },
  "coins": 360
}

폴링 후 다운로드

GET /v1/api/images/:idstatus"succeeded" 또는 "failed"가 될 때까지 폴링합니다. 성공하면 GET /v1/api/images/:id/content에서 실제 바이트를 가져옵니다. 실패하면 사용한 코인은 자동으로 환불되며, failureCode는 항상 정확히 네 가지 값 중 하나입니다: TIMEOUT, MODERATION_REJECTED, VENDOR_ERROR, UNKNOWN. 처리해야 할 다섯 번째 코드도 없고, 대조해야 할 부분 차감도 없습니다 - 왜 이렇게 설계했는지는 API 가격 정책과 생성 실패 처리에 관한 글에서 더 자세히 다룹니다.

curl, 처음부터 끝까지

API_KEY="fk_live_your_key_here"

# 1. 작업을 대기열에 넣기
JOB=$(curl -s https://fellowi.com/api/v1/api/images \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt":"a neon-lit rooftop at night","quality":"standard","format":"png","aspectRatio":"16:9"}')
ID=$(echo "$JOB" | jq -r .image.id)

# 2. 완료될 때까지 폴링
while true; do
  STATUS=$(curl -s https://fellowi.com/api/v1/api/images/$ID \
    -H "Authorization: Bearer $API_KEY" | jq -r .image.status)
  [ "$STATUS" = "succeeded" ] && break
  [ "$STATUS" = "failed" ] && { echo "generation failed"; exit 1; }
  sleep 3
done

# 3. 이미지 다운로드
curl -s https://fellowi.com/api/v1/api/images/$ID/content \
  -H "Authorization: Bearer $API_KEY" -o output.png

Node

const API_KEY = process.env.FELLOWI_API_KEY;
const base = "https://fellowi.com/api/v1/api";
const headers = { Authorization: `Bearer ${API_KEY}` };

const create = await fetch(`${base}/images`, {
  method: "POST",
  headers: { ...headers, "Content-Type": "application/json" },
  body: JSON.stringify({ prompt: "a neon-lit rooftop at night", quality: "standard", format: "png", aspectRatio: "16:9" }),
});
const { image } = await create.json();
const id = image.id;

let job;
do {
  await new Promise((r) => setTimeout(r, 3000));
  job = await fetch(`${base}/images/${id}`, { headers }).then((r) => r.json());
} while (job.image.status !== "succeeded" && job.image.status !== "failed");

if (job.image.status === "failed") throw new Error(job.image.failureCode);

const bytes = await fetch(`${base}/images/${id}/content`, { headers }).then((r) => r.arrayBuffer());
await Bun.write("output.png", bytes);

Python

import os, time, requests

API_KEY = os.environ["FELLOWI_API_KEY"]
base = "https://fellowi.com/api/v1/api"
headers = {"Authorization": f"Bearer {API_KEY}"}

job = requests.post(f"{base}/images", headers=headers, json={
    "prompt": "a neon-lit rooftop at night",
    "quality": "standard",
    "format": "png",
    "aspectRatio": "16:9",
}).json()

while True:
    time.sleep(3)
    status = requests.get(f"{base}/images/{job['image']['id']}", headers=headers).json()
    if status["image"]["status"] in ("succeeded", "failed"):
        break

if status["image"]["status"] == "failed":
    raise RuntimeError(status["image"]["failureCode"])

content = requests.get(f"{base}/images/{job['image']['id']}/content", headers=headers)
open("output.png", "wb").write(content.content)

모델, 가격, 제한

모든 응답은 모델을 fellowi-nsfw-image-1로 표시합니다. 표시되는 이름은 이것 하나뿐입니다 - 웹 앱 Fellowi Images를 지원하는 것과 같은 생성기이며, 같은 Fellowi 코인 지갑에서 같은 가격으로 청구됩니다: 표준(1.5K) 이미지는 40코인, 고화질(2K)은 60코인입니다. 웹 앱과 따로 맞춰봐야 할 별도의 API 가격표는 없습니다.

속도 제한은 남용을 막기 위한 것이지 실제 상한선이 아닙니다 - 기본값은 생성 호출 분당 20건, 읽기 호출 분당 120건입니다. GET /v1/api/me는 현재 코인 잔액, 키의 속도 제한, 그리고 일일 한도 내에서 오늘 남은 이미지 수를 반환합니다 - 한도에 부딪힌 후가 아니라 배치를 보내기 전에 확인하세요.

전체 참조 문서, 실시간 가격, 키 관리는 모두 API 콘솔에 있습니다.

직접 경험해보세요

따뜻하고 사적인 AI 컴패니언. 7일 무료, 메시지 30개, 카드 불필요.

요금과 한도

계속 읽기