{"data":{"name":"Tapter Profile API","version":"v1","baseUrl":"https://dev.tapter.kz/api/v1","authentication":{"scheme":"Bearer","header":"Authorization: Bearer <token>","tokenPrefix":"tptr_","issuedAt":"https://dev.tapter.kz/settings/api","abilities":{"profile:read":"Read profiles, slots, their statistics and discovery.","profile:write":"Create, change and delete slots, update profiles, upload files."}},"discovery":{"me":"https://dev.tapter.kz/api/v1/me","slotTypes":"https://dev.tapter.kz/api/v1/slot-types","profileSettings":"https://dev.tapter.kz/api/v1/profiles/{profile}/settings","openapi":"https://dev.tapter.kz/api/v1/openapi.json","profileMarkdown":"https://dev.tapter.kz/api/v1/profiles/{profile}/markdown","musicLookup":"https://dev.tapter.kz/api/v1/music/lookup?query=<UPC|ISRC|release link|title>","analytics":"https://dev.tapter.kz/api/v1/analytics","profileAnalytics":"https://dev.tapter.kz/api/v1/profiles/{profile}/analytics"},"conventions":{"envelope":"Success: {data, meta?}. Error: {message, code, errors?, documentation?}.","keys":"camelCase","dates":"ISO 8601","strictWrite":"Unknown or server-computed fields in data return 422 listing every offending key.","tolerantRead":"Legacy slots are returned with \"supported\": false and can be deleted or reordered, but not edited.","dryRun":"Send \"Precognition: true\" on any write request to validate without executing.","login":"A profile login is its public URL. It can be changed through PATCH /profiles/{profile}/settings, but the old address stops working immediately and is not redirected, so existing links, QR codes and NFC tags break. Change it only when the user explicitly asked to, and check availability with GET /profiles/check-login first.","batch":"Blocks go in batches. Creating a page? Send every block in one POST /profiles/{profile}/slots/batch — the array order is the page order. Changing several blocks is one PATCH /profiles/{profile}/slots, removing several is one DELETE /profiles/{profile}/slots with {\"ids\": [...]}; each is all or nothing. Reordering stays PUT /profiles/{profile}/slots/order. Calling the per-slot endpoints in a loop works but burns the rate limit.","editing":"Change a block with PATCH, do not delete and re-create it: click statistics are tied to the slot id and disappear with it.","idempotency":"Send \"Idempotency-Key: <string>\" on any write request (POST, PATCH, PUT, DELETE). Repeating it within 24h returns the stored response.","images":"Profile avatar is rendered as a circle: send a square (1:1, 800x800+). Profile bgImage is optional — do not generate one unless the user asked — and is rendered full width without cropping: send 16:9 landscape (1600x900+), otherwise it pushes the whole page below the fold. Uploads are downscaled to 800px width, so larger than ~1600px brings nothing. POST /files takes either a multipart \"file\" (up to 50 MB) or JSON {\"url\": \"https://…\"} and downloads it for you (http/https, up to 10 MB).","analytics":"Read-only, aggregates only. Counted in Asia/Atyrau, kept for 365 days, and unique counters are approximate (HyperLogLog), so per-block uniques do not sum to the total.","preview":"GET /profiles/{profile}/markdown renders the whole page as markdown. Read it back after writing to catch empty blocks and a wrong order before showing the link to the user."},"limits":{"requestsPerSecond":5,"requestsPerMinute":60,"analyticsPerMinute":20,"slotsPerProfile":500,"slotsPerBatch":50,"profilesPerUser":100,"tokensPerUser":5},"examples":{"readProfile":"curl -H 'Authorization: Bearer $TAPTER_TOKEN' 'https://dev.tapter.kz/api/v1/profiles/coffeeshop?include=slots'","addButton":"curl -X POST -H 'Authorization: Bearer $TAPTER_TOKEN' -H 'Content-Type: application/json' -H 'Idempotency-Key: add-button-1' -d '{\"type\":\"button\",\"data\":{\"title\":\"Book now\",\"link\":\"https://example.com/book\",\"style\":\"primary\"}}' 'https://dev.tapter.kz/api/v1/profiles/coffeeshop/slots'","addManyBlocks":"curl -X POST -H 'Authorization: Bearer $TAPTER_TOKEN' -H 'Content-Type: application/json' -H 'Idempotency-Key: build-coffeeshop-1' -d '{\"slots\":[{\"type\":\"button\",\"data\":{\"title\":\"Book now\",\"link\":\"https://example.com/book\",\"style\":\"primary\"}},{\"type\":\"text\",\"data\":{\"title\":\"About us\",\"description\":\"A coffee shop on Abay street\"}},{\"type\":\"divider\",\"data\":[]}]}' 'https://dev.tapter.kz/api/v1/profiles/coffeeshop/slots/batch'","updateManyBlocks":"curl -X PATCH -H 'Authorization: Bearer $TAPTER_TOKEN' -H 'Content-Type: application/json' -d '{\"slots\":[{\"id\":12,\"data\":{\"title\":\"Book a table\"}},{\"id\":15,\"data\":{\"title\":\"About us\"}}]}' 'https://dev.tapter.kz/api/v1/profiles/coffeeshop/slots'","deleteManyBlocks":"curl -X DELETE -H 'Authorization: Bearer $TAPTER_TOKEN' -H 'Content-Type: application/json' -d '{\"ids\":[12,15,18]}' 'https://dev.tapter.kz/api/v1/profiles/coffeeshop/slots'","reorderSlots":"curl -X PUT -H 'Authorization: Bearer $TAPTER_TOKEN' -H 'Content-Type: application/json' -d '{\"order\":[12,7,33]}' 'https://dev.tapter.kz/api/v1/profiles/coffeeshop/slots/order'","addMusic":"curl -H 'Authorization: Bearer $TAPTER_TOKEN' 'https://dev.tapter.kz/api/v1/music/lookup?query=USRC11700001' # then POST data.slot as-is to https://dev.tapter.kz/api/v1/profiles/coffeeshop/slots","whoAmI":"curl -H 'Authorization: Bearer $TAPTER_TOKEN' 'https://dev.tapter.kz/api/v1/me'","previewPage":"curl -H 'Authorization: Bearer $TAPTER_TOKEN' 'https://dev.tapter.kz/api/v1/profiles/coffeeshop/markdown'","readAnalytics":"curl -H 'Authorization: Bearer $TAPTER_TOKEN' 'https://dev.tapter.kz/api/v1/profiles/coffeeshop/analytics?period=last28&include=timeline'","uploadByUrl":"curl -X POST -H 'Authorization: Bearer $TAPTER_TOKEN' -H 'Content-Type: application/json' -d '{\"url\":\"https://example.com/logo.png\"}' 'https://dev.tapter.kz/api/v1/files'","changeLanguage":"curl -X PATCH -H 'Authorization: Bearer $TAPTER_TOKEN' -H 'Content-Type: application/json' -d '{\"languageCode\":\"kk\"}' 'https://dev.tapter.kz/api/v1/profiles/coffeeshop/settings'"},"notAvailable":["Deleting a profile (link) — dashboard only, it is irreversible.","Profile themes — not open in the dashboard yet, so the API neither returns nor accepts them.","Events and storefront catalogs — event slots are read-only.","Replacing all slots of a page in one declarative call — delete by id and create explicitly; a sync would also wipe the click stats of the removed blocks."]}}