서버 API 참조
SosoAPI 게시 API: 인증, 요청 및 결과
대상별 Scheduled Post 하나를 중심으로 서버 측 게시 통합을 구현하세요. 이 참조는 20 October 2026 검토된 게시 API 계약을 다룹니다. 예제에는 자리표시자가 있으며 이 페이지에서 실행되지 않습니다.
Markdown으로 읽기SosoAPI 팀 검토 ·
1. 서버에서 인증
SosoAPI App → Settings → Agents & API Access에서 API 키를 생성하세요. 서버 환경의 SOSOAPI_API_KEY로 저장하세요. 요청은 Authorization: Bearer <your-key>와 Content-Type: application/json을 사용합니다. 키를 웹사이트, 모바일 앱 번들, URL, 공개 저장소에 넣지 마세요.
아래 엔드포인트는 모두 JSON 본문의 POST를 사용합니다. 키와 위임 에이전트 권한은 기능, 허용 Workspace, 소유자의 현재 멤버십으로 제한됩니다. 읽기에는 agent:operate 및 최소 viewer 접근, 게시 변경에는 agent:publish 및 최소 editor 접근이 필요합니다. 위임 권한이 소유자의 권한을 확장할 수는 없습니다.
앱의 현재 Workspace 및 연결된 계정을 사용하거나 /identity-api/workspace/list와 /identity-api/user/social-accounts/list를 호출하여 사용 권한이 있는 ID를 찾으세요. 고객의 Workspace 또는 계정 ID를 추측하지 마세요.
// Node.js 20+; run only on your server.
const apiKey = process.env.SOSOAPI_API_KEY;
if (!apiKey) throw new Error("Set SOSOAPI_API_KEY on your server");
const apiBase = "https://gqeshlawtcexsapabaui.supabase.co/functions/v1";
async function sosoPost(path, body) {
const response = await fetch(apiBase + path, {
method: "POST",
headers: {
Authorization: "Bearer " + apiKey,
"Content-Type": "application/json"
},
body: JSON.stringify(body)
});
const result = await response.json();
if (!response.ok) {
const requestId = result.request_id ?? response.headers.get("x-request-id");
// Handler errors use code/message; schema-validation 400s instead use
// success:false and error:{name:"ZodError",message:...}.
// Preserve status, available code and requestId in server diagnostics.
// Never log the key or an Authorization header.
throw new Error("SosoAPI " + response.status + " (" +
(requestId ?? "no request id") + ")");
}
return result;
}2. 게시 엔드포인트 맵
이 경로는 서버 헬퍼가 사용하는 API 기본 주소에 대한 상대 경로입니다. Scheduled Post 상세에서 현재 버전, 가능한 작업, 게시 결과를 가져오세요.
| 경로 | 요청 | 응답 및 경계 |
|---|---|---|
| /studio-api/scheduled-posts/list | workspace_id; 선택적 project_id, status, 시간 쌍, limit, cursor. | posts, next_cursor, returned_count. Workspace 범위 읽기. |
| /studio-api/scheduled-posts/get | id. | post, delivery, actions, attempts, outcomes. 여기서 현재 버전을 읽으세요. |
| /studio-api/scheduled-posts/eligibility | workspace_id, targets; 선택적 include_quota. | 대상과 선택적 할당량. 읽기 전용 사전 검사이며 용량 예약이 아닙니다. |
| /studio-api/scheduled-posts/create | workspace_id, 정확한 계정, provider_payload, 콘텐츠, scheduled_at, idempotency_key. | post 및 deduped. 새 예약은 201, 일치하는 재요청은 200. |
| /studio-api/scheduled-posts/bulk-create | workspace_id 및 1–50개 targets. 각 항목에 자체 idempotency_key가 필요합니다. | batch_id, successes, failures. 하나 이상 성공하면 201, 모두 실패하면 422. 두 배열을 모두 확인하세요. |
| /studio-api/scheduled-posts/update | id, expected_version, patch; 선택적으로 일치하는 provider_payload. | post. 오래된 버전은 거부되며 대상은 변경할 수 없습니다. |
| /studio-api/scheduled-posts/publish-now | id 및 expected_version. | post. 즉시 실행을 요청하며 게시를 증명하지 않습니다. |
| /studio-api/scheduled-posts/retry | id, expected_version; 선택적 미래 scheduled_at. | post. 실패한 항목만 증거에 따라 복구하며 무작정 재전송하지 않습니다. |
| /studio-api/scheduled-posts/cancel | id 및 expected_version. | post. 아직 게시되지 않은 작업을 취소하며 원격 취소는 대기 상태로 남을 수 있습니다. |
| /studio-api/scheduled-posts/delete | id 및 expected_version. | post. 머신 호출자는 이미 게시된 제공업체 콘텐츠를 삭제할 수 없습니다. |
| /studio-api/scheduled-posts/withdraw-delete | id 및 expected_version. | post. 중단된 검증 전용 Instagram Login 삭제 요청을 철회하고 제공업체 콘텐츠를 유지합니다. |
3. 범위를 유지하며 목록 조회 및 페이지 이동
limit 기본값은 50이며 1–200을 허용합니다. 선택적 status는 scheduled, publishing, published, failed, expired, needs_reschedule, cancelled 또는 deleted 중 하나입니다. scheduled_from과 scheduled_to는 오프셋을 포함한 ISO-8601 시각으로 함께 제공해야 하며 종료는 시작보다 뒤여야 합니다.
next_cursor는 null 또는 scheduled_at과 id가 있는 객체입니다. 같은 Workspace 및 필터와 함께 그 객체 전체를 cursor로 돌려 보내세요. 이 엔드포인트는 page, offset, platform, social_account_id 필터를 받지 않습니다.
await sosoPost("/studio-api/scheduled-posts/list", {
"workspace_id": "<workspace-uuid>",
"limit": 50
});const first = await sosoPost("/studio-api/scheduled-posts/list", {
workspace_id: "<workspace-uuid>", limit: 50
});
if (first.next_cursor) {
const next = await sosoPost("/studio-api/scheduled-posts/list", {
workspace_id: "<workspace-uuid>", limit: 50, cursor: first.next_cursor
});
// Consume next.posts; continue only while next_cursor is not null.
}4. 검토한 게시물 하나 검증 및 생성
모든 자리표시자를 승인된 범위의 값과 미래 시간으로 바꾸세요. 이 예제는 실행하면 실제 Threads 텍스트 게시물을 예약합니다. 생성 호출 전에 당사자에게 계정, 콘텐츠, 시간을 확인받으세요.
provider_payload.platform과 해당 플랫폼의 publish_options를 설정하세요. 서버는 선택 계정과 일치하는지 확인합니다. 게시물 출처 기록에 project_id를 포함할 수 있지만 프로젝트는 게시 권한을 부여하거나 예약을 제어하지 않습니다.
| 필드 | 계약 |
|---|---|
| workspace_id / social_account_id | 승인된 Workspace와 정확한 대상의 필수 UUID. |
| provider_payload | 필수 플랫폼 구분자 및 플랫폼별 publish_options. |
| scheduled_at / display_timezone | 오프셋이 포함된 필수 ISO-8601 시각. 유효한 IANA 표시 시간대이며 기본값은 UTC입니다. |
| idempotency_key | 필수 공백 제거 문자열, 8–160자. 이 단일 의도에 대해 동일하게 유지합니다. |
| caption / hashtags | Caption은 null을 허용하며 최대 5,000자, 기본값 null입니다. Hashtags 기본값은 []이며 최대 100개 문자열, 각 100자입니다. 제공업체 제한은 더 엄격할 수 있습니다. |
| media | 기본값 []이며 등록된 미디어 참조는 최대 20개입니다. 각 항목은 kind image/video 및 정식 url을 가지며 준비된 asset_id를 포함하세요. 플랫폼 규칙은 더 엄격할 수 있습니다. |
| link_url | 선택적 URL 또는 null. 대상과 게시 유형이 지원해야 합니다. |
| local_scheduled_at / schedule_dst_disambiguation | 선택적 쌍: 오프셋 없는 현지 시간과 exact/earlier/later. 둘 다 제공하거나 둘 다 생략하며 의도한 시각과 시간대에 일치해야 합니다. |
| expires_at / automatic_retry_enabled | scheduled_at 이후 만료 시각은 선택 사항이며 null은 만료 없음을 뜻합니다. 자동 재시도 기본값은 true이며 제공업체 안전 조건을 따릅니다. |
| project_id / source_ref | null을 허용하는 선택적 Project UUID 및 호출자 출처 객체. 어느 것도 권한을 변경하지 않습니다. |
await sosoPost("/studio-api/scheduled-posts/eligibility", {
"workspace_id": "<workspace-uuid>",
"include_quota": true,
"targets": [
{
"social_account_id": "<threads-account-uuid>",
"media": [],
"provider_payload": {
"platform": "threads",
"publish_options": {
"post_type": "TEXT"
}
},
"draft": {
"caption": "A reviewed update from our team.",
"hashtags": [],
"scheduled_at": "<future-ISO-8601-instant-with-offset>",
"display_timezone": "Asia/Hong_Kong"
}
}
]
});await sosoPost("/studio-api/scheduled-posts/create", {
"workspace_id": "<workspace-uuid>",
"social_account_id": "<threads-account-uuid>",
"caption": "A reviewed update from our team.",
"hashtags": [],
"media": [],
"provider_payload": {
"platform": "threads",
"publish_options": {
"post_type": "TEXT"
}
},
"scheduled_at": "<future-ISO-8601-instant-with-offset>",
"display_timezone": "Asia/Hong_Kong",
"idempotency_key": "<stable-key-for-this-one-intent>"
});5. 결과 확인 및 안전한 취소
Create는 { post, deduped }, List는 { posts, next_cursor, returned_count }, Get은 { post, delivery, actions, attempts, outcomes }를 반환합니다. post에는 id, status, version, destination, schedule 및 가능한 제공업체 ID/고유 링크가 포함됩니다. delivery와 actions는 현재 진행 및 허용된 다음 작업을 설명합니다.
status가 scheduled 또는 publishing인 게시물은 대기 중입니다. status published인 최종 게시 결과가 게시를 확인하며 가능한 제공업체 증거를 포함합니다. 고유 링크는 없을 수 있습니다. 클라이언트 연결이 끊기거나 응답이 늦으면 결과를 보고하기 전에 기존 게시물을 읽으세요.
취소 전에 게시물 상세를 가져와 현재 숫자 version을 전달하세요. SosoAPI가 제공업체의 예약을 취소하는 동안 결과는 cancellation_pending일 수 있습니다. 예약 취소는 이미 게시된 게시물을 삭제하지 않습니다.
await sosoPost("/studio-api/scheduled-posts/get", {
"id": "<scheduled-post-uuid>"
});const detail = await sosoPost("/studio-api/scheduled-posts/get", {
id: "<scheduled-post-uuid>"
});
// Run only after the person confirms cancelling this unpublished post.
await sosoPost("/studio-api/scheduled-posts/cancel", {
id: detail.post.id, expected_version: detail.post.version
});6. 멱등성, 충돌, 불확실한 쓰기
같은 생성 요청을 반복할 때는 같은 idempotency_key를 사용하세요. 일치하는 재요청은 기존 게시물을 deduped=true로 반환합니다. 키를 재사용하면서 콘텐츠를 바꾸면 충돌이 발생합니다. 이는 SosoAPI의 중복 생성을 방지하며 제공업체의 정확히 한 번 전송을 보장하지는 않습니다.
수정 및 작업에는 최신 상세 응답의 expected_version을 전달하세요. 충돌하면 게시물을 다시 가져와 새 버전에 맞춰 변경을 검토하세요. 응답 유실 시 기존 상태를 확인해야 하며 새 키로 다른 게시물을 생성해서는 안 됩니다.
중복 콘텐츠 가드는 정규화된 공개 콘텐츠, 계정, 근접한 게시 시간이 같은 별도 요청을 거부할 수 있습니다. 읽기 권한이 있으면 기존 게시물 참조를 확인하고 요청을 변경하기 전에 사용자에게 물으세요. 일괄 요청은 대상별 결과를 반환하며 일부는 성공하고 일부는 실패할 수 있습니다.
7. 오류, 요청 속도 제한 및 통합 제한
핸들러 오류는 error, message, 선택적 code, retryable, request_id, 선택적 details, retry_after_seconds가 있는 봉투 형식을 사용합니다. 스키마 검증 400은 다른 형식인 { success: false, error: { name: "ZodError", message: "…" } }를 반환합니다. 현재 검증 메시지는 경로를 포함한 직렬화된 필드 문제를 담습니다. 핸들러 봉투 필드가 있다고 가정하지 마세요.
오류 진단 시 HTTP 상태, 오류 코드, result.request_id ?? response.headers.get("x-request-id")의 상관 ID를 보관하세요. 검증 필드 경로로 요청을 수정하세요. 인증 또는 권한 오류는 재시도 전에 자격 증명이나 권한을 수정하세요.
현재 studio-api 제한은 사람 사용자당 분당 240개 요청이며 해당 사용자의 별도 머신 자격 증명 버킷은 분당 480개입니다. 게시 처리량이나 요금제 할당량이 아닌 요청 상한입니다. 다른 엔드포인트와 소셜 제공업체는 별도 제한이 있습니다. 429 또는 재시도 가능한 503에서는 실제 Retry-After 헤더를 따르고 반복 호출하지 마세요.
사용자가 게시물을 추적하는 동안 제한된 간격으로 상태를 읽거나 앱의 실시간 상태 보기를 사용하세요. 이 API는 외부 웹훅, 구독자 SLA, 플랫폼 간 동일 기능, 고정 게시 시각을 보장하지 않습니다.
| 상태 | 의미 및 대응 |
|---|---|
| 400 | 스키마 검증은 핸들러 봉투 대신 success:false와 error 안의 ZodError를 반환할 수 있습니다. 필드 문제를 수정하고 본문에 request_id가 없으면 x-request-id를 사용하세요. 핸들러 수준의 잘못되거나 지원되지 않는 요청도 400을 사용할 수 있습니다. |
| 401 / 403 | 자격 증명 없음/만료 또는 기능, 역할, Workspace, 계정 접근 거부. 해당 권한 또는 멤버십을 수정하세요. |
| 404 | 승인된 범위에서 리소스를 사용할 수 없습니다. ID를 확인하세요. |
| 409 | 상태/버전, 멱등성, 중복 콘텐츠 또는 적격성 충돌. 다시 읽고 무작정 재전송하지 마세요. |
| bulk-create의 422 | 성공한 대상이 없습니다. failures를 확인하세요. 일부 성공은 201을 사용합니다. |
| 429 | 요청 제한. Retry-After를 따르고 같은 의도 ID를 유지하세요. |
| 503 / 기타 5xx | 일시적 서비스 실패 또는 내부 오류. request_id를 보관하고 불확실한 변경을 재시도하기 전에 기존 상태를 확인하세요. |