curl --request POST \
--url 'https://api.apimart.ai/v1/uploads/images?retention_days=3' \
--header 'Authorization: Bearer <token>' \
--form 'file=@/path/to/reference.png'
import requests
with open("reference.png", "rb") as file:
response = requests.post(
"https://api.apimart.ai/v1/uploads/images?retention_days=3",
headers={"Authorization": "Bearer <token>"},
files={"file": file}
)
response.raise_for_status()
result = response.json()
print(result["url"])
const input = document.querySelector('input[type="file"]');
const file = input?.files?.[0];
if (!file) throw new Error("Select a file first");
const formData = new FormData();
formData.append("file", file, file.name);
const response = await fetch("https://api.apimart.ai/v1/uploads/images?retention_days=3", {
method: "POST",
headers: { Authorization: "Bearer <token>" },
body: formData
});
const result = await response.json();
if (!response.ok) {
throw new Error(result.error?.message ?? `HTTP ${response.status}`);
}
console.log(result.url);
{
"url": "https://cdn.example/uploads/reference.png",
"filename": "reference.png",
"content_type": "image/png",
"file_type": "image",
"bytes": 235680,
"created_at": 1793836800,
"retention_days": 3,
"expires_at": 1794182400
}
{
"error": {
"message": "insufficient balance: uploading files requires a positive account balance, please top up",
"type": "insufficient_user_quota"
}
}
{
"error": {
"message": "image file exceeds maximum 31457280 bytes (30MB)",
"type": "invalid_request_error"
}
}
업로드 관리
이미지 업로드
JPEG, PNG, GIF, WebP 이미지를 업로드하고 생성 API에 사용할 공개 URL을 받습니다. 기본 파일당 한도는 30MB입니다.
POST
/
v1
/
uploads
/
images
curl --request POST \
--url 'https://api.apimart.ai/v1/uploads/images?retention_days=3' \
--header 'Authorization: Bearer <token>' \
--form 'file=@/path/to/reference.png'
import requests
with open("reference.png", "rb") as file:
response = requests.post(
"https://api.apimart.ai/v1/uploads/images?retention_days=3",
headers={"Authorization": "Bearer <token>"},
files={"file": file}
)
response.raise_for_status()
result = response.json()
print(result["url"])
const input = document.querySelector('input[type="file"]');
const file = input?.files?.[0];
if (!file) throw new Error("Select a file first");
const formData = new FormData();
formData.append("file", file, file.name);
const response = await fetch("https://api.apimart.ai/v1/uploads/images?retention_days=3", {
method: "POST",
headers: { Authorization: "Bearer <token>" },
body: formData
});
const result = await response.json();
if (!response.ok) {
throw new Error(result.error?.message ?? `HTTP ${response.status}`);
}
console.log(result.url);
{
"url": "https://cdn.example/uploads/reference.png",
"filename": "reference.png",
"content_type": "image/png",
"file_type": "image",
"bytes": 235680,
"created_at": 1793836800,
"retention_days": 3,
"expires_at": 1794182400
}
{
"error": {
"message": "insufficient balance: uploading files requires a positive account balance, please top up",
"type": "insufficient_user_quota"
}
}
{
"error": {
"message": "image file exceeds maximum 31457280 bytes (30MB)",
"type": "invalid_request_error"
}
}
참조 파일을 업로드하면 공개 URL이 바로 반환되며 폴링은 필요하지 않습니다. 보관 기간은 3, 7, 15, 30일입니다. 3일 보관은 계정 무료 한도 내에서 무료이며, 초과분과 장기 보관에는 유료 업로드 활성화가 필요합니다. 실제 무료 한도와 사용 가능한 옵션은 콘솔에서 확인하세요.
문서 Playground는 파일 업로드를 지원하지 않습니다. 아래 cURL, Python, JavaScript 예제를 사용하세요. JavaScript 예제에는 파일을 선택한
<input type="file"> 요소가 필요합니다.curl --request POST \
--url 'https://api.apimart.ai/v1/uploads/images?retention_days=3' \
--header 'Authorization: Bearer <token>' \
--form 'file=@/path/to/reference.png'
import requests
with open("reference.png", "rb") as file:
response = requests.post(
"https://api.apimart.ai/v1/uploads/images?retention_days=3",
headers={"Authorization": "Bearer <token>"},
files={"file": file}
)
response.raise_for_status()
result = response.json()
print(result["url"])
const input = document.querySelector('input[type="file"]');
const file = input?.files?.[0];
if (!file) throw new Error("Select a file first");
const formData = new FormData();
formData.append("file", file, file.name);
const response = await fetch("https://api.apimart.ai/v1/uploads/images?retention_days=3", {
method: "POST",
headers: { Authorization: "Bearer <token>" },
body: formData
});
const result = await response.json();
if (!response.ok) {
throw new Error(result.error?.message ?? `HTTP ${response.status}`);
}
console.log(result.url);
{
"url": "https://cdn.example/uploads/reference.png",
"filename": "reference.png",
"content_type": "image/png",
"file_type": "image",
"bytes": 235680,
"created_at": 1793836800,
"retention_days": 3,
"expires_at": 1794182400
}
{
"error": {
"message": "insufficient balance: uploading files requires a positive account balance, please top up",
"type": "insufficient_user_quota"
}
}
{
"error": {
"message": "image file exceeds maximum 31457280 bytes (30MB)",
"type": "invalid_request_error"
}
}
인증
활성 상태이며 만료되지 않은 유효한 APIMart API Key를
Bearer <token> 형식으로 사용하세요. 계정은 정지되지 않아야 하며 잔액이 양수여야 합니다. 유료 업로드에는 해당 비용을 지불할 충분한 계정 잔액과 API Key의 남은 사용 금액 한도가 필요합니다. 무료 파일 한도와 Key의 지출 한도는 별개입니다. API Key 관리에서 Key를 발급받을 수 있습니다.요청 매개변수
선택 사항이며
3, 7, 15, 30일을 지원합니다. 지정하면 계정 기본값을 덮어씁니다. 생략하면 콘솔에서 현재 적용 중인 기본값을 사용하므로 항상 3일인 것은 아닙니다. URL 쿼리 매개변수만 적용되며 같은 이름의 폼 필드는 무시됩니다. 사용 가능한 옵션은 콘솔을 확인하세요.multipart/form-data의 file 필드에 파일명과 함께 파일 하나를 전송하세요. 파일 부분을 JSON, base64 문자열, 파일 URL로 대체하지 마세요. 다른 폼 필드는 무시하며 여러 file 부분을 보내면 첫 번째만 처리합니다.지원 형식: JPEG (.jpg, .jpeg), PNG (.png), GIF (.gif), WebP (.webp)기본 파일 크기 상한: 30MB. 크기 상한은 설정에 따라 변경될 수 있습니다. 실제 서비스 설정과 크기 초과 오류의 값을 기준으로 하세요.--form, Python files, JavaScript FormData를 사용할 때는 클라이언트가 boundary를 포함한 Content-Type을 생성하도록 두세요. 이 헤더를 직접 설정하지 마세요.
파일 검증
확장자나 클라이언트가 지정한 MIME 유형이 아닌 실제 내용으로 형식을 판별합니다. 내용은 업로드 API 종류와 일치해야 합니다. 이름을 바꿔도 형식이 변환되지 않으며 유형 불일치는 HTTP400을 반환합니다.
이미지 전체가 디코딩되어야 하며 총 40MP 이하, 각 변 32768픽셀 이하여야 합니다. GIF는 최대 500프레임입니다.
| 형식 | 감지된 MIME 유형 |
|---|---|
| JPEG (.jpg, .jpeg) | image/jpeg |
| PNG (.png) | image/png |
| GIF (.gif) | image/gif |
| WebP (.webp) | image/webp |
보관 기간과 유료 업로드 설정
| 보관 옵션 | 과금 규칙 | 무료 한도 |
|---|---|---|
| 3일 | 무료 한도 내에서는 무료입니다. 초과 시 유료 업로드를 활성화하고 해당 가격을 확인하면 실제 파일 크기로 과금합니다. | 계정 공용 무료 한도를 사용합니다. |
| 7 / 15 / 30일 | 무료 한도 잔여량과 무관하게 모든 파일에 선택한 옵션의 요금을 부과합니다. | 무료 한도를 사용하지 않습니다. |
기본값이 7, 15, 30일이면
retention_days를 생략해도 무료 한도가 남아 있는지와 관계없이 파일마다 과금됩니다. 해당 요청에 3일 규칙을 적용하려면 retention_days=3을 지정하세요. 위 요청 예제는 모두 3일을 명시합니다.curl --request POST \
--url 'https://api.apimart.ai/v1/uploads/images?retention_days=7' \
--header 'Authorization: Bearer <token>' \
--form 'file=@/path/to/reference.png'
성공 응답
HTTP200으로 파일 정보를 반환합니다. url은 JSON 최상위에 있으며 data 래퍼나 생성 작업 ID는 없습니다.
응답 예제는 파일 정보만 표시하며 선택 필드인 quota와 overage는 생략합니다. 반환 조건은 아래 설명을 참고하세요.
파일 공개 URL입니다. 대상 생성 API의 해당 참조 매개변수에 전달하세요. 모델별 형식, 크기, 수량, 길이 제한이 별도로 적용되므로 업로드 성공이 모델 호환성을 보장하지는 않습니다.
과금된 업로드에만 반환됩니다. 3일 옵션의 초과 업로드 또는 모든 7 / 15 / 30일 업로드가 대상입니다.
charged는 과금 여부, bytes는 과금 파일 바이트 수, cost_usd는 이번 요금(USD), price_per_gb_usd는 GB당 단가, retention_days는 과금 옵션입니다. 무료 업로드에서는 생략됩니다.계정 공용 무료 한도 정보이며 선택 필드입니다. 3일 옵션에서 반환되며 장기 보관은 무료 한도를 사용하지 않아 생략합니다. 무제한 계정과 통계 조회 불가 시 동작은 아래를 참고하세요.
| 필드 | 설명 |
|---|---|
quota.limit | 통계 기간 내 계정의 무료 파일 한도입니다. 실제 반환값이나 콘솔을 기준으로 하며, 유료 업로드 활성화 후의 총 업로드 상한이 아닙니다. |
quota.used | 기간 내 집계된 3일 옵션 업로드 수로 이번 성공분을 포함합니다. |
quota.remaining | 남은 무료 파일 수입니다. |
quota.window_hours | 통계 기간(시간). 기본값은 72입니다. |
quota.reset_at | 가장 오래된 기록이 기간에서 빠지는 Unix 시각(초). 일부 한도가 복구되는 시점이며 전체 한도의 일괄 초기화가 아닙니다. |
공유 할당량과 요청 속도 제한
이미지, 영상, 오디오 API는 계정의 무료 한도를 공유하며 API Key가 여러 개여도 합산되지 않습니다. 기간은 매 정시에 이동하며 기본적으로 최근 약 71–72시간의 3일 옵션 성공 업로드를 집계합니다. 장기 보관, 형식 오류, 크기 초과, 저장 실패는 무료 한도를 사용하지 않습니다. 실제 한도는 콘솔 또는quota.limit를 확인하세요.
3일 옵션의 일반 한도 응답에는 X-Upload-Quota-Limit, X-Upload-Quota-Remaining, X-Upload-Quota-Reset이 포함되며 각각 limit, remaining, reset_at에 대응합니다. Reset은 Unix 초입니다. 무제한 계정은 quota: {"unlimited": true}를 반환하고 세 헤더는 생략합니다.
통계를 일시적으로 조회할 수 없으면 성공 응답에도 quota가 없을 수 있으며, 장기 보관에서도 생략합니다. 필드가 없다고 0이나 무제한으로 해석하거나 재업로드하지 마세요.
3일 무료 한도를 소진해도 유료 업로드가 활성화되고 해당 가격을 확인했다면 유료로 계속 업로드할 수 있습니다. 그 외에는 아래 429 처리를 따르세요. 별도로 Key당 60초에 1000회 요청 제한이 있으며 rate_limit_error에 해당합니다. 무료 파일 한도와는 별개입니다.
오류 처리
오류는 최상위error에 포함됩니다. HTTP 상태, error.type / error.code, 최상위 overage 필드를 함께 확인하고 언어에 따라 달라지는 error.message에만 의존하지 마세요. 오류의 overage는 성공 시 과금 정보와 다르며 available, enabled, needs_reconfirm, retention_days, price_per_gb_usd, 선택적인 settings_url 및 reason을 포함할 수 있습니다. 활성화와 가격 재확인은 콘솔에서 진행하세요.
| HTTP | 필드 / 조건 | 원인 및 처리 |
|---|---|---|
| 400 | invalid_request_error | 파일 누락, multipart가 아닌 요청, 빈 파일, 유형 불일치, 지원하지 않는 형식, 손상된 내용입니다. 파일이나 API 경로를 수정하세요. |
| 400 | retention_days | 보관 기간이 잘못되었거나 해당 옵션을 사용할 수 없습니다. 쿼리와 콘솔의 사용 가능한 옵션을 확인하세요. |
| 401 / 403 | — | 유효하지 않거나 비활성화된 Key, 또는 정지된 계정입니다. 인증과 계정 상태를 확인하세요. |
| 402 | insufficient_user_quota | 계정 잔액이 0 이하이거나 Key가 만료되었습니다. 충전하거나 유효한 Key를 사용하세요. 무료 업로드도 이용 조건을 충족해야 합니다. |
| 402 | overage.reason = overage_not_enabled | 장기 보관을 선택했지만 유료 업로드가 꺼져 있습니다. 콘솔에서 활성화하고 가격을 확인하세요. |
| 402 | overage.reason = needs_reconfirm | 장기 보관 가격이 미확인 상태이거나 인상 후 재확인하지 않았습니다. 현재 가격을 확인하세요. |
| 402 | overage.reason = insufficient_balance | 이번 업로드 비용을 지불할 계정 잔액이 부족합니다. 충전 후 재시도하세요. |
| 402 | overage.reason = insufficient_key_quota | API Key에 지출 상한이 설정되어 있으며 남은 금액이 부족합니다. Key 한도를 조정하세요. |
| 413 | invalid_request_error | 유형별 파일 크기 한도를 초과했습니다. 압축하거나 크기를 줄이고 오류에 표시된 현재 한도를 확인하세요. |
| 429 | rate_limit_error | Key의 요청이 너무 잦습니다. 요청 빈도를 낮추고 대기 시간을 두어 재시도하세요. |
| 429 | overage.enabled = false | 3일 무료 한도를 소진했고 유료 업로드가 꺼져 있습니다. 콘솔에서 켜고 가격을 확인하거나 Retry-After에 따라 무료 한도가 복구될 때까지 기다리세요. |
| 429 | overage.needs_reconfirm = true | 3일 옵션의 가격 확인이 필요합니다. 콘솔에서 재확인 후 재시도하세요. |
| 429 | error.type = rate_limit_exceeded | 무료 한도를 소진했습니다. overage가 없으면 error.message에 따르세요. 유료 업로드를 사용할 수 없는 경우일 수 있습니다. 무료 한도를 기다리려면 Retry-After의 초 단위 대기 시간을 따르세요. |
| 500 | server_error | 저장소에 파일을 쓰지 못했습니다. 나중에 다시 시도하세요. |
| 503 | Retry-After | 과금 또는 계정 한도 조회가 일시적으로 불가능합니다. 헤더에 지정된 초만큼 기다린 후 재시도하세요. 이번 실패에는 과금하지 않습니다. |
URL 사용 및 파일 보관
무료 한도의 72시간 집계 기간과 파일 보관 기간은 별개입니다. 선택한 옵션에 따라 파일이 만료되며 실제 시각은expires_at을 기준으로 합니다. 만료 후 URL은 404를 반환합니다. 원본을 보관하고 URL이 영구적이라고 가정하지 마세요.
대량 업로드에는 자체 객체 스토리지(OSS)를 권장합니다. 모델이 공개 파일 URL을 지원한다면 자체 저장소 링크를 직접 사용하여 반복 업로드와 저장 비용을 줄일 수 있습니다.