URL Shortener
Create short links that lead to the address you choose, count their visits and manage your domains, all from the API. This guide takes you from the first key to a working link.
9 min readReviewed on
Goal
By the end of this guide you will know how to create a short link (for example https:) that leads to the long address you choose, know how many people open it, change or turn it off whenever you want and recover it if you delete it by mistake.
It is useful when you send links inside messages (where every character counts), when you want to measure a campaign or when you need to be able to change the destination of a link that has already been handed out.
When it is not what you are looking for
The destination of a short link is public: whoever opens it reaches that address. Do not use it to hide information. It also does not accept internal destinations or other short links.
Requirements
- An active Hablame organization, with a valid API key. How to get one.
- The
urlshortenerservice on the key. It grants the whole URL shortener: list and view links, statistics, overview, domains and price, and also create (each creation is charged), edit, delete and restore. Only the owner of your organization creates keys. - Available balance or an active URL Shortener plan to create links. Your organization also needs to have its currency defined and a URL Shortener price in that currency.
- If you want to use your own domain, it must be registered and verified in your organization. There is no endpoint to register or verify it.
Credentials
Every request carries your API key in the Authorization: header. The urlshortener service is granted in full: there are no read-only URL shortener keys.
| Key | What it can do | Use it for |
|---|---|---|
With urlshortener | List and view links, statistics, overview, domains and price, and also create (charged), edit, delete and restore links. | The system that generates and manages the links. |
Without urlshortener | Nothing in the URL shortener: every endpoint answers 403 AUTH_SERVICE_NOT_ALLOWED. | Integrations of other services that must not touch your links. |
Steps
- 01Check your key
Call
GET /. Autilities/ ping 200confirms the key and the network work. - 02See your domains
GET /lists where you can publish, with the default first. If you do not sendurlshortener/ domains domainwhen creating, that one is used. - 03Check the price
GET /tells you what creating a link and each visit cost your organization, and whether your plan includes it. This documentation does not publish figures.urlshortener/ pricing - 04Create a link
POST /with the destination address. Always send anurlshortener/ links Idempotency-Key: if the request is cut off and you repeat it, no other link is created or charged. - 05Check it
Open the short URL in a browser and query the link with
GET /.urlshortener/ links/ {domain}/ {code} - 06Measure
GET /brings a link’s visits per day or per hour and its breakdown by country, device, system, browser and source.urlshortener/ links/ {domain}/ {code}/ stats GET /summarizes your whole organization.urlshortener/ overview - 07Maintain
Change the destination, turn a link off or back on with
PATCH; delete it withDELETEand recover it for 90 days withrestore.
What is charged, is charged for real
There is no test environment. Creating a link is charged and, after that, every visit by a person too. Visits by bots and the previews generated by social networks and chat apps are not charged. Read testing without surprises.
Examples
Create a link
Only four fields are accepted: longUrl (required), domain, code (your alias) and expiresAt. A field that does not exist is rejected with 400 naming the field.
curl -X POST https://developers.hablame.co/api/v6/urlshortener/links \
-H 'Authorization: Bearer hk_TU_API_KEY' \
-H 'Idempotency-Key: 5f3b2c10-9a7e-4b2d-8c1f-0a1b2c3d4e5f' \
-H 'Content-Type: application/json' \
-d '{
"longUrl": "https://example.com/landing?utm_source=sms",
"code": "promo-octubre",
"expiresAt": "2026-12-31T23:59:59-05:00"
}'import { randomUUID } from 'node:crypto'
const idempotencyKey = randomUUID()
const res = await fetch('https://developers.hablame.co/api/v6/urlshortener/links', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.HABLAME_API_KEY}`,
'Idempotency-Key': idempotencyKey,
'Content-Type': 'application/json',
},
body: JSON.stringify({
longUrl: 'https://example.com/landing?utm_source=sms',
code: 'promo-octubre',
}),
})
const body = await res.json()
if (body.success) console.log(body.data.shortUrl)
else console.error(body.error.code, body.meta.requestId)import os
import uuid
import requests
r = requests.post(
"https://developers.hablame.co/api/v6/urlshortener/links",
headers={
"Authorization": f"Bearer {os.environ['HABLAME_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={"longUrl": "https://example.com/landing?utm_source=sms", "code": "promo-octubre"},
timeout=30,
)
body = r.json()
print(body["data"]["shortUrl"] if body["success"] else body["error"]["code"])<?php
$ch = curl_init('https://developers.hablame.co/api/v6/urlshortener/links');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('HABLAME_API_KEY'),
'Idempotency-Key: ' . bin2hex(random_bytes(16)),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'longUrl' => 'https://example.com/landing?utm_source=sms',
'code' => 'promo-octubre',
]),
]);
$body = json_decode(curl_exec($ch), true);
echo $body['success'] ? $body['data']['shortUrl'] : $body['error']['code'];Create many at once
For a campaign use bulk creation: up to 1,000 links per request. An invalid link does not sink the batch; the response carries one result per link.
LOTE=campana-octubre-lote-01
curl -X POST https://developers.hablame.co/api/v6/urlshortener/links/batch \
-H 'Authorization: Bearer hk_TU_API_KEY' \
-H "Idempotency-Key: $LOTE" \
-H 'Content-Type: application/json' \
-d '{
"links": [
{ "longUrl": "https://example.com/landing?c=1" },
{ "longUrl": "https://example.com/landing?c=2", "code": "oferta-2" }
]
}'List and measure
curl 'https://developers.hablame.co/api/v6/urlshortener/links?perPage=20&search=promo' \
-H 'Authorization: Bearer hk_TU_API_KEY'curl 'https://developers.hablame.co/api/v6/urlshortener/links/h0b.co/promo-octubre/stats?from=2026-10-01&to=2026-10-24' \
-H 'Authorization: Bearer hk_TU_API_KEY'Turn off and restore
curl -X PATCH https://developers.hablame.co/api/v6/urlshortener/links/h0b.co/promo-octubre \
-H 'Authorization: Bearer hk_TU_API_KEY' \
-H 'Content-Type: application/json' \
-d '{ "status": "disabled" }'curl -X POST https://developers.hablame.co/api/v6/urlshortener/links/h0b.co/promo-octubre/restore \
-H 'Authorization: Bearer hk_TU_API_KEY'Expected responses
Creating a link answers 201 with the link inside data. The values are examples:
{
"success": true,
"data": {
"domain": "h0b.co",
"code": "promo-octubre",
"shortUrl": "https://h0b.co/promo-octubre",
"longUrl": "https://example.com/landing?utm_source=sms",
"isAlias": true,
"status": "active",
"domainStatus": "active",
"expiresAt": "2027-01-01T04:59:59Z",
"createdAt": "2026-10-24T15:04:05Z",
"clicks": 0,
"uniqueClicks": 0,
"firstClickAt": null,
"lastClickAt": null
},
"meta": {
"requestId": "5d0f3a9c7b2e41a8",
"clientIp": "203.0.113.45",
"timestamp": "2026-10-24T15:04:05+00:00",
"responseTimeMs": 31.2
}
}shortUrl- The full short URL, always
https:. It is the one you hand out./ / {domain}/ {code} statusactive,disabledorblocked. Expired is not a status: anactivelink whoseexpiresAthas passed stops redirecting but staysactive.blockedis set by Hablame for security: it does not redirect and cannot be edited, deleted or reactivated.domainStatus- Whether the domain lets the link open. With
suspended,releasedorpendingthe link does not redirect even if itsstatusisactive. clicks / uniqueClicks- Lifetime visits of the link and the sum of each day’s unique visits. They can take from seconds to a few minutes to show up. They do not count bots or previews.
With a repeated Idempotency-Key and the same body, you receive the same link with the Idempotency-Status: header, without creating or charging another. Deleting answers 204 with no body. Lists carry items, total, hasMore and nextCursor: to walk through many links pass the nextCursor as cursor in the next request.
Common errors
| Code | What happened | What to do |
|---|---|---|
403 AUTH_SERVICE_NOT_ALLOWED | Your key does not have the urlshortener service. | Ask the owner of your organization for a key with the URL shortener. |
400 URL_INVALID / URL_SCHEME_NOT_ALLOWED / URL_BLOCKED_HOST | The destination is not a full http or https URL, or it points to an internal address or another short link. | Use a full public URL of up to 2,048 characters. |
409 ALIAS_TAKEN / ALIAS_RESERVED / ALIAS_RETIRED | The alias is already in use on that domain, is a reserved word or a brand on a shared domain, or belonged to a deleted link of yours. | Choose another alias, or restore the link if it was yours. |
409 DOMAIN_NOT_VERIFIED | Your own domain is not verified yet. | Use a domain from GET /. |
402 URLSHORTENER_INSUFFICIENT_FUNDS | There is no available balance. The link was not created. | Top up and retry with the same Idempotency-Key. |
409 URLSHORTENER_CURRENCY_UNDEFINED / URLSHORTENER_NOT_PRICED | Your organization has no currency defined, or there is no price in its currency. | Retrying does not fix it: define the currency or write to support. |
422 IDEMPOTENCY_KEY_REUSED | You used an Idempotency-Key with a body different from the first time. | Use a new key for a new link. |
429 URLSHORTENER_LINK_QUOTA_EXCEEDED | With a plan, you reached the daily creation quota. | Retry-After says how long until midnight in Colombia. |
409 LINK_BLOCKED | Hablame blocked the link for security. | If you think it is a mistake, write to us with the requestId. |
All the codes are in the error catalog and the most common symptoms are in troubleshooting.
Security
- Separate your keys by service. The URL shortener is granted in full: a key with it can also create, redirect and delete your links if it leaks. Give the
urlshortenerservice only to the system that really manages them; only the owner of your organization creates keys. - Look after the destination. Whoever controls
longUrlcontrols where your already distributed links lead. Validate where each destination comes from before sending it. - Hablame filters dangerous destinations.
localhost, internal names, private or reserved IP addresses, other short links, destinations with a user before the domain and domains with invisible characters or characters from other alphabets are rejected. On shared domains, aliases that imitate a brand, a bank, a payment method or a public entity are not accepted either. - A deleted link does not release its code. Nobody can reuse it to point somewhere else. You can restore it for 90 days.
- Every change is recorded: the previous value, the new one and who made it (the API key or the Cloud user).
Related endpoints
| Endpoint | What it does |
|---|---|
POST / | Create a short link |
POST / | Create short links in bulk |
GET / | List short links |
GET / | Get a short link |
PATCH / | Update a short link |
DELETE / | Delete a short link |
POST / | Restore a deleted link |
GET / | Link statistics |
GET / | Organization overview |
GET / | List available domains |
GET / | URL Shortener pricing |
All of them only require the urlshortener service: with it, the key also creates, edits, deletes and restores.
Next steps
Retry without creating or charging twice.
How many requests each endpoint accepts and how to pace yourself.
Every endpoint with its parameters and errors.
What the URL Shortener is and what it is for, in a few words.
For technical questions, email developers@hablame.co. If you have a production incident, message us on WhatsApp at +57 319 660 0002, 24/7.