curl -X DELETE https://api.bouncy.ai/v1/links/bulk \
-H "Authorization: Bearer bcy_live_pk_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"links": ["my-link", "tapmy.social__promo", "missing-link"]
}'
const response = await fetch('https://api.bouncy.ai/v1/links/bulk', {
method: 'DELETE',
headers: {
'Authorization': 'Bearer bcy_live_pk_YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
links: ['my-link', 'tapmy.social__promo', 'missing-link']
})
});
const result = await response.json();
console.log(`Deleted ${result.deletedCount} links`);
import requests
response = requests.delete(
'https://api.bouncy.ai/v1/links/bulk',
headers={
'Authorization': 'Bearer bcy_live_pk_YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
'links': ['my-link', 'tapmy.social__promo', 'missing-link']
}
)
result = response.json()
print(f"Deleted {result['deletedCount']} links")
{
"success": true,
"message": "Bulk delete completed: 2 successful, 1 failed, 0 skipped",
"results": {
"successful": ["my-link", "tapmy.social__promo"],
"failed": [
{ "identifier": "missing-link", "error": "Deeplink not found. Deletes only match a link id or its full short URL (for example tapmy.social/amy), never the bare slug of a link on another domain. A bouncy.ai link uses its slug as its id." }
],
"skipped": []
},
"deletedCount": 2,
"redeployPending": []
}
{
"success": true,
"message": "Bulk delete completed: 3 successful, 0 failed, 0 skipped. 1 custom domain(s) not confirmed redeployed, see redeployPending",
"results": {
"successful": ["go.example.com__sale", "shop.example.com__old", "tapmy.social__promo"],
"failed": [],
"skipped": []
},
"deletedCount": 3,
"redeployPending": [
{ "domain": "shop.example.com", "reason": "timed_out" }
]
}
{
"error": "Bad Request",
"message": "links must be a non-empty array. The single link whose id is \"bulk\" is addressed by its short URL, https://bouncy.ai/bulk (URL-encoded in the path)."
}
{
"error": "Bad Request",
"message": "links can hold at most 100 identifiers per request (got 150)"
}
{
"error": "Bad Request",
"code": "TOO_MANY_CUSTOM_DOMAINS",
"message": "These links are on 12 custom domains; one bulk delete can change at most 10 custom domains (each one is redeployed). Split the request by domain. Nothing was deleted."
}
Links
Bulk Delete Links
Delete up to 100 short links in a single request
DELETE
/
v1
/
links
/
bulk
curl -X DELETE https://api.bouncy.ai/v1/links/bulk \
-H "Authorization: Bearer bcy_live_pk_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"links": ["my-link", "tapmy.social__promo", "missing-link"]
}'
const response = await fetch('https://api.bouncy.ai/v1/links/bulk', {
method: 'DELETE',
headers: {
'Authorization': 'Bearer bcy_live_pk_YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
links: ['my-link', 'tapmy.social__promo', 'missing-link']
})
});
const result = await response.json();
console.log(`Deleted ${result.deletedCount} links`);
import requests
response = requests.delete(
'https://api.bouncy.ai/v1/links/bulk',
headers={
'Authorization': 'Bearer bcy_live_pk_YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
'links': ['my-link', 'tapmy.social__promo', 'missing-link']
}
)
result = response.json()
print(f"Deleted {result['deletedCount']} links")
{
"success": true,
"message": "Bulk delete completed: 2 successful, 1 failed, 0 skipped",
"results": {
"successful": ["my-link", "tapmy.social__promo"],
"failed": [
{ "identifier": "missing-link", "error": "Deeplink not found. Deletes only match a link id or its full short URL (for example tapmy.social/amy), never the bare slug of a link on another domain. A bouncy.ai link uses its slug as its id." }
],
"skipped": []
},
"deletedCount": 2,
"redeployPending": []
}
{
"success": true,
"message": "Bulk delete completed: 3 successful, 0 failed, 0 skipped. 1 custom domain(s) not confirmed redeployed, see redeployPending",
"results": {
"successful": ["go.example.com__sale", "shop.example.com__old", "tapmy.social__promo"],
"failed": [],
"skipped": []
},
"deletedCount": 3,
"redeployPending": [
{ "domain": "shop.example.com", "reason": "timed_out" }
]
}
{
"error": "Bad Request",
"message": "links must be a non-empty array. The single link whose id is \"bulk\" is addressed by its short URL, https://bouncy.ai/bulk (URL-encoded in the path)."
}
{
"error": "Bad Request",
"message": "links can hold at most 100 identifiers per request (got 150)"
}
{
"error": "Bad Request",
"code": "TOO_MANY_CUSTOM_DOMAINS",
"message": "These links are on 12 custom domains; one bulk delete can change at most 10 custom domains (each one is redeployed). Split the request by domain. Nothing was deleted."
}
Request
Headers
string
required
Must be
application/jsonBody
array
required
Identifiers of the links to delete (max: 100). Each one is resolved exactly like DELETE /v1/links/: the link
id or its full short URL. A bare slug only matches the link whose id it is (a bouncy.ai link); it is never looked up across your other domains, so resending the same request after a timeout reports the already deleted links as not found instead of deleting other links that share their slugs. An identifier also never falls through to a similar link (another case of a custom path, a_b for a/b, the bare domain for a used www. host), and a short URL with #, a . or .. segment or an encoded / fails as not found: see Delete Link. For an active, non-viewer team member, the team owner’s links resolve too, by their exact id or short URL.A link named more than once (for example by its id and by its short URL) is deleted once; the extra entries are listed under skipped.The links in one request can be on at most 10 different custom domains (each one is redeployed after the delete). Over that, the request is refused with 400 TOO_MANY_CUSTOM_DOMAINS and nothing is deleted: split it by domain.Example: ["my-link", "tapmy.social__promo", "https://go.example.com/sale"]This action is permanent and cannot be undone. All short URLs will immediately stop working. Contacts collected by a deleted website are deleted with it, and each affected custom domain is redeployed once.
The deletes are committed before any custom domain is redeployed. Redeploys run a few at a time within a fixed time budget, so the response always arrives well inside the request timeout. A domain whose redeploy did not finish in time is listed in
redeployPending: its links are deleted, but the domain may keep serving the deleted paths until it is next deployed.Response
boolean
true when the request was processed (individual links can still fail)string
Summary of the counts
object
Show properties
Show properties
integer
Number of links deleted
array
{ domain, reason } for each affected custom domain whose redeploy was not confirmed (empty when every domain was redeployed). reason is timed_out (still running when the time budget ran out), not_started (the budget ran out first) or failed.curl -X DELETE https://api.bouncy.ai/v1/links/bulk \
-H "Authorization: Bearer bcy_live_pk_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"links": ["my-link", "tapmy.social__promo", "missing-link"]
}'
const response = await fetch('https://api.bouncy.ai/v1/links/bulk', {
method: 'DELETE',
headers: {
'Authorization': 'Bearer bcy_live_pk_YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
links: ['my-link', 'tapmy.social__promo', 'missing-link']
})
});
const result = await response.json();
console.log(`Deleted ${result.deletedCount} links`);
import requests
response = requests.delete(
'https://api.bouncy.ai/v1/links/bulk',
headers={
'Authorization': 'Bearer bcy_live_pk_YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
'links': ['my-link', 'tapmy.social__promo', 'missing-link']
}
)
result = response.json()
print(f"Deleted {result['deletedCount']} links")
{
"success": true,
"message": "Bulk delete completed: 2 successful, 1 failed, 0 skipped",
"results": {
"successful": ["my-link", "tapmy.social__promo"],
"failed": [
{ "identifier": "missing-link", "error": "Deeplink not found. Deletes only match a link id or its full short URL (for example tapmy.social/amy), never the bare slug of a link on another domain. A bouncy.ai link uses its slug as its id." }
],
"skipped": []
},
"deletedCount": 2,
"redeployPending": []
}
{
"success": true,
"message": "Bulk delete completed: 3 successful, 0 failed, 0 skipped. 1 custom domain(s) not confirmed redeployed, see redeployPending",
"results": {
"successful": ["go.example.com__sale", "shop.example.com__old", "tapmy.social__promo"],
"failed": [],
"skipped": []
},
"deletedCount": 3,
"redeployPending": [
{ "domain": "shop.example.com", "reason": "timed_out" }
]
}
{
"error": "Bad Request",
"message": "links must be a non-empty array. The single link whose id is \"bulk\" is addressed by its short URL, https://bouncy.ai/bulk (URL-encoded in the path)."
}
{
"error": "Bad Request",
"message": "links can hold at most 100 identifiers per request (got 150)"
}
{
"error": "Bad Request",
"code": "TOO_MANY_CUSTOM_DOMAINS",
"message": "These links are on 12 custom domains; one bulk delete can change at most 10 custom domains (each one is redeployed). Split the request by domain. Nothing was deleted."
}