API v1
API documentation
Manage the content and advertisements your account is allowed to access. The API is designed for agents and uses one personal Bearer key instead of OAuth.
1. Create and protect your key
A key can be created in the profile only when the account email is verified and the profile status is trusted or verified. It is shown once, has no expiry, and works only on the site that issued it. Revoke it immediately if it may have been exposed.
Authorization: Bearer YOUR_API_KEY
Accept: application/json
2. Verify access and load references
curl -H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json" \
"https://vietnam.anilau.com/api/v1/me"
curl -H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json" \
"https://vietnam.anilau.com/api/v1/reference-data?lang=en"
Reference data returns configured languages, permitted content types, categories, active advertisement sections, locations, advertisement types, price types and currencies, media types, and whether automatic translation is configured.
3. Advertisement sections
Super-admin keys can list, create, read, patch, add a cover to, and delete advertisement sections through /api/v1/sections. Other accounts continue to receive active sections through reference-data, but cannot use the management routes.
curl -X POST "https://vietnam.anilau.com/api/v1/sections" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"lang": "en",
"name": "Software development",
"slug": "software-development",
"title": "Software development services",
"text": "A complete description for this site.",
"translations": {
"ru": {"name":"Разработка ПО","title":"Услуги разработки ПО","text":"Полное описание раздела."}
},
"auto_translate": {"target_languages":["id"]}
}'
Creation is atomic: every language returned by this site's reference data must be complete before the row is inserted. Manual values take priority over automatic translation. If a source name, title, teaser, or text changes later, send the same field for every site language or regenerate all selected languages with overwrite=true. Changing a slug or parent refreshes descendant section and advertisement URLs. Deletion is allowed only for an unused leaf section.
Each site has its own database and identifiers. A client publishing the same section to Bali, Ceylon, Mauritius, and Vietnam should keep the same slug, resolve parent identifiers independently, and provide site-specific descriptions plus every language supported by each site.
4. Content
Use /api/v1/content to list, read, create, and patch posts, pages, or categories allowed by the account. Lists accept lang, type, updated_after, and per_page up to 100.
curl -X POST "https://vietnam.anilau.com/api/v1/content" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"type": "post",
"lang": "en",
"name": "A practical island guide",
"teaser": "A detailed introduction long enough for article moderation.",
"text": "ARTICLE BODY OF AT LEAST 500 CHARACTERS",
"accept_rules": true,
"tags": ["travel"],
"location_ids": [1]
}'
Ordinary key holders create moderated posts only. They may patch their own pending or rejected submissions; a rejected article returns to pending. Published articles, pages, and categories require the corresponding account permissions. Administrative fields are accepted only when those permissions apply.
5. Advertisements
Use /api/v1/ads to manage advertisements. Creation requires an active section, language, type, name, contact, and at least one location. Contact must contain at least one email, phone number, web URL, or messenger link. Omitted PATCH fields and relations stay unchanged.
curl -X POST "https://vietnam.anilau.com/api/v1/ads" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"section_id": 1,
"lang": "en",
"type": "offer",
"name": "Local airport transfer",
"text": "Private local transfer with direct booking.",
"address": "WhatsApp +00 000 000 000",
"location_ids": [1]
}'
Only the owner may edit an advertisement, except for super-admin access. The create request may also include initial prices, manual translations, and auto_translate.target_languages. Advertisement limits are 150 characters for name and title, 180 for slug, 500 for teaser, 1,500 for text, 255 for video, coordinates, address, and price comments, 20 tags of 60 characters, 20 locations, and 20 initial prices.
6. Manual and automatic translations
List translations with GET /{resource}/{id}/translations. Use PUT /{resource}/{id}/translations/{lang} for a complete language payload and DELETE to remove a non-source language. Content translations are related Post records and keep the normal moderation and permission rules. Advertisement translations live in the advertisement JSON and may include price comments.
curl -X POST "https://vietnam.anilau.com/api/v1/ads/123/translations/auto" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"target_languages":["ru","id"],"overwrite":false}'
Automatic translation is optional and uses Azure Translator only when the site operator has configured it. It translates names, titles, teasers, article HTML, article tags, and price comments. It never translates addresses, contacts, URLs, coordinates, slugs, or filenames. Existing manual translations are preserved unless overwrite=true. The limit is 10 operations per user per hour and 30,000 source characters per operation. Content batches isolate every target language: partial and failed responses list both saved and failed languages, including unexpected provider or persistence errors. A global provider/configuration failure before any per-language work may still return 503.
For PUT /content/{id}/translations/{lang}, omitting slug and parent_id preserves those values on an existing translation. A newly created translation whose localized name cannot form a Latin slug uses the predictable fallback source-slug-lang.
7. Prices
Advertisement prices are managed through GET/POST /api/v1/ads/{id}/prices and PATCH/DELETE /api/v1/ads/{id}/prices/{price}. Writable fields are type, value, a currency returned by reference data, discount, validity dates, comment, sort, and translated comments. PATCH preserves omitted fields.
curl -X POST "https://vietnam.anilau.com/api/v1/ads/123/prices" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"type":"day","value":125,"currency":"usd","comment":"Breakfast included","translations":{"ru":{"comment":"Завтрак включён"}}}'
8. Covers and media galleries
Upload or replace a cover with a multipart POST to /api/v1/sections/{id}/cover, /api/v1/content/{id}/cover, or /api/v1/ads/{id}/cover. Use field image; GIF, JPEG, PNG, and WebP files up to 5 MB are accepted.
Gallery routes are GET/POST /{resource}/{id}/media and PATCH/DELETE /{resource}/{id}/media/{media}. A gallery item is a photo, uploaded file, or external video link with optional name, source, sort, group, and active state. Advertisement galleries are limited to six items. Deleting an item removes its stored file and relation. Content translations use gallery fallback through their shared bind and do not duplicate files.
9. Access and errors
401 means the key is missing or invalid; 403 means eligibility, ability, or operation access is missing; 404 hides an inaccessible entity; 422 contains validation errors; 429 is the API rate limit. Successful writes return data; lists also return Laravel pagination links and meta.
Nested prices, translations, and media inherit their parent policy. Never send a real key in chat, source control, logs, query strings, or screenshots. Revoke and recreate a key if it may have been exposed.