개발자용 API
고객 사이트 연동 API
고객 사이트가 Trina에 준비된 글을 가져가 직접 올리고, 게시된 주소를 알려 주는 방식입니다. 주소를 받으면 Trina가 실제 페이지를 확인합니다. 콘솔에서 직접 올린 글을 확인하는 것과 같은 방식입니다.
흐름
- 콘솔에서 키를 발급합니다: 설정 → 채널 설정 → 고객 사이트 연동 API. 키 발급과 폐기는 브랜드 소유자만 할 수 있습니다.
- 서버에서 GET /posts?status=ready 로 준비된 글을 받고, GET /posts/{id} 로 본문(Markdown·HTML)을 가져옵니다.
- 가져간 글을 사이트에 올립니다.
- POST /posts/{id}/published 로 게시 주소를 보냅니다. 글이 '발행됨'으로 바뀌고 Trina가 확인을 시작합니다.
인증
모든 요청에 키를 Bearer 토큰으로 보냅니다. 키 하나는 브랜드 하나에 속하고, 그 브랜드의 글만 볼 수 있습니다.
Authorization: Bearer trn_live_…- 전체 키는 발급할 때 한 번만 보입니다. Trina는 해시만 저장하므로 잃어버린 키는 되찾을 수 없습니다. 폐기하고 새로 발급하세요.
- 키는 서버(환경 변수 등)에만 두세요. 브라우저 코드나 공개 저장소에 넣으면 안 됩니다.
- 폐기한 키는 바로 막힙니다(401). 브랜드당 사용 중인 키는 5개까지이며, 모든 요금제에서 조건이 같습니다.
엔드포인트
기본 주소: https://trina.app/api/v1
글 목록GET /posts
최신순이며 본문은 빠져 있습니다. 쿼리 파라미터(모두 선택):
statusready(기본) 또는 publishedsinceISO 8601 시각. ready는 만든 시각, published는 게시 시각이 이 값 이후인 글만channelblog(기본) - 고객 사이트limit1~100, 기본 50curl -s "https://trina.app/api/v1/posts?status=ready&since=2026-10-01T00:00:00Z" \
-H "Authorization: Bearer $TRINA_API_KEY"{
"posts": [
{
"id": "d-2026-10-16-blog-1",
"title": "치아 미백, 집에서 해도 될까",
"status": "ready",
"channel": "blog",
"excerpt": "치아 미백을 집에서 할 때 확인할 것들을 정리했습니다…",
"cover_image_url": "https://…/cover.png",
"seo_score": 82,
"scheduled_for": null,
"created_at": "2026-10-16T01:00:00.000Z",
"published_at": null,
"post_url": null,
"verify_state": null
}
]
}글 하나 가져오기GET /posts/{id}
본문을 markdown과 html 두 가지로 돌려줍니다. HTML에는 인라인 스타일이 들어 있어 별도 CSS 없이도 읽기 좋게 보입니다. 초안 안의 raw HTML은 버려지고 그대로 나가지 않습니다.
curl -s "https://trina.app/api/v1/posts/d-2026-10-16-blog-1" \
-H "Authorization: Bearer $TRINA_API_KEY"{
"post": {
"id": "d-2026-10-16-blog-1",
"title": "치아 미백, 집에서 해도 될까",
"status": "ready",
"markdown": "## 집에서 하는 미백…",
"html": "<h2 style=\"…\">집에서 하는 미백…</h2>…",
"canonical_url": null,
"verify_note": null,
"verify_at": null,
"…": "plus every field from the list"
}
}게시 주소 알려 주기POST /posts/{id}/published
실제 페이지의 전체 https:// 주소를 보냅니다. 글이 발행됨으로 바뀌고(post_url, published_at) verify_state가 checking이 됩니다. 이어서 Trina가 페이지를 확인해 confirmed 또는 mismatch로 바꿉니다. 나중에 다른 주소를 보내면 그 주소로 바뀝니다.
curl -s -X POST "https://trina.app/api/v1/posts/d-2026-10-16-blog-1/published" \
-H "Authorization: Bearer $TRINA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://www.example.com/blog/teeth-whitening-at-home"}'{
"post": {
"id": "d-2026-10-16-blog-1",
"status": "published",
"published_at": "2026-10-16T05:12:44.120Z",
"post_url": "https://www.example.com/blog/teeth-whitening-at-home",
"verify_state": "checking",
"…": "…"
}
}글 필드
id글 id. 위 경로에 씁니다title제목statusready 또는 publishedexcerpt메타 설명용 요약(약 160자, 일반 텍스트)cover_image_url커버 이미지 주소 또는 nullscheduled_for예정 게시일(YYYY-MM-DD) 또는 null. 그날 이후에 올려 주세요post_url알려 준 게시 주소 또는 nullverify_statenull · checking · confirmed · mismatch · not_found · wrong_channelmarkdown / html본문(글 하나 응답에만)오류
오류는 JSON으로 옵니다: { "error": "코드", "hint"?: "…" }
400invalid_status · invalid_since · invalid_channel · invalid_limit · invalid_json · url_not_https401missing_api_key · invalid_api_key (없는 키, 형식이 틀린 키, 폐기한 키)403forbidden - 다른 브랜드의 글404post_not_found422wrong_channel - 주소의 호스트가 다른 채널의 것(예: 블로그 글에 네이버 주소)500internal_error - 잠시 뒤 다시 시도HTTP/1.1 403
{ "error": "forbidden", "hint": "This post belongs to another brand." }다음 단계
글이 준비되면 고객 사이트로 바로 보내 주는 푸시(웹훅) 방식도 준비 중입니다. 그전까지는 GET /posts?status=ready 를 주기적으로(15~60분 간격이면 충분합니다) 호출해 주세요.