curl -X POST "https://api.hooked.so/v1/image/remove-background" \
-H "x-api-key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{ "imageUrl": "https://example.com/portrait.jpg" }'
const response = await fetch('https://api.hooked.so/v1/image/remove-background', {
method: 'POST',
headers: { 'x-api-key': 'your_api_key_here', 'Content-Type': 'application/json' },
body: JSON.stringify({ media: 'cm1a2b3c4d5e6f7g8h9i0j1k2' })
});
const { data } = await response.json();
if (data.status === 'COMPLETED') {
console.log(data.backgroundRemovedUrl); // PNG with transparency
} else {
console.log(`Poll GET /v1/image/${data.mediaId}`);
}
import requests
response = requests.post(
'https://api.hooked.so/v1/image/remove-background',
headers={'x-api-key': 'your_api_key_here'},
json={'imageUrl': 'https://example.com/portrait.jpg'}
)
data = response.json()['data']
print(data['mediaId'], data['status'])
{
"success": true,
"message": "Background removal started",
"data": {
"mediaId": "cm1a2b3c4d5e6f7g8h9i0j1k2",
"status": "PROCESSING",
"url": "https://.../portrait.jpg",
"jobId": "aab23fd5fe10445c8fc1d2821b1482bd",
"usedCredits": 4
}
}
{
"success": true,
"message": "Background removal already running",
"data": {
"mediaId": "cm1a2b3c4d5e6f7g8h9i0j1k2",
"status": "PROCESSING",
"url": "https://.../portrait.jpg",
"jobId": "aab23fd5fe10445c8fc1d2821b1482bd",
"usedCredits": 0
}
}
{
"success": true,
"message": "Background already removed",
"data": {
"mediaId": "cm1a2b3c4d5e6f7g8h9i0j1k2",
"status": "COMPLETED",
"url": "https://.../portrait.jpg",
"backgroundRemovedUrl": "https://.../cm1a2b3c4d5e6f7g8h9i0j1k2-1726560000000.png",
"usedCredits": 0
}
}
{
"success": false,
"message": "media: Image not found"
}
{
"success": false,
"errorCode": "INSUFFICIENT_CREDITS",
"creditsNeeded": 4,
"creditsAvailable": 1,
"message": "Not enough credits to perform this action"
}
{
"success": false,
"code": "missing_credentials",
"errorCode": "MISSING_CREDENTIALS",
"missingProviders": ["bria"],
"message": "Your team uses its own provider keys (BYOK) and these are missing or invalid: Bria. Add them in Settings → AI keys."
}
Remove Image Background
Cut the subject out of an image and get a PNG with a transparent background
curl -X POST "https://api.hooked.so/v1/image/remove-background" \
-H "x-api-key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{ "imageUrl": "https://example.com/portrait.jpg" }'
const response = await fetch('https://api.hooked.so/v1/image/remove-background', {
method: 'POST',
headers: { 'x-api-key': 'your_api_key_here', 'Content-Type': 'application/json' },
body: JSON.stringify({ media: 'cm1a2b3c4d5e6f7g8h9i0j1k2' })
});
const { data } = await response.json();
if (data.status === 'COMPLETED') {
console.log(data.backgroundRemovedUrl); // PNG with transparency
} else {
console.log(`Poll GET /v1/image/${data.mediaId}`);
}
import requests
response = requests.post(
'https://api.hooked.so/v1/image/remove-background',
headers={'x-api-key': 'your_api_key_here'},
json={'imageUrl': 'https://example.com/portrait.jpg'}
)
data = response.json()['data']
print(data['mediaId'], data['status'])
{
"success": true,
"message": "Background removal started",
"data": {
"mediaId": "cm1a2b3c4d5e6f7g8h9i0j1k2",
"status": "PROCESSING",
"url": "https://.../portrait.jpg",
"jobId": "aab23fd5fe10445c8fc1d2821b1482bd",
"usedCredits": 4
}
}
{
"success": true,
"message": "Background removal already running",
"data": {
"mediaId": "cm1a2b3c4d5e6f7g8h9i0j1k2",
"status": "PROCESSING",
"url": "https://.../portrait.jpg",
"jobId": "aab23fd5fe10445c8fc1d2821b1482bd",
"usedCredits": 0
}
}
{
"success": true,
"message": "Background already removed",
"data": {
"mediaId": "cm1a2b3c4d5e6f7g8h9i0j1k2",
"status": "COMPLETED",
"url": "https://.../portrait.jpg",
"backgroundRemovedUrl": "https://.../cm1a2b3c4d5e6f7g8h9i0j1k2-1726560000000.png",
"usedCredits": 0
}
}
{
"success": false,
"message": "media: Image not found"
}
{
"success": false,
"errorCode": "INSUFFICIENT_CREDITS",
"creditsNeeded": 4,
"creditsAvailable": 1,
"message": "Not enough credits to perform this action"
}
{
"success": false,
"code": "missing_credentials",
"errorCode": "MISSING_CREDENTIALS",
"missingProviders": ["bria"],
"message": "Your team uses its own provider keys (BYOK) and these are missing or invalid: Bria. Add them in Settings → AI keys."
}
Overview
Starts removing the background of an image. The result is a PNG with real transparency, attached to the image in your library a few seconds later. The call answers202 with the media to follow: poll Get Image until backgroundRemoval.status is COMPLETED.
The image can be one already in your library (media) or a public URL (imageUrl). A URL is imported into your library first, so the result is always attached to a media you own. When both are sent, media is used.
- An image that already has its cut-out answers
200at once with the PNG. Nothing is charged. - An image whose removal is already running answers
202again with the same job. Nothing is charged.
media).
Credits
| Team mode | Cost |
|---|---|
| Managed (Hooked’s keys) | 4 credits per new removal, charged when the job starts and refunded if it fails |
| BYOK (your own keys) | No credits (usedCredits is 0). The team needs its own Bria key in Settings → AI keys |
curl -X POST "https://api.hooked.so/v1/image/remove-background" \
-H "x-api-key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{ "imageUrl": "https://example.com/portrait.jpg" }'
const response = await fetch('https://api.hooked.so/v1/image/remove-background', {
method: 'POST',
headers: { 'x-api-key': 'your_api_key_here', 'Content-Type': 'application/json' },
body: JSON.stringify({ media: 'cm1a2b3c4d5e6f7g8h9i0j1k2' })
});
const { data } = await response.json();
if (data.status === 'COMPLETED') {
console.log(data.backgroundRemovedUrl); // PNG with transparency
} else {
console.log(`Poll GET /v1/image/${data.mediaId}`);
}
import requests
response = requests.post(
'https://api.hooked.so/v1/image/remove-background',
headers={'x-api-key': 'your_api_key_here'},
json={'imageUrl': 'https://example.com/portrait.jpg'}
)
data = response.json()['data']
print(data['mediaId'], data['status'])
{
"success": true,
"message": "Background removal started",
"data": {
"mediaId": "cm1a2b3c4d5e6f7g8h9i0j1k2",
"status": "PROCESSING",
"url": "https://.../portrait.jpg",
"jobId": "aab23fd5fe10445c8fc1d2821b1482bd",
"usedCredits": 4
}
}
{
"success": true,
"message": "Background removal already running",
"data": {
"mediaId": "cm1a2b3c4d5e6f7g8h9i0j1k2",
"status": "PROCESSING",
"url": "https://.../portrait.jpg",
"jobId": "aab23fd5fe10445c8fc1d2821b1482bd",
"usedCredits": 0
}
}
{
"success": true,
"message": "Background already removed",
"data": {
"mediaId": "cm1a2b3c4d5e6f7g8h9i0j1k2",
"status": "COMPLETED",
"url": "https://.../portrait.jpg",
"backgroundRemovedUrl": "https://.../cm1a2b3c4d5e6f7g8h9i0j1k2-1726560000000.png",
"usedCredits": 0
}
}
{
"success": false,
"message": "media: Image not found"
}
{
"success": false,
"errorCode": "INSUFFICIENT_CREDITS",
"creditsNeeded": 4,
"creditsAvailable": 1,
"message": "Not enough credits to perform this action"
}
{
"success": false,
"code": "missing_credentials",
"errorCode": "MISSING_CREDENTIALS",
"missingProviders": ["bria"],
"message": "Your team uses its own provider keys (BYOK) and these are missing or invalid: Bria. Add them in Settings → AI keys."
}
Errors
| Status | When | Body |
|---|---|---|
| 400 | Body is not JSON | Invalid JSON body |
| 400 | Neither media nor imageUrl | media or imageUrl is required |
| 400 | media is not an image of your library | media: Image not found, media: Media must be an image |
| 400 | imageUrl could not be imported | imageUrl: The image URL could not be fetched, imageUrl: The URL must point to a JPEG, PNG or WEBP image, imageUrl: The image is larger than 25 MB |
| 401 | Missing or invalid API key | { "code": "not_authenticated", ... } |
| 402 | Managed team without enough credits | errorCode: "INSUFFICIENT_CREDITS" |
| 402 | Managed team without a live subscription | code: "subscription_required" |
| 402 | BYOK team without its Bria key | code: "missing_credentials", missingProviders: ["bria"] |
| 403 | The team does not have the Hooked app product | code: "entitlement_required" |
| 502 | Bria did not take the request (nothing is charged) | { "success": false, "message": "..." } |
| 500 | Unexpected error | { "code": "internal_server_error", "message": "Failed to remove the background", ... } |
backgroundRemoval.status: "FAILED" in Get Image and the credits are refunded.
Related Endpoints
Get Image
Expand Image
Remove Video Background
Authorizations
Headers
Makes the request safe to retry. 1-255 printable ASCII characters, one per operation (your job id, or a UUID you store), reused on every retry. Within 24 hours the same key with the same body answers with the first response and the header Idempotent-Replayed: true, without running or charging again. Keys are scoped to your team and the endpoint. 5xx answers and refusals before anything ran (401, 402, 403, 409, 429) are not kept. See Idempotency.
1 - 255^[\x20-\x7E]+$Body
ID of an image in your media library. Required unless imageUrl is given. When both are sent, media is used. A media that is not COMPLETED yet (an import or upload in progress) answers 400 media: Media "<id>" is not ready (status PROCESSING).
Public URL of a JPEG, PNG or WEBP image (up to 25 MB). It is imported into your library first, so the result is attached to a media you own. Required unless media is given.