curl --request POST 'https://api.voicecheap.ai/v1/actions/thumbnails_upload_complete' \
--header "x-api-key: $VOICECHEAP_API_KEY" \
--header 'Content-Type: application/json' \
--data '{"requestId":"ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a","uploadId":"c547fb7f-f334-46a8-a8bb-80b5b343889a","parts":[{"partNumber":1,"etag":"\"d41d8cd98f00b204e9800998ecf8427e\""},{"partNumber":2,"etag":"\"0cc175b9c0f1b6a831c399e269772661\""}]}'
const input = {
requestId: 'ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a',
uploadId: 'c547fb7f-f334-46a8-a8bb-80b5b343889a',
parts: [
{
partNumber: 1,
etag: '"d41d8cd98f00b204e9800998ecf8427e"',
},
{
partNumber: 2,
etag: '"0cc175b9c0f1b6a831c399e269772661"',
},
],
};
const response = await fetch('https://api.voicecheap.ai/v1/actions/thumbnails_upload_complete', {
method: 'POST',
headers: {
'x-api-key': process.env.VOICECHEAP_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify(input),
});
const body = await response.json();
if (!response.ok) throw new Error(body.code + ': ' + body.message);
console.log(body);
import os
import requests
response = requests.post(
"https://api.voicecheap.ai/v1/actions/thumbnails_upload_complete",
headers={"x-api-key": os.environ["VOICECHEAP_API_KEY"]},
json={"requestId": "ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a", "uploadId": "c547fb7f-f334-46a8-a8bb-80b5b343889a", "parts": [{"partNumber": 1, "etag": "\"d41d8cd98f00b204e9800998ecf8427e\""}, {"partNumber": 2, "etag": "\"0cc175b9c0f1b6a831c399e269772661\""}]},
timeout=120,
)
body = response.json()
if not response.ok:
raise RuntimeError(f"{body.get('code')}: {body.get('message')}")
print(body)
{
"data": {
"fileKey": "uploads/example-user/2502829e-3fde-4aad-b3c7-ce0f779fa2e6-reference.png",
"readUrl": "https://media.example.com/uploads/example-user/2502829e-3fde-4aad-b3c7-ce0f779fa2e6-reference.png"
},
"requestId": "ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a"
}
{
"data": {
"requestId": "ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a",
"operation": "thumbnails_upload_complete",
"createdAt": 1792144800000,
"updatedAt": 1792144820000,
"status": "running",
"pollAfterSeconds": 5
},
"requestId": "ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a"
}
{
"data": {
"requestId": "ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a",
"operation": "thumbnails_upload_complete",
"createdAt": 1792144800000,
"updatedAt": 1792144820000,
"status": "completed",
"resultStored": false,
"message": "The action completed. Retrieve its output from the corresponding history or resource action."
},
"requestId": "ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a"
}
Miniatury
Zakończ przesyłanie obrazu referencyjnego miniatury
Zakończ należące do Ciebie przesyłanie obrazu referencyjnego, używając numerów części i ETag z żądań PUT. Sprawdza rozmiar zapisanego pliku. Użyj zwróconego fileKey jako obrazu referencyjnego do generowania.
POST
/
v1
/
actions
/
thumbnails_upload_complete
curl --request POST 'https://api.voicecheap.ai/v1/actions/thumbnails_upload_complete' \
--header "x-api-key: $VOICECHEAP_API_KEY" \
--header 'Content-Type: application/json' \
--data '{"requestId":"ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a","uploadId":"c547fb7f-f334-46a8-a8bb-80b5b343889a","parts":[{"partNumber":1,"etag":"\"d41d8cd98f00b204e9800998ecf8427e\""},{"partNumber":2,"etag":"\"0cc175b9c0f1b6a831c399e269772661\""}]}'
const input = {
requestId: 'ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a',
uploadId: 'c547fb7f-f334-46a8-a8bb-80b5b343889a',
parts: [
{
partNumber: 1,
etag: '"d41d8cd98f00b204e9800998ecf8427e"',
},
{
partNumber: 2,
etag: '"0cc175b9c0f1b6a831c399e269772661"',
},
],
};
const response = await fetch('https://api.voicecheap.ai/v1/actions/thumbnails_upload_complete', {
method: 'POST',
headers: {
'x-api-key': process.env.VOICECHEAP_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify(input),
});
const body = await response.json();
if (!response.ok) throw new Error(body.code + ': ' + body.message);
console.log(body);
import os
import requests
response = requests.post(
"https://api.voicecheap.ai/v1/actions/thumbnails_upload_complete",
headers={"x-api-key": os.environ["VOICECHEAP_API_KEY"]},
json={"requestId": "ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a", "uploadId": "c547fb7f-f334-46a8-a8bb-80b5b343889a", "parts": [{"partNumber": 1, "etag": "\"d41d8cd98f00b204e9800998ecf8427e\""}, {"partNumber": 2, "etag": "\"0cc175b9c0f1b6a831c399e269772661\""}]},
timeout=120,
)
body = response.json()
if not response.ok:
raise RuntimeError(f"{body.get('code')}: {body.get('message')}")
print(body)
{
"data": {
"fileKey": "uploads/example-user/2502829e-3fde-4aad-b3c7-ce0f779fa2e6-reference.png",
"readUrl": "https://media.example.com/uploads/example-user/2502829e-3fde-4aad-b3c7-ce0f779fa2e6-reference.png"
},
"requestId": "ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a"
}
{
"data": {
"requestId": "ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a",
"operation": "thumbnails_upload_complete",
"createdAt": 1792144800000,
"updatedAt": 1792144820000,
"status": "running",
"pollAfterSeconds": 5
},
"requestId": "ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a"
}
{
"data": {
"requestId": "ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a",
"operation": "thumbnails_upload_complete",
"createdAt": 1792144800000,
"updatedAt": 1792144820000,
"status": "completed",
"resultStored": false,
"message": "The action completed. Retrieve its output from the corresponding history or resource action."
},
"requestId": "ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a"
}
Zakończ należące do Ciebie przesyłanie obrazu referencyjnego, używając numerów części i ETag z żądań PUT. Sprawdza rozmiar zapisanego pliku. Użyj zwróconego fileKey jako obrazu referencyjnego do generowania.
Wymagane uprawnienia:
POST https://api.voicecheap.ai/v1/actions/thumbnails_upload_complete
Uwierzytelnianie i uprawnienia
string
wymagane
Wyślij klucz API VoiceCheap w tym nagłówku. Obsługiwany jest również nagłówek Authorization: Bearer z tym samym kluczem API. Tokeny dostępu OAuth są
akceptowane tylko przez MCP, a nie przez ten endpoint REST.
thumbnails:write.
Wymagana jest aktywna płatna subskrypcja. Uprawnienia nie zmieniają ról w zespole, własności zasobów, kredytów na multimedia ani limitów planu.
Parametry
string
Opcjonalne na poziomie transportu: jeśli identyfikator zostanie pominięty, serwer doda go przed walidacją. Podaj własny, stały UUID v4, aby bezpiecznie odzyskać wynik po utracie odpowiedzi.Format: “uuid”. Wzorzec:
^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$.string
wymagane
uploadId zwrócony przez akcję upload_initialize tej domeny.Format: “uuid”. Wzorzec:
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$.array
wymagane
Lista wartości. Strukturę elementów opisuje pełny schemat danych wejściowych.Minimalna liczba elementów: 1. Maksymalna liczba elementów: 2.
Pełny schemat danych wejściowych
Pełny schemat danych wejściowych
Poniższy JSON Schema zachowuje dokładne nazwy pól, typy zagnieżdżone, wartości domyślne, ograniczenia i akceptowane wartości udostępniane przez mechanizm wykrywania. Dodatkowe reguły zależności między polami znajdują się w uwagach do operacji.
{
"type": "object",
"properties": {
"requestId": {
"description": "UUID v4 for this action. Reuse the same ID with identical arguments on retries.",
"type": "string",
"format": "uuid",
"pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
},
"uploadId": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "The uploadId returned by this domain’s upload_initialize action."
},
"parts": {
"minItems": 1,
"maxItems": 2,
"type": "array",
"items": {
"type": "object",
"properties": {
"partNumber": {
"type": "integer",
"minimum": 1,
"maximum": 2
},
"etag": {
"type": "string",
"minLength": 1,
"maxLength": 256
}
},
"required": ["partNumber", "etag"],
"additionalProperties": false
}
}
},
"required": ["uploadId", "parts"],
"additionalProperties": false
}
Idempotencja
Dla każdej operacji zmieniającej dane użyj UUID v4 w requestId lub w nagłówku HTTP Idempotency-Key. Po awarii sieci użyj ponownie tego samego identyfikatora i identycznych argumentów. Jeśli podasz oba, muszą być zgodne. Ponowienie zapisanego żądania nie powtarza operacji ani nie zużywa kolejnego wywołania z miesięcznego limitu. Żądania zakończone błędem lub przerwane nie są automatycznie uruchamiane ponownie. Każda operacja zmieniająca dane może zwrócić HTTP 202, gdy ponowienie napotka to samo żądanie nadal w stanie running, nawet jeśli jej pierwsze wykonanie zwykle jest synchroniczne. Jeśli wykonanie się zakończyło, ale resultStored ma wartość false, ponowienie zwraca HTTP 200 z zapisanym stanem żądania zamiast pierwotnego wyniku. Pobierz wynik za pomocą akcji historii, wyniku lub pobierania właściwej dla danej domeny.Przykłady żądań
Zastąp przykładowe identyfikatory zasobów i klucze multimediów wartościami zwróconymi dla Twojego konta. Przy ponawianiu tej samej operacji zmieniającej dane zachowaj identyfikator żądania.curl --request POST 'https://api.voicecheap.ai/v1/actions/thumbnails_upload_complete' \
--header "x-api-key: $VOICECHEAP_API_KEY" \
--header 'Content-Type: application/json' \
--data '{"requestId":"ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a","uploadId":"c547fb7f-f334-46a8-a8bb-80b5b343889a","parts":[{"partNumber":1,"etag":"\"d41d8cd98f00b204e9800998ecf8427e\""},{"partNumber":2,"etag":"\"0cc175b9c0f1b6a831c399e269772661\""}]}'
const input = {
requestId: 'ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a',
uploadId: 'c547fb7f-f334-46a8-a8bb-80b5b343889a',
parts: [
{
partNumber: 1,
etag: '"d41d8cd98f00b204e9800998ecf8427e"',
},
{
partNumber: 2,
etag: '"0cc175b9c0f1b6a831c399e269772661"',
},
],
};
const response = await fetch('https://api.voicecheap.ai/v1/actions/thumbnails_upload_complete', {
method: 'POST',
headers: {
'x-api-key': process.env.VOICECHEAP_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify(input),
});
const body = await response.json();
if (!response.ok) throw new Error(body.code + ': ' + body.message);
console.log(body);
import os
import requests
response = requests.post(
"https://api.voicecheap.ai/v1/actions/thumbnails_upload_complete",
headers={"x-api-key": os.environ["VOICECHEAP_API_KEY"]},
json={"requestId": "ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a", "uploadId": "c547fb7f-f334-46a8-a8bb-80b5b343889a", "parts": [{"partNumber": 1, "etag": "\"d41d8cd98f00b204e9800998ecf8427e\""}, {"partNumber": 2, "etag": "\"0cc175b9c0f1b6a831c399e269772661\""}]},
timeout=120,
)
body = response.json()
if not response.ok:
raise RuntimeError(f"{body.get('code')}: {body.get('message')}")
print(body)
Odpowiedź
Pierwsze pomyślne wykonanie zwraca HTTP 200 z wynikiem operacji w data. Ponowienie może zamiast tego zwrócić zapisany stan żądania. Przykład przedstawia jedną obsługiwaną odpowiedź, bez wszystkich opcjonalnych pól. Klucz ukończonego pliku referencyjnego należącego do użytkownika i jego adres URL do odczytu, zwracane dopiero wtedy, gdy liczba zapisanych bajtów dokładnie odpowiada zadeklarowanemu rozmiarowi pliku. W argumentach generowania używaj fileKey, a nie readUrl.{
"data": {
"fileKey": "uploads/example-user/2502829e-3fde-4aad-b3c7-ce0f779fa2e6-reference.png",
"readUrl": "https://media.example.com/uploads/example-user/2502829e-3fde-4aad-b3c7-ce0f779fa2e6-reference.png"
},
"requestId": "ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a"
}
{
"data": {
"requestId": "ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a",
"operation": "thumbnails_upload_complete",
"createdAt": 1792144800000,
"updatedAt": 1792144820000,
"status": "running",
"pollAfterSeconds": 5
},
"requestId": "ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a"
}
{
"data": {
"requestId": "ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a",
"operation": "thumbnails_upload_complete",
"createdAt": 1792144800000,
"updatedAt": 1792144820000,
"status": "completed",
"resultStored": false,
"message": "The action completed. Retrieve its output from the corresponding history or resource action."
},
"requestId": "ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a"
}
Pola wyniku
| Pole | Opis |
|---|---|
data.fileKey | Klucz ukończonego obiektu należącego do wywołującego, do użycia jako materiał referencyjny do generowania. |
data.readUrl | Adres URL odczytu przesłanego obiektu referencyjnego. Akcje generowania przyjmują fileKey, a nie ten adres URL. |
Odzyskaj żądanie i sprawdź jego stan
Używaj tego samego identyfikatora także po utracie połączenia. Jeśli resultStored ma wartość false, pobierz wynik za pomocą odpowiedniej akcji historii, wyniku lub pobierania. Nigdy nie uruchamiaj drugiego generowania tylko po to, aby sprawdzić postęp.curl --request POST 'https://api.voicecheap.ai/v1/actions/action_request_get' \
--header "x-api-key: $VOICECHEAP_API_KEY" \
--header 'Content-Type: application/json' \
--data '{"requestId":"ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a","operation":"thumbnails_upload_complete"}'
HTTP 200
{
"data": {
"requestId": "ef5fe21c-c80c-4b96-b2ed-8d37bf2c667a",
"operation": "thumbnails_upload_complete",
"status": "completed",
"createdAt": 1792144800000,
"updatedAt": 1792144820000,
"resultStored": true,
"result": {
"fileKey": "uploads/example-user/2502829e-3fde-4aad-b3c7-ce0f779fa2e6-reference.png",
"readUrl": "https://media.example.com/uploads/example-user/2502829e-3fde-4aad-b3c7-ce0f779fa2e6-reference.png"
}
}
}
Uwagi do operacji
- Wymaga thumbnails:write; dodatkowy zakres przesyłania nie jest potrzebny.
- uploadId to UUID z initialize. parts zawiera dokładnie 1–2 części wymagane przez sesję. Każda część ma całkowite partNumber od 1 do 2 i ciąg etag o długości 1–256 znaków pobrany z odpowiedzi udanego PUT.
- Wszystkie numery części muszą być obecne i unikatowe. Przed ukończeniem części są sortowane, a wartości ETag są normalizowane do wartości w cudzysłowach. Możesz zachować cudzysłowy ETag zwrócone przez magazyn danych.
- Rzeczywista długość ukończonego obiektu w bajtach jest porównywana z fileSize i limitem 8 MiB. Brak długości, jej niezgodność lub przekroczenie limitu powoduje usunięcie obiektu i aktywnej sesji oraz zwrócenie UPLOAD_SIZE_MISMATCH.
- Przekaż fileKey jako element referenceImageKeys w thumbnails_generate. Ukończone pliki referencyjne mogą być ponownie używane przy kolejnych generowaniach obrazów lub miniatur należących do tego samego użytkownika; generowanie nie zużywa pliku referencyjnego.
- Tylko przesłany plik należący do połączonego użytkownika może zostać podpisany, ukończony lub przerwany. Te aliasy akceptują tylko sesje JPG, PNG i WebP o rozmiarze maksymalnie 8 MiB, nawet jeśli sesja została utworzona przez inną rodzinę przesyłania.
- Produkcyjna sesja przesyłania wygasa po 24 godzinach. Podpisane adresy URL części wygasają po jednej godzinie. Zakończenie i przerwanie przesyłania usuwa aktywną sesję; sign-parts i complete zwracają wtedy Upload not found. Żadna z tych odpowiedzi nie zawiera pola expiresAt.
- Użyj requestId w formacie UUID v4 lub nagłówka HTTP Idempotency-Key i używaj tej samej wartości z identycznymi danymi wejściowymi przy ponownych próbach. Warstwa integracji zapisuje każdą modyfikację i zwraca jej zapisany stan lub wynik bez ponownego wykonywania. Żądanie w stanie failed lub interrupted nie jest automatycznie ponawiane.
- Ukończenie zamyka sesję przesyłania wieloczęściowego. Ponów ukończenie z oryginalnym requestId, aby pobrać zapisany wynik; nowe żądanie ukończenia dla tego zamkniętego uploadId zwraca Upload not found. Ta akcja nie zwraca terminu wygaśnięcia przechowywanego pliku referencyjnego.
Wykorzystanie
Każde pomyślne wywołanie zużywa jedno wywołanie z miesięcznego limitu API/MCP. Obowiązują również kredyty na multimedia oraz limity generowania danej operacji.Błędy
| Status HTTP | Kod | Znaczenie lub sposób rozwiązania |
|---|---|---|
| 400 | BAD_REQUEST | Na liście ukończenia brakuje numerów części, występują ich duplikaty lub nieprawidłowe numery. |
| 400 | CREDENTIAL_IN_QUERY | Dane uwierzytelniające zostały podane w parametrze zapytania access_token lub api_key. Wysyłaj dane uwierzytelniające w nagłówkach. |
| 400 | IDEMPOTENCY_CONFLICT | Nagłówek Idempotency-Key i pole requestId w treści żądania muszą być zgodne. |
| 400 | INVALID_REQUEST_ID | requestId lub Idempotency-Key nie jest identyfikatorem UUID v4. |
| 400 | UPLOAD_SIZE_MISMATCH | Zapisany rozmiar ukończonego obiektu jest niedostępny, różni się od fileSize lub przekracza 8 MiB; obiekt i sesja zostają usunięte. |
| 400 | UPLOAD_TYPE_NOT_ALLOWED | Sesja przesyłania nie dotyczy obsługiwanego typu obrazu lub przekracza 8 MiB. |
| 400 | VALIDATION_ERROR | Brakuje argumentu, ma on nieobsługiwaną wartość, przekracza limit lub nie należy do ścisłego schematu danych wejściowych. |
| 401 | API_KEY_EXPIRED | Klucz API wygasł. |
| 401 | INVALID_API_KEY | Podaj prawidłowy, niewygasły klucz API. |
| 401 | INVALID_CREDENTIAL | Nagłówek Authorization ma nieprawidłowy format lub jest sprzeczny z x-api-key. |
| 401 | MISSING_CREDENTIAL | Nie podano użytecznych danych uwierzytelniających w nagłówku lub przekroczyły one 4096 znaków. |
| 401 | UNAUTHORIZED | Sesja przesyłania należy do innego użytkownika. |
| 401 | USER_NOT_FOUND | Konto powiązane z poświadczeniem już nie istnieje. |
| 403 | ACCOUNT_UNAVAILABLE | Konto wykonujące operację lub konto rozliczeniowe jest niedostępne albo jest w trakcie usuwania. |
| 403 | AMBIGUOUS_TEAM_API_KEY | Użytkownik, do którego należą dane uwierzytelniające, należy do więcej niż jednego zespołu, więc kontekst rozliczeniowy jest niejednoznaczny. |
| 403 | INSUFFICIENT_SCOPE | Nadaj wszystkie wymagane uprawnienia lub wybierz inne dane uwierzytelniające. |
| 403 | INTEGRATION_PLAN_UNSUPPORTED | Nie udało się zweryfikować limitów integracji konta. |
| 403 | SUBSCRIPTION_REQUIRED | Użyj aktywnej płatnej subskrypcji. |
| 403 | TEAM_OWNER_NOT_FOUND | Nie znaleziono konta faktycznego właściciela zespołu. |
| 404 | NOT_FOUND | Sesja przesyłania jest nieznana, wygasła, została już zakończona lub przerwana. |
| 409 | CONCURRENT_ACTION_LIMIT_REACHED | Na tym koncie działa już 10 akcji integracji. Sprawdzaj stan istniejącego żądania przed rozpoczęciem kolejnego. |
| 409 | IDEMPOTENCY_CONFLICT | Identyfikator żądania został już użyty z innymi argumentami; niezgodność identyfikatorów w nagłówku i treści zwraca HTTP 400 z tym samym kodem. |
| 429 | INTEGRATION_MONTHLY_LIMIT_REACHED | Poczekaj na odnowienie miesięcznego limitu lub zmień plan. |
| 429 | INTEGRATION_RATE_LIMIT_REACHED | Jeśli występuje nagłówek Retry-After, odczekaj wskazany czas i stosuj rosnące odstępy między ponowieniami. |
| 500 | INTERNAL_ERROR | Sprawdź stan zapisanego żądania i historię zasobu przed podjęciem decyzji o ponowieniu operacji zmieniającej dane. |
| 503 | ACTION_RESULT_UNAVAILABLE | Akcja została wykonana, ale nie udało się zapisać jej wyniku. Sprawdź zapisany stan żądania i historię zasobu przed rozpoczęciem nowego generowania. |
| 503 | INTERNAL_ERROR | Nie udało się odczytać aktywnej sesji przesyłania. Sprawdź stan żądania przed kolejną próbą ukończenia. |
| 503 | SERVER_RESTARTING | Serwer jest uruchamiany ponownie. Spróbuj ponownie wkrótce i zachowaj ten sam identyfikator żądania dla operacji zmieniającej dane. |
{
"code": "INSUFFICIENT_SCOPE",
"message": "This credential does not permit the requested action.",
"status": 403,
"details": {
"requiredScopes": ["thumbnails:write"]
}
}
Czy ta strona była pomocna?

