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://ceylon.anilau.com/api/v1/me"

curl -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json" \
  "https://ceylon.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. 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://ceylon.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.

4. 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://ceylon.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.

5. 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://ceylon.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. Partial success returns translated and failed language lists; a total provider failure returns 503.

6. 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://ceylon.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":"Завтрак включён"}}}'

7. Covers and media galleries

Upload or replace a cover with a multipart POST to /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.

8. 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.