Name
Create a short link
Publish a short link with a generated code or your own alias. Charged on creation, unless your plan includes it.
HTTP method and path
/ api/ v6/ urlshortener/ linkshttps:
What happens when you run it
- Creates data in your organization.
- The call is charged to your organization.
- After that, every visit by a person to the link is also charged (visits by bots and link previews are not).
What it does
Creates a short link on one of the domains available to your organization. If you do not send code, the service generates a 7-character one (0-9a-z); if you do, it becomes an alias (isAlias:). Codes are unique per domain, and the code of a deleted link cannot be used for another link: if it was yours, you can restore it for 90 days.
Each created link is charged at your organization’s current price (see GET /). If your organization has an active monthly URL shortener plan, creating links is not charged, and a daily creation quota applies instead (100,000 per Colombia day, unless you agreed another one): once reached, the API returns 429 URLSHORTENER_LINK_QUOTA_EXCEEDED until midnight. Without a plan there is no daily quota: without available balance the API returns 402 and the link is not created.
Many links at once, for example for a campaign? Use bulk creation: up to 1,000 per request, with the same rules and a single charge for what was created.
Availability and prerequisites
- Published and available in the production API v6.
- Every path starts at
https:./ / developers. hablame. co - You need a Hablame API key to call it.
Authentication and permissions
- Send your API key in the
Authorizationheader with the Bearer scheme.
Who can call it: An API key with the urlshortener service enabled.
Limits and operational notes
Usage limit: 35 requests per second.
- The destination URL allows up to 2048 characters; the body, up to 64 KiB.
- Destinations on
localhost,*.,local *.or on private or reserved IPs are rejected; so are destinations that already are a short link (our domains or shorteners such as bit.ly, tinyurl.com or t.co); destinations with a user or password before the domain (internal user@); domains with accents, ñ or other alphabets (also asxn--), and URLs with invisible characters. - With a plan: up to 100,000 creations per Colombia day (daily quota).
Path parameters
This endpoint has no path parameters.
Query parameters
This endpoint has no query parameters.
HTTP headers
| Name | Type | Description and rules |
|---|---|---|
AuthorizationRequired | string | Your API key with the Bearer scheme. Example: |
Content-TypeRequired | string | Type of the body you send. Fixed value: |
Idempotency-KeyOptional | string | Optional idempotency key (1 to 255 characters from Pattern: |
Request body
Content type:application/jsonRequired
Only these four fields are accepted. One that does not exist (for example url or alias, from the previous contract) is rejected with 400 naming the field.
| Name | Type | Description and rules |
|---|---|---|
longUrlRequired | string | Destination URL. Absolute Format: |
domainOptional | string | Domain to publish on, one of Example: |
codeOptional | string | Optional alias: 3 to 32 characters among lowercase letters, digits, Pattern: |
expiresAtOptional | string | Optional expiry, always in the future. Accepts RFC 3339 and also Format: |
{
"longUrl": "https://example.com/landing?utm_source=sms",
"domain": "h0b.co",
"code": "promo-septiembre",
"expiresAt": "2026-12-31T23:59:59-05:00"
}Successful responses
201
Link created. With a repeated Idempotency-Key and the same body, it is the link from the first time (Idempotency-Status:): no other one was created or charged.
{
"success": true,
"data": {
"domain": "h0b.co",
"code": "a1b2c3d",
"shortUrl": "https://h0b.co/a1b2c3d",
"longUrl": "https://example.com/landing?utm_source=sms",
"isAlias": false,
"status": "active",
"domainStatus": "active",
"expiresAt": null,
"createdAt": "2026-09-23T15:04:05Z",
"clicks": 0,
"uniqueClicks": 0,
"firstClickAt": null,
"lastClickAt": null
},
"meta": {
"requestId": "8f0c0e2a4b1d4c8f",
"clientIp": "203.0.113.45",
"timestamp": "2026-09-23T18:30:00+00:00",
"responseTimeMs": 7.2
}
}The example values are illustrative.
Response fields
| Name | Type | Description and rules |
|---|---|---|
successAlways present | boolean | |
dataAlways present | object | |
data.Always present | string | Domain of the link, lowercase. If the domain no longer belongs to your organization ( |
data.Always present | string | Link code, lowercase: 7 |
data.Always present | string | The full short URL: always Format: |
data.Always present | string | Destination URL. Format: |
data.Always present | boolean |
|
data.Always present | string |
Allowed values: |
data. | string | Whether the domain lets the link open, apart from its own Allowed values: |
data.Always present | string | Expiry in UTC, or May come as Format: |
data.Always present | string | Creation date, in UTC. Format: |
data.Always present | integer | Lifetime visits of the link. A background process consolidates them: a visit can take from seconds to a few minutes to show up. Bots and the previews generated by social networks and chat apps are not counted. |
data.Always present | integer | Sum of each day’s unique visits: the first visit of the day from each browser. Not distinct people over the life of the link. |
data.Always present | string | First visit, in UTC. May come as Format: |
data.Always present | string | Last visit, in UTC. May come as Format: |
metaAlways present | object | Response metadata. |
meta.Always present | string | Unique request identifier (16 hexadecimal characters). It matches the Example: |
meta.Always present | string | IP the API saw your request come from. Useful if your API key only accepts certain networks. Example: |
meta.Always present | string | Date and time the response was built (ISO 8601 with offset). Format: |
meta.Always present | number | Time (ms) the server took to process the request. Example: |
Error codes
Every error response has the same shape: success set to false and an error object whose code says what happened. They are grouped here by kind, with the codes this endpoint can return.
Shape of an error response
| Name | Type | Description and rules |
|---|---|---|
successAlways present | boolean | Fixed value: |
metaAlways present | object | Response metadata. |
meta.Always present | string | Unique request identifier (16 hexadecimal characters). It matches the Example: |
meta.Always present | string | IP the API saw your request come from. Useful if your API key only accepts certain networks. Example: |
meta.Always present | string | Date and time the response was built (ISO 8601 with offset). Format: |
meta.Always present | number | Time (ms) the server took to process the request. Example: |
errorAlways present | object | |
error.Always present | string | Stable UPPER_SNAKE_CASE identifier. Clients branch on this value. Example: |
error. | integer | Legacy v5 numeric code, only when a bridge exists. Omitted for codes born in v6. Example: |
error.Always present | string | URL to the error documentation. Format: |
error.Always present | string | Human readable text, in English. It is for the developer log, not the end user: do not parse it. |
error.Always present | array<object> | Structured context (validation issues, affected resource). Empty array when there is no extra context. |
Validation
- 400Invalid body: destination URL, alias, expiry or domain, a field that does not exist, malformed JSON, or an
Idempotency-Keywith another shape. - 422The
Idempotency-Keywas already used to create a link with a different body. Use a new key for a new link.
400VALIDATION_INVALID_PARAMETER
A parameter or a body field is not valid.
The idempotency key does not match the format.
The key already exists, but with a different body.
400URL_INVALID
The destination URL is malformed.
Message the API returns: The destination URL is not valid. Provide an absolute `http`/`https` URL with a host.
Only http/https destinations are allowed.
Message the API returns: Only `http` and `https` destination URLs are allowed.
400URL_TOO_LONG
The destination URL exceeds the maximum length.
Message the API returns: The destination URL exceeds the maximum allowed length.
The destination host is private or reserved.
Message the API returns: The destination host is not allowed (private, reserved, or loopback addresses are blocked).
The custom alias doesn't match the allowed format.
Message the API returns: The alias must be 3-32 characters of lowercase letters, digits, hyphen or underscore.
expiresAtmust be a future ISO date-time.Message the API returns: `expiresAt` must be a future ISO-8601 date-time.
The chosen domain isn't available to your account.
Message the API returns: The requested domain is not available for this account.
Authentication
- 401Invalid or missing credentials.
No Bearer token was sent, and every call requires one.
Message the API returns: Authentication is required. Send your API key as `Authorization: Bearer <token>`.
The API key is not recognized: wrong format, revoked or expired.
Message the API returns: The provided API key is invalid or has expired. Please verify the value sent in the `Authorization: Bearer` header.
Permissions
- 403The API key does not have the URL shortener enabled (or it is turned off for your organization), the key cannot be used from the request network, or the organization is not active.
The key is not allowed to use the service behind this endpoint.
Message the API returns: This API key is not authorized to use the requested service.
The key only works from certain networks and your IP is not one of them.
Message the API returns: This API key cannot be used from this IP address. The address we saw is in `meta.clientIp`: call from one of the networks allowed for the key, or use a key that allows this one.
Your organization is suspended or closed.
Message the API returns: The organization associated with this API key is not active. Please contact support.
We could not load the organization behind your key.
Message the API returns: Organization configuration could not be loaded. Please contact support.
Usage limits
- 429The request limit was exceeded, or (with a plan) the daily creation quota. In the second case
Retry-Aftersays how long until midnight in Colombia.
429URLSHORTENER_LINK_QUOTA_EXCEEDED
Your organization reached its plan’s daily link quota.
You exceeded your organization quota for this endpoint.
Message the API returns: You have exceeded the allowed request rate for this endpoint. Please wait before retrying.
Resource not found
This endpoint does not declare responses of this kind.
Internal errors and availability
- 500A free code could not be generated. Retry.
- 503Balance could not be checked right now. The link is not created; you can retry (better with
Idempotency-Key).
Something went wrong on our side.
Message the API returns: Internal Server Error
Generic 503: a service we depend on is not responding.
Other responses
- 402Your organization has no available balance to create the link (or no active billing account), or creating it would exceed a spend limit it configured itself (
URLSHORTENER_SPEND_LIMIT_REACHED: adjust it in the spend limits, topping up does not fix it). The link is not created. - 409The alias is already taken on that domain, is a reserved word or a brand on a shared domain, or belongs to a deleted link of yours (
ALIAS_RETIRED: restore it); the own domain is not verified; or the URL shortener has no price for your organization’s currency, or your organization does not have a currency yet. In the last two cases retrying does not fix it.
409ALIAS_TAKEN
The alias was already used on this domain.
Message the API returns: That alias has already been used on this domain and cannot be used again.
The alias is a reserved word.
Message the API returns: That alias is reserved and cannot be used.
The alias belongs to a link of yours that you deleted.
Your domain is not verified yet.
402URLSHORTENER_INSUFFICIENT_FUNDS
Your organization has no balance to create the link.
402URLSHORTENER_SPEND_LIMIT_REACHED
A spend limit your organization configured was reached.
The URL shortener has no price configured for your currency.
409URLSHORTENER_CURRENCY_UNDEFINED
Your organization does not have a currency yet.
Special considerations
- Supports the
Idempotency-Keyheader: if a request is cut off and you repeat it with the same key, it is not duplicated. The details are in the idempotency guide.
Retry without duplicates with Idempotency-Key. If a creation is cut off (a timeout, a 5xx) and you repeat it with the same key and the same body, you get the same link (201 with Idempotency-Status:) without creating another one or charging twice, even while the first one is still being processed. The same key with a different body returns 422 IDEMPOTENCY_KEY_REUSED. On this endpoint the key stays tied to the link forever. Without a key, each retry creates and charges another link.
The body is validated before the balance is checked: an invalid URL, alias, domain or expiry returns its error without touching your balance.
A key with the URL shortener also creates and deletes
The urlshortener service grants the whole URL shortener: with it, the API key lists and reads links, and also creates them (each creation is charged), edits, deletes and restores them. There are no read-only keys. Only the owner of your organization creates keys: if one must not create links, do not give it this service. Without it, the key gets 403 AUTH_SERVICE_NOT_ALLOWED.