(POST) Create links
Create one or more links in a single request. Each link requires a destination URL and collection ID.
Endpoint
POST /api/links
Create one or more links in a single request. This endpoint accepts an array of link objects, allowing you to create multiple links efficiently in one API call.
Each link requires a destination URL and a collection ID. A unique short ID is automatically generated for each link, producing a short URL and QR code URL under https://hoko.to.
You can include rich metadata such as titles, descriptions, images, UTM parameters, tag IDs, and custom external IDs to organize and track your links effectively.
POST /api/linksAuthentication
Requires authentication with an API key that has the linksWrite scope.
Request Body
The request body must be an array of link objects. Each object represents one link to create.
You can create up to 10,000 links in a single request. However, the actual maximum may be lower based on your subscription plan limits and available resources.
| Parameter | Type | Required | Description |
|---|---|---|---|
url (body) | string (URL) | Yes | The destination URL that the short link will redirect to. Must be a valid HTTPS URL. |
collectionId (body) | string (UUID) | Yes | The ID of the collection (folder) to organize this link. The collection must exist in your workspace. |
tagIds (body) | string[] | No | Existing tag IDs to assign to this link. Every tag must already exist in your workspace. |
title (body) | string | No | A descriptive title for the link. Useful for organization and identification. |
description (body) | string | No | Additional description or notes about the link. |
image (body) | string (URL) | No | A preview image URL for the link. Must be a valid HTTPS URL. |
utm (body) | object | No | UTM parameters for campaign tracking. Create requests accept string values for source, medium, campaign, term, content, and referral. |
expiresAt (body) | string | No | ISO date-time when the link should expire. Requires a plan with link expiration. |
expiredUrl (body) | string (URL) | No | Destination used after expiration. Requires a plan with link expiration. |
password (body) | string | No | Password required before resolving the destination. Requires a plan with password protection. |
cloaked (body) | boolean | No | Render the resolved destination in an iframe. The destination is preflighted and rejected with 400 if it currently blocks iframe rendering. Requires a plan with link cloaking. |
ios (body) | string (URL) | No | Destination for iOS visitors. Requires a plan with device targeting. |
android (body) | string (URL) | No | Destination for Android visitors. Requires a plan with device targeting. |
geo (body) | object/null | No | Country-code destination map such as `{ "SA": "https://example.com/sa" }`; send null or omit for no geo targeting. Requires geo targeting when set. |
externalId (body) | string | No | A custom external ID for syncing with external systems. Must be unique within your workspace. |
tenantId (body) | string | No | A tenant identifier for multi-tenant scenarios. Useful for segmenting links by customer or organization. |
partnerId (body) | string (UUID) | No | The ID of the partner associated with this link. Used for affiliate and partner attribution tracking. |
Plan Limits
The actual maximum number of links you can create per request may be lower than 10,000 based on your subscription plan limits and available resources. The system will enforce both the hard limit (10,000) and your plan-specific limits.
Advanced Link Behavior
password: Visitors must enter the password before Hoko resolves the final destination. A correct password stores a secure, HTTP-only cookie scoped to that short link, so the same visitor can continue without re-entering it.expiresAt: Use an ISO date-time with timezone offset, such as2026-12-31T23:59:00Z. When the current server time is later thanexpiresAt, the link is expired. IfexpiredUrlis set, Hoko sends visitors there. If it is not set, Hoko shows an expired-link page.iosandandroid: Device destinations are selected from the visitor's User-Agent. iOS and Android checks run before geo targeting.geo: Map ISO 3166-1 alpha-2 country codes to destination URLs, for example{ "SA": "https://example.com/sa" }. Use uppercase country codes. Sendnullor omit the field for no geo targeting. Country detection is best-effort and uses trusted edge country headers when available, then IP lookup.cloaked: Hoko renders the resolved destination in a full-page iframe. Create requests preflight the destination and return 400 if it currently blocks iframe rendering.
Advanced fields are applied only when they are set on the link and your workspace plan supports the feature.
All URL fields accepted by this endpoint must use https:. This includes url, image, expiredUrl, ios, android, and every URL value in geo.
Resolution order is: password gate, expiration, iOS/Android targeting, geo targeting, default url, then cloaking. Expired links do not run device or geo targeting.
Examples
curl -X POST "https://hoko.to/api/links" \
-H "Authorization: Bearer <API_KEY>" \
-H "Content-Type: application/json" \
-d '[
{
"url": "https://example.com",
"title": "Example Link",
"description": "An example link",
"collectionId": "550e8400-e29b-41d4-a716-446655440000",
"tagIds": ["7c4e4a56-f3bb-43e9-9dc7-2f4bda07c8f0"],
"utm": {
"source": "google",
"medium": "cpc",
"campaign": "summer"
}
}
]'const response = await fetch('https://hoko.to/api/links', {
method: 'POST',
headers: {
Authorization: 'Bearer <API_KEY>',
'Content-Type': 'application/json'
},
body: JSON.stringify([
{
url: 'https://example.com',
title: 'Example Link',
description: 'An example link',
collectionId: '550e8400-e29b-41d4-a716-446655440000',
tagIds: ['7c4e4a56-f3bb-43e9-9dc7-2f4bda07c8f0'],
utm: {
source: 'google',
medium: 'cpc',
campaign: 'summer'
}
}
])
});
const links = await response.json();[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://example.com",
"shortUrl": "https://hoko.to/abc123",
"qrCode": "https://hoko.to/qrcode?text=https%3A%2F%2Fhoko.to%2Fabc123%3Fqr%3D1&size=512&errorCorrection=H&foreground=000000&background=FFFFFF&margin=1&format=svg",
"title": "Example Link",
"description": "An example link",
"image": null,
"utm": null,
"expiresAt": null,
"expiredUrl": null,
"password": null,
"cloaked": false,
"ios": null,
"android": null,
"geo": null,
"collectionId": "550e8400-e29b-41d4-a716-446655440000",
"tagIds": [
"7c4e4a56-f3bb-43e9-9dc7-2f4bda07c8f0"
],
"externalId": null,
"tenantId": null,
"partnerId": null,
"createdAt": "2024-01-01T00:00:00Z"
}
]Important Constraints
The collectionId must reference an existing collection in your workspace. Each tagIds value must reference an existing tag in your workspace. The externalId must be unique within your workspace if provided. Plan limits may restrict the number of links you can create per request and overall.